1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 Google LLC 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci#include <emscripten/bind.h> 8cb93a386Sopenharmony_ci#include <emscripten/emscripten.h> 9cb93a386Sopenharmony_ci#include <emscripten/html5.h> 10cb93a386Sopenharmony_ci// https://github.com/emscripten-core/emscripten/blob/main/system/include/emscripten/html5_webgpu.h 11cb93a386Sopenharmony_ci// The import/export functions defined here should allow us to fetch a handle to a given JS 12cb93a386Sopenharmony_ci// Texture/Sampler/Device etc if needed. 13cb93a386Sopenharmony_ci#include <emscripten/html5_webgpu.h> 14cb93a386Sopenharmony_ci// https://github.com/emscripten-core/emscripten/blob/main/system/include/webgpu/webgpu.h 15cb93a386Sopenharmony_ci// This defines WebGPU constants and such. It also includes a lot of typedefs that make something 16cb93a386Sopenharmony_ci// like WGPUDevice defined as a pointer to something external. These "pointers" are actually just 17cb93a386Sopenharmony_ci// a small integer that refers to an array index of JS objects being held by a "manager" 18cb93a386Sopenharmony_ci// https://github.com/emscripten-core/emscripten/blob/f47bef371f3464471c6d30b631cffcdd06ced004/src/library_webgpu.js#L192 19cb93a386Sopenharmony_ci#include <webgpu/webgpu.h> 20cb93a386Sopenharmony_ci// https://github.com/emscripten-core/emscripten/blob/main/system/include/webgpu/webgpu_cpp.h 21cb93a386Sopenharmony_ci// This defines the C++ equivalents to the JS WebGPU API. 22cb93a386Sopenharmony_ci#include <webgpu/webgpu_cpp.h> 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_ciusing namespace emscripten; 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ciwgpu::ShaderModule createShaderModule(wgpu::Device device, const char* source) { 27cb93a386Sopenharmony_ci // https://github.com/emscripten-core/emscripten/blob/da842597941f425e92df0b902d3af53f1bcc2713/system/include/webgpu/webgpu_cpp.h#L1415 28cb93a386Sopenharmony_ci wgpu::ShaderModuleWGSLDescriptor wDesc; 29cb93a386Sopenharmony_ci wDesc.source = source; 30cb93a386Sopenharmony_ci wgpu::ShaderModuleDescriptor desc = {.nextInChain = &wDesc}; 31cb93a386Sopenharmony_ci return device.CreateShaderModule(&desc); 32cb93a386Sopenharmony_ci} 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ciwgpu::RenderPipeline createRenderPipeline(wgpu::Device device, wgpu::ShaderModule vertexShader, 35cb93a386Sopenharmony_ci wgpu::ShaderModule fragmentShader) { 36cb93a386Sopenharmony_ci wgpu::ColorTargetState colorTargetState{}; 37cb93a386Sopenharmony_ci colorTargetState.format = wgpu::TextureFormat::BGRA8Unorm; 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci wgpu::FragmentState fragmentState{}; 40cb93a386Sopenharmony_ci fragmentState.module = fragmentShader; 41cb93a386Sopenharmony_ci fragmentState.entryPoint = "main"; // assumes main() is defined in fragment shader code 42cb93a386Sopenharmony_ci fragmentState.targetCount = 1; 43cb93a386Sopenharmony_ci fragmentState.targets = &colorTargetState; 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci wgpu::PipelineLayoutDescriptor pl{}; 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci // Inspired by https://github.com/kainino0x/webgpu-cross-platform-demo/blob/4061dd13096580eb5525619714145087b0d5acf6/main.cpp#L129 48cb93a386Sopenharmony_ci wgpu::RenderPipelineDescriptor pipelineDescriptor{}; 49cb93a386Sopenharmony_ci pipelineDescriptor.layout = device.CreatePipelineLayout(&pl); 50cb93a386Sopenharmony_ci pipelineDescriptor.vertex.module = vertexShader; 51cb93a386Sopenharmony_ci pipelineDescriptor.vertex.entryPoint = "main"; // assumes main() is defined in vertex code 52cb93a386Sopenharmony_ci pipelineDescriptor.fragment = &fragmentState; 53cb93a386Sopenharmony_ci pipelineDescriptor.primitive.topology = wgpu::PrimitiveTopology::TriangleList; 54cb93a386Sopenharmony_ci return device.CreateRenderPipeline(&pipelineDescriptor); 55cb93a386Sopenharmony_ci} 56cb93a386Sopenharmony_ci 57cb93a386Sopenharmony_ciwgpu::SwapChain getSwapChainForCanvas(wgpu::Device device, std::string canvasSelector, int width, int height) { 58cb93a386Sopenharmony_ci wgpu::SurfaceDescriptorFromCanvasHTMLSelector surfaceSelector; 59cb93a386Sopenharmony_ci surfaceSelector.selector = canvasSelector.c_str(); 60cb93a386Sopenharmony_ci 61cb93a386Sopenharmony_ci wgpu::SurfaceDescriptor surface_desc; 62cb93a386Sopenharmony_ci surface_desc.nextInChain = &surfaceSelector; 63cb93a386Sopenharmony_ci wgpu::Instance instance; 64cb93a386Sopenharmony_ci wgpu::Surface surface = instance.CreateSurface(&surface_desc); 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci wgpu::SwapChainDescriptor swap_chain_desc; 67cb93a386Sopenharmony_ci swap_chain_desc.format = wgpu::TextureFormat::BGRA8Unorm; 68cb93a386Sopenharmony_ci swap_chain_desc.usage = wgpu::TextureUsage::RenderAttachment; 69cb93a386Sopenharmony_ci swap_chain_desc.presentMode = wgpu::PresentMode::Fifo; 70cb93a386Sopenharmony_ci swap_chain_desc.width = width; 71cb93a386Sopenharmony_ci swap_chain_desc.height = height; 72cb93a386Sopenharmony_ci return device.CreateSwapChain(surface, &swap_chain_desc); 73cb93a386Sopenharmony_ci} 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_civoid drawPipeline(wgpu::Device device, wgpu::TextureView view, wgpu::RenderPipeline pipeline, 76cb93a386Sopenharmony_ci wgpu::Color clearColor) { 77cb93a386Sopenharmony_ci wgpu::RenderPassColorAttachment attachment{}; 78cb93a386Sopenharmony_ci attachment.view = view; 79cb93a386Sopenharmony_ci attachment.loadOp = wgpu::LoadOp::Clear; 80cb93a386Sopenharmony_ci attachment.storeOp = wgpu::StoreOp::Store; 81cb93a386Sopenharmony_ci attachment.clearColor = clearColor; 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci wgpu::RenderPassDescriptor renderpass{}; 84cb93a386Sopenharmony_ci renderpass.colorAttachmentCount = 1; 85cb93a386Sopenharmony_ci renderpass.colorAttachments = &attachment; 86cb93a386Sopenharmony_ci wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); 87cb93a386Sopenharmony_ci wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderpass); 88cb93a386Sopenharmony_ci pass.SetPipeline(pipeline); 89cb93a386Sopenharmony_ci pass.Draw(3, // vertexCount 90cb93a386Sopenharmony_ci 1, // instanceCount 91cb93a386Sopenharmony_ci 0, // firstIndex 92cb93a386Sopenharmony_ci 0 // firstInstance 93cb93a386Sopenharmony_ci ); 94cb93a386Sopenharmony_ci pass.EndPass(); 95cb93a386Sopenharmony_ci wgpu::CommandBuffer commands = encoder.Finish(); 96cb93a386Sopenharmony_ci device.GetQueue().Submit(1, &commands); 97cb93a386Sopenharmony_ci} 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ciclass WebGPUSurface { 100cb93a386Sopenharmony_cipublic: 101cb93a386Sopenharmony_ci WebGPUSurface(std::string canvasSelector, int width, int height) { 102cb93a386Sopenharmony_ci fDevice = wgpu::Device::Acquire(emscripten_webgpu_get_device()); 103cb93a386Sopenharmony_ci fCanvasSwap = getSwapChainForCanvas(fDevice, canvasSelector, width, height); 104cb93a386Sopenharmony_ci } 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_ci wgpu::ShaderModule makeShader(std::string source) { 107cb93a386Sopenharmony_ci return createShaderModule(fDevice, source.c_str()); 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_ci wgpu::RenderPipeline makeRenderPipeline(wgpu::ShaderModule vertexShader, 111cb93a386Sopenharmony_ci wgpu::ShaderModule fragmentShader) { 112cb93a386Sopenharmony_ci return createRenderPipeline(fDevice, vertexShader, fragmentShader); 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci void drawPipeline(wgpu::RenderPipeline pipeline, float r, float g, float b, float a) { 116cb93a386Sopenharmony_ci // We cannot cache the TextureView because it will be destroyed after use. 117cb93a386Sopenharmony_ci ::drawPipeline(fDevice, fCanvasSwap.GetCurrentTextureView(), pipeline, {r, g, b, a}); 118cb93a386Sopenharmony_ci } 119cb93a386Sopenharmony_ci 120cb93a386Sopenharmony_ciprivate: 121cb93a386Sopenharmony_ci wgpu::Device fDevice; 122cb93a386Sopenharmony_ci wgpu::SwapChain fCanvasSwap; 123cb93a386Sopenharmony_ci}; 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ciEMSCRIPTEN_BINDINGS(Skia) { 126cb93a386Sopenharmony_ci class_<WebGPUSurface>("WebGPUSurface") 127cb93a386Sopenharmony_ci .constructor<std::string, int, int>() 128cb93a386Sopenharmony_ci .function("MakeShader", &WebGPUSurface::makeShader) 129cb93a386Sopenharmony_ci .function("MakeRenderPipeline", &WebGPUSurface::makeRenderPipeline) 130cb93a386Sopenharmony_ci .function("drawPipeline", &WebGPUSurface::drawPipeline); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci class_<wgpu::ShaderModule>("ShaderModule"); 133cb93a386Sopenharmony_ci class_<wgpu::RenderPipeline>("RenderPipeline"); 134cb93a386Sopenharmony_ci} 135