diff --git a/cpp/deps b/cpp/deps index 59453e1b..a234fd51 160000 --- a/cpp/deps +++ b/cpp/deps @@ -1 +1 @@ -Subproject commit 59453e1bac7a407ab2218924b4d266faeac5d87f +Subproject commit a234fd5151dfeb623522c06b1b9a35050dfe7c14 diff --git a/cpp/examples/luma.gl/animometer.cpp b/cpp/examples/luma.gl/animometer.cpp index 41f72499..e2d12231 100644 --- a/cpp/examples/luma.gl/animometer.cpp +++ b/cpp/examples/luma.gl/animometer.cpp @@ -21,198 +21,14 @@ // Note: This file was inspired by the Dawn codebase at https://dawn.googlesource.com/dawn/ // Copyright 2017 The Dawn Authors http://www.apache.org/licenses/LICENSE-2.0 -#include -#include #include #include "luma.gl/core.h" #include "probe.gl/core.h" -wgpu::Device device; -wgpu::Queue queue; -wgpu::SwapChain swapchain; -wgpu::RenderPipeline pipeline; -wgpu::BindGroup bindGroup; -wgpu::Buffer ubo; - -lumagl::GLFWAnimationLoop animationLoop{wgpu::BackendType::Metal}; - -float RandomFloat(float min, float max) { - float zeroOne = rand() / float(RAND_MAX); - return zeroOne * (max - min) + min; -} - -constexpr size_t kNumTriangles = 10000; - -struct alignas(lumagl::utils::kMinDynamicBufferOffsetAlignment) ShaderData { - float scale; - float time; - float offsetX; - float offsetY; - float scalar; - float scalarOffset; -}; - -static std::vector shaderData; - -void init() { - device = animationLoop.createDevice(wgpu::BackendType::Metal); - - queue = device.CreateQueue(); - swapchain = animationLoop.getSwapChain(device); - swapchain.Configure(animationLoop.getPreferredSwapChainTextureFormat(), wgpu::TextureUsage::OutputAttachment, 640, - 480); - - wgpu::ShaderModule vsModule = lumagl::utils::createShaderModule(device, lumagl::utils::SingleShaderStage::Vertex, R"( - #version 450 - - layout(std140, set = 0, binding = 0) uniform Constants { - float scale; - float time; - float offsetX; - float offsetY; - float scalar; - float scalarOffset; - } c; - - layout(location = 0) out vec4 v_color; - - const vec4 positions[3] = vec4[3]( - vec4( 0.0f, 0.1f, 0.0f, 1.0f), - vec4(-0.1f, -0.1f, 0.0f, 1.0f), - vec4( 0.1f, -0.1f, 0.0f, 1.0f) - ); - - const vec4 colors[3] = vec4[3]( - vec4(1.0f, 0.0f, 0.0f, 1.0f), - vec4(0.0f, 1.0f, 0.0f, 1.0f), - vec4(0.0f, 0.0f, 1.0f, 1.0f) - ); - - void main() { - vec4 position = positions[gl_VertexIndex]; - vec4 color = colors[gl_VertexIndex]; - - float fade = mod(c.scalarOffset + c.time * c.scalar / 10.0, 1.0); - if (fade < 0.5) { - fade = fade * 2.0; - } else { - fade = (1.0 - fade) * 2.0; - } - float xpos = position.x * c.scale; - float ypos = position.y * c.scale; - float angle = 3.14159 * 2.0 * fade; - float xrot = xpos * cos(angle) - ypos * sin(angle); - float yrot = xpos * sin(angle) + ypos * cos(angle); - xpos = xrot + c.offsetX; - ypos = yrot + c.offsetY; - v_color = vec4(fade, 1.0 - fade, 0.0, 1.0) + color; - gl_Position = vec4(xpos, ypos, 0.0, 1.0); - })"); - - wgpu::ShaderModule fsModule = - lumagl::utils::createShaderModule(device, lumagl::utils::SingleShaderStage::Fragment, R"( - #version 450 - layout(location = 0) out vec4 fragColor; - layout(location = 0) in vec4 v_color; - void main() { - fragColor = v_color; - })"); - - wgpu::BindGroupLayout bgl = lumagl::utils::makeBindGroupLayout( - device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::UniformBuffer, true}}); - - lumagl::utils::ComboRenderPipelineDescriptor descriptor(device); - descriptor.layout = lumagl::utils::makeBasicPipelineLayout(device, &bgl); - descriptor.vertexStage.module = vsModule; - descriptor.cFragmentStage.module = fsModule; - descriptor.cColorStates[0].format = animationLoop.getPreferredSwapChainTextureFormat(); - - pipeline = device.CreateRenderPipeline(&descriptor); - - shaderData.resize(kNumTriangles); - for (auto& data : shaderData) { - data.scale = RandomFloat(0.2f, 0.4f); - data.time = 0.0; - data.offsetX = RandomFloat(-0.9f, 0.9f); - data.offsetY = RandomFloat(-0.9f, 0.9f); - data.scalar = RandomFloat(0.5f, 2.0f); - data.scalarOffset = RandomFloat(0.0f, 10.0f); - } - - wgpu::BufferDescriptor bufferDesc; - bufferDesc.size = kNumTriangles * sizeof(ShaderData); - bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform; - ubo = device.CreateBuffer(&bufferDesc); - - bindGroup = lumagl::utils::makeBindGroup(device, bgl, {{0, ubo, 0, sizeof(ShaderData)}}); -} - -void frame() { - wgpu::TextureView backbufferView = swapchain.GetCurrentTextureView(); - - static int f = 0; - f++; - for (auto& data : shaderData) { - data.time = f / 60.0f; - } - ubo.SetSubData(0, kNumTriangles * sizeof(ShaderData), shaderData.data()); - - lumagl::utils::ComboRenderPassDescriptor renderPass({backbufferView}); - wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); - { - wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); - pass.SetPipeline(pipeline); - - for (size_t i = 0; i < kNumTriangles; i++) { - uint32_t offset = static_cast(i * sizeof(ShaderData)); - pass.SetBindGroup(0, bindGroup, 1, &offset); - pass.Draw(3, 1, 0, 0); - } - - pass.EndPass(); - } - - wgpu::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); - swapchain.Present(); - animationLoop.flush(); - // fprintf(stderr, "frame %i\n", f); -} - -int main(int argc, const char* argv[]) { - init(); - - while (!glfwWindowShouldClose(animationLoop.window)) { - frame(); - probegl::uSleep(16000); - } - - // TODO release stuff -} - -/* - -#include "luma.gl/core.h" - using namespace lumagl; -using namespace lumagl::utils; -float RandomFloat(float min, float max) { - float zeroOne = rand() / float(RAND_MAX); - return zeroOne * (max - min) + min; -} - -constexpr size_t kNumTriangles = 10000; - -struct alignas(kMinDynamicBufferOffsetAlignment) ShaderData { - float scale; - float time; - float offsetX; - float offsetY; - float scalar; - float scalarOffset; -}; +namespace { auto vs = R"( #version 450 @@ -269,86 +85,71 @@ void main() { fragColor = v_color; })"; -static std::vector shaderData; +auto randomFloat(float min, float max) -> float { + float zeroOne = rand() / float(RAND_MAX); + return zeroOne * (max - min) + min; +} -int main(int argc, const char* argv[]) { - // if (!InitSample(argc, argv)) { - // return 1; - // } +constexpr size_t kNumTriangles = 10000; - GLFWAnimationLoop animationLoop{wgpu::BackendType::Vulkan}; - auto device = animationLoop.createDevice(wgpu::BackendType::Vulkan); +struct alignas(utils::kMinDynamicBufferOffsetAlignment) ShaderData { + float scale; + float time; + float offsetX; + float offsetY; + float scalar; + float scalarOffset; +}; -// animationLoop.initializeDevice(); +auto createSampleData(int count) -> std::vector { + std::vector shaderData; + shaderData.resize(count); + for (auto& data : shaderData) { + data.scale = randomFloat(0.2f, 0.4f); + data.time = 0.0; + data.offsetX = randomFloat(-0.9f, 0.9f); + data.offsetY = randomFloat(-0.9f, 0.9f); + data.scalar = randomFloat(0.5f, 2.0f); + data.scalarOffset = randomFloat(0.0f, 10.0f); + } - Model::Options options{vs, fs}; - Model model{device, options}; + return shaderData; +} + +} // anonymous namespace + +int main(int argc, const char* argv[]) { + GLFWAnimationLoop animationLoop{}; + wgpu::Device device = *(animationLoop.device.get()); -// init(); + Model::Options options{vs, fs, animationLoop.getPreferredSwapChainTextureFormat()}; + Model model{animationLoop.device, options}; - animationLoop.onBeforeRender = [](AnimationLoop*) { -// static int f = 0; -// f++; -// for (auto& data : shaderData) { -// data.time = f / 60.0f; -// } -// ubo.SetSubData(0, kNumTriangles * sizeof(ShaderData), shaderData.data()); - }; + std::vector shaderData = createSampleData(kNumTriangles); - animationLoop.run([model](wgpu::RenderPassEncoder pass) { + wgpu::BufferDescriptor bufferDesc; + bufferDesc.size = kNumTriangles * sizeof(ShaderData); + bufferDesc.usage = wgpu::BufferUsage::CopyDst | wgpu::BufferUsage::Uniform; + wgpu::Buffer ubo = device.CreateBuffer(&bufferDesc); + + wgpu::BindGroup bindGroup = + utils::makeBindGroup(device, *model.uniformBindGroupLayout.get(), {{0, ubo, 0, sizeof(ShaderData)}}); + + animationLoop.run([&](wgpu::RenderPassEncoder pass) { static int f = 0; f++; for (auto& data : shaderData) { - data.time = f / 60.0f; + data.time = f / 60.0f; } ubo.SetSubData(0, kNumTriangles * sizeof(ShaderData), shaderData.data()); - pass.SetPipeline(model.pipeline); + pass.SetPipeline(*model.pipeline.get()); for (size_t i = 0; i < kNumTriangles; i++) { - uint32_t offset = i * sizeof(ShaderData); + uint32_t offset = static_cast(i * sizeof(ShaderData)); pass.SetBindGroup(0, bindGroup, 1, &offset); pass.Draw(3, 1, 0, 0); } }); - // TODO(ib@unfolded.ai): do we need to release stuff? -} - - -bool InitSample(int argc, const char** argv) { - for (int i = 1; i < argc; i++) { - if (std::string("-b") == argv[i] || std::string("--backend") == argv[i]) { - i++; - if (i >= argc) { - - } - auto backendType = i < argc getBackendTypeFromString() - fprintf(stderr, "--backend expects a backend name (opengl, metal, d3d12, null, vulkan)\n"); - return false; - } - - cmdBufType = CmdBufType::None; - if (std::string("-c") == argv[i] || std::string("--command-buffer") == argv[i]) { - i++; - if (i < argc && std::string("none") == argv[i]) { - cmdBufType = CmdBufType::None; - continue; - } - if (i < argc && std::string("terrible") == argv[i]) { - cmdBufType = CmdBufType::Terrible; - continue; - } - fprintf(stderr, "--command-buffer expects a command buffer name (none, terrible)\n"); - return false; - } - - if (std::string("-h") == argv[i] || std::string("--help") == argv[i]) { - printf("Usage: %s [-b BACKEND] [-c COMMAND_BUFFER]\n", argv[0]); - printf(" BACKEND is one of: d3d12, metal, null, opengl, vulkan\n"); - printf(" COMMAND_BUFFER is one of: none, terrible\n"); - return false; - } - } - return true; + return 0; } -*/ diff --git a/cpp/modules/deck.gl/core/src/lib/constants.cpp b/cpp/modules/deck.gl/core/src/lib/constants.cpp index c3b3e237..8d0271eb 100644 --- a/cpp/modules/deck.gl/core/src/lib/constants.cpp +++ b/cpp/modules/deck.gl/core/src/lib/constants.cpp @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -#include "./constants.h" +#include "./constants.h" // NOLINT(build/include) using namespace deckgl; @@ -44,4 +44,4 @@ auto deckgl::operator<<(std::ostream& os, COORDINATE_SYSTEM cs) -> std::ostream& break; } return os; -} \ No newline at end of file +} diff --git a/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.cpp b/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.cpp index 7a265b0b..d23a0644 100644 --- a/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.cpp +++ b/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.cpp @@ -242,7 +242,8 @@ auto ScatterplotLayer::_getModel(wgpu::Device device) -> std::shared_ptr(new lumagl::Model(device)); + auto devicePtr = std::make_shared(std::move(device)); + return std::shared_ptr(new lumagl::Model(devicePtr)); // Object.assign(this->getShaders(), { // id: this->props.id, // geometry: new Geometry({ diff --git a/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.h b/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.h index 1da8c892..b32c060a 100644 --- a/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.h +++ b/cpp/modules/deck.gl/layers/src/scatterplot-layer/scatterplot-layer.h @@ -53,6 +53,7 @@ class ScatterplotLayer : public Layer { void drawState() override; private: + // TODO(ilija@unfolded.ai): Is there a way to avoid passing device here? auto _getModel(wgpu::Device device) -> std::shared_ptr; }; diff --git a/cpp/modules/luma.gl/CMakeLists.txt b/cpp/modules/luma.gl/CMakeLists.txt index 048289c5..b049f275 100644 --- a/cpp/modules/luma.gl/CMakeLists.txt +++ b/cpp/modules/luma.gl/CMakeLists.txt @@ -29,13 +29,11 @@ set(WEBGPU_HEADER_FILE_LIST webgpu/src/webgpu-constants.h webgpu/src/webgpu-utils.h webgpu/src/webgpu-helpers.h - webgpu/src/terrible-command-buffer.h webgpu/src/backends/backend-binding.h ) set(WEBGPU_SOURCE_FILE_LIST webgpu/src/combo-render-pipeline-descriptor.cpp webgpu/src/shaderc-utils.cpp - webgpu/src/terrible-command-buffer.cpp webgpu/src/webgpu-utils.cpp webgpu/src/webgpu-helpers.cpp webgpu/src/backends/backend-binding.cpp @@ -60,16 +58,12 @@ set(TESTS_SOURCE_FILE_LIST find_library(dawn_proc_LIB dawn_proc PATH ${DECK_DEPS_PATH} NO_DEFAULT_PATH) find_library(dawn_native_LIB dawn_native PATH ${DECK_DEPS_PATH} NO_DEFAULT_PATH) -find_library(dawn_wire_LIB dawn_wire PATH ${DECK_DEPS_PATH} NO_DEFAULT_PATH) -find_library(dawn_bindings_LIB dawn_bindings PATH ${DECK_DEPS_PATH} NO_DEFAULT_PATH) find_library(glfw_LIB glfw PATH ${DECK_DEPS_PATH} NO_DEFAULT_PATH) find_library(shaderc_LIB shaderc_combined PATH ${DECK_DEPS_PATH} NO_DEFAULT_PATH) target_link_libraries(luma.gl PUBLIC ${DECK_LINK_FLAGS} ${dawn_proc_LIB} ${dawn_native_LIB} - ${dawn_wire_LIB} - ${dawn_bindings_LIB} ${glfw_LIB} ${shaderc_LIB} ${DECK_DEPS_PATH}/webgpu_cpp.o diff --git a/cpp/modules/luma.gl/core/src/animation-loop.cpp b/cpp/modules/luma.gl/core/src/animation-loop.cpp index 9c59788e..b67d9522 100644 --- a/cpp/modules/luma.gl/core/src/animation-loop.cpp +++ b/cpp/modules/luma.gl/core/src/animation-loop.cpp @@ -20,6 +20,8 @@ #include "./animation-loop.h" // NOLINT(build/include) +#include + #include #include "luma.gl/webgpu.h" @@ -28,60 +30,40 @@ using namespace lumagl; using namespace lumagl::utils; -AnimationLoop::AnimationLoop(wgpu::Device device_) : device{device_} { - // Create a device if none was provided - // this->swapchain = - this->setSize(640, 480); +AnimationLoop::~AnimationLoop() { + // TODO(ilija@unfolded.ai): Cleanup? } -auto AnimationLoop::createDevice(wgpu::BackendType) -> wgpu::Device { return wgpu::Device(); } - void AnimationLoop::setSize(int width, int height) { bool sizeChanged = width != this->width || height != this->height; this->width = width; this->height = height; if (sizeChanged) { - // auto swapchain = GetSwapChain(device); TODO(ib@unfolded.ai): better to just query for swap chain before use? - // this->swapchain.Configure(GetPreferredSwapChainTextureFormat(), wgpu::TextureUsage::OutputAttachment, - // this->width, - // this->height); + this->swapchain = this->_createSwapchain(this->device); + // TODO(ilija@unfolded.ai): Trigger redraw } } void AnimationLoop::run(std::function onRender) { - if (!this->device) { - this->device = this->createDevice(getDefaultWebGPUBackendType()); - this->queue = this->device.CreateQueue(); - } - this->running = true; + // TODO(ilija@unfolded.ai): Add needsRedraw and check it while (this->running && !this->shouldQuit()) { this->frame(onRender); // TODO(ib@unfolded.ai): We should not wait 16ms, we should wait **max** 16ms. - // uSleep(16000); + probegl::uSleep(16000); } this->running = false; } -void AnimationLoop::stop() { this->running = false; } - -/* - if (!this->onNeedsRedraw(this)) { - return; - } - this->onBeforeRender(this); - this->onRender(this, pass); - this->onAfterRender(this); -*/ - void AnimationLoop::frame(std::function onRender) { - wgpu::TextureView backbufferView = this->swapchain.GetCurrentTextureView(); + // TODO(ilija@unfolded.ai): There seems to be a memory leak, what do we need to free? + wgpu::TextureView backbufferView = this->swapchain->GetCurrentTextureView(); - utils::ComboRenderPassDescriptor renderPass({backbufferView}); - wgpu::CommandEncoder encoder = device.CreateCommandEncoder(); + utils::ComboRenderPassDescriptor passDescriptor({backbufferView}); + wgpu::CommandEncoder encoder = device->CreateCommandEncoder(); { - wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&renderPass); + wgpu::RenderPassEncoder pass = encoder.BeginRenderPass(&passDescriptor); onRender(pass); // TODO(ib@unfolded.ai): protect with try catch @@ -90,8 +72,28 @@ void AnimationLoop::frame(std::function onRender) wgpu::CommandBuffer commands = encoder.Finish(); - this->queue.Submit(1, &commands); - this->swapchain.Present(); + this->queue->Submit(1, &commands); + this->swapchain->Present(); this->flush(); } + +void AnimationLoop::stop() { this->running = false; } + +void AnimationLoop::_initialize(const wgpu::BackendType backendType, std::shared_ptr device) { + // TODO(ilija@unfolded.ai): This should likely be set up globally? + DawnProcTable procs = dawn_native::GetProcs(); + dawnProcSetProcs(&procs); + procs.deviceSetUncapturedErrorCallback( + device->Get(), + [](WGPUErrorType errorType, const char* message, void*) { + probegl::ErrorLog() << getWebGPUErrorName(errorType) << " error: " << message; + }, + nullptr); + + this->device = device; + this->queue = std::make_unique(this->device->CreateQueue()); + this->swapchain = this->_createSwapchain(this->device); + + this->setSize(width, height); +} diff --git a/cpp/modules/luma.gl/core/src/animation-loop.h b/cpp/modules/luma.gl/core/src/animation-loop.h index 689a8fca..5f70cd4c 100644 --- a/cpp/modules/luma.gl/core/src/animation-loop.h +++ b/cpp/modules/luma.gl/core/src/animation-loop.h @@ -24,37 +24,40 @@ #include #include +#include namespace lumagl { class AnimationLoop { public: - explicit AnimationLoop(wgpu::Device device = nullptr); + virtual ~AnimationLoop(); void setSize(int width, int height); - void run(std::function); - void frame(std::function); - void stop(); + virtual void run(std::function onRender); + virtual void frame(std::function onRender); + virtual void stop(); - std::function onNeedsRedraw{[](AnimationLoop *) { return true; }}; - std::function onBeforeRender{[](AnimationLoop *) {}}; - std::function onRender{[](AnimationLoop *) {}}; - std::function onAfterRender{[](AnimationLoop *) {}}; - - virtual auto createDevice(wgpu::BackendType) -> wgpu::Device; virtual bool shouldQuit() { return false; } virtual void flush() {} + virtual auto getPreferredSwapChainTextureFormat() -> wgpu::TextureFormat { return wgpu::TextureFormat::Undefined; }; + // TODO(ilija@unfolded.ai): Make these read-only? int width{640}; int height{480}; // Internal, but left public to facilitate integration - wgpu::Device device; - wgpu::Queue queue; - wgpu::SwapChain swapchain; + std::shared_ptr device; + std::unique_ptr queue; + std::unique_ptr swapchain; + // TODO(ilija@unfolded.ai): Make this read-only? bool running{false}; + + protected: + void _initialize(const wgpu::BackendType backendType, std::shared_ptr device); + virtual auto _createDevice(const wgpu::BackendType backendType) -> std::unique_ptr = 0; + virtual auto _createSwapchain(std::shared_ptr device) -> std::unique_ptr = 0; }; } // namespace lumagl diff --git a/cpp/modules/luma.gl/core/src/glfw-animation-loop.cpp b/cpp/modules/luma.gl/core/src/glfw-animation-loop.cpp index 12e845ba..a672cc15 100644 --- a/cpp/modules/luma.gl/core/src/glfw-animation-loop.cpp +++ b/cpp/modules/luma.gl/core/src/glfw-animation-loop.cpp @@ -1,22 +1,31 @@ -// Copyright 2017 The Dawn Authors under http://www.apache.org/licenses/LICENSE-2.0 +// Copyright (c) 2020 Unfolded Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #include "./glfw-animation-loop.h" // NOLINT(build/include) -#include -#include +#include +#include +#include +#include -#include "GLFW/glfw3.h" -#include "GLFW/glfw3native.h" -#include "dawn/dawn_proc.h" -#include "dawn/dawn_wsi.h" -#include "dawn/webgpu_cpp.h" -#include "dawn_native/DawnNative.h" -#include "dawn_wire/WireClient.h" -#include "dawn_wire/WireServer.h" - -// #include "utils/BackendBinding.h" -// #include "utils/GLFWUtils.h" -// #include "utils/TerribleCommandBuffer.h" +#include #include "luma.gl/webgpu.h" #include "probe.gl/core.h" @@ -30,84 +39,51 @@ using namespace lumagl; using namespace lumagl::utils; -enum class CmdBufType { - None, - Terrible, - // TODO(cwallez@chromium.org) double terrible cmdbuf -}; +GLFWAnimationLoop::GLFWAnimationLoop(const wgpu::BackendType backendType, std::shared_ptr device) { + this->_window = this->_initializeGLFW(backendType); -static auto cmdBufType = CmdBufType::Terrible; + // Create a device if none was provided + auto _device = device; + if (device == nullptr) { + _device = this->_createDevice(backendType); + } -GLFWAnimationLoop::GLFWAnimationLoop(wgpu::BackendType backendType) : AnimationLoop{} { - this->_initializeGLFW(backendType); - this->window = glfwCreateWindow(640, 480, "deck.gl window", nullptr, nullptr); - if (!this->window) { - throw new std::runtime_error("Failed to create GLFW window"); + this->_binding = CreateBinding(backendType, this->_window, _device->Get()); + if (this->_binding == nullptr) { + throw new std::runtime_error("Failed to create binding"); } -} -auto GLFWAnimationLoop::createDevice(wgpu::BackendType backendType) -> wgpu::Device { - return this->_createCppDawnDevice(backendType); + this->_initialize(backendType, _device); } -bool GLFWAnimationLoop::shouldQuit() { return glfwWindowShouldClose(this->window); } +GLFWAnimationLoop::~GLFWAnimationLoop() { + glfwTerminate(); -void GLFWAnimationLoop::flush() { - if (this->_c2sBuf) { - bool c2sSuccess = this->_c2sBuf->Flush(); - ASSERT(c2sSuccess); - } - if (this->_s2cBuf) { - bool s2cSuccess = this->_s2cBuf->Flush(); - ASSERT(s2cSuccess); - } - - glfwPollEvents(); + // TODO(ilija@unfolded.ai): Additional cleanup? } -auto GLFWAnimationLoop::getSwapChain(const wgpu::Device& device) -> wgpu::SwapChain { - wgpu::SwapChainDescriptor swapChainDesc; - swapChainDesc.implementation = this->_getSwapChainImplementation(); - return device.CreateSwapChain(nullptr, &swapChainDesc); -} +void GLFWAnimationLoop::frame(std::function onRender) { + // Break the run loop if esc is pressed + if (glfwGetKey(this->_window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { + glfwSetWindowShouldClose(this->_window, true); + } -wgpu::TextureFormat GLFWAnimationLoop::getPreferredSwapChainTextureFormat() { - this->flush(); - return static_cast(this->_binding->GetPreferredSwapChainTextureFormat()); + AnimationLoop::frame(onRender); } -void GLFWAnimationLoop::_initializeGLFW(wgpu::BackendType backendType) { - // Set up an error logging callback - glfwSetErrorCallback([](int code, const char* message) { - probegl::ErrorLog() << "GLFW error: " << code << " - " << message; - }); +bool GLFWAnimationLoop::shouldQuit() { return glfwWindowShouldClose(this->_window); } - // Init the library - if (!glfwInit()) { - throw new std::runtime_error("Failed to initialize GLFW"); - } +void GLFWAnimationLoop::flush() { glfwPollEvents(); } - // Configure graphics context creation - switch (backendType) { - case wgpu::BackendType::OpenGL: - // Ask for OpenGL 4.4 which is what the GL backend requires for compute shaders and texture views. - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - break; - default: - // Without this GLFW will initialize a GL context on the window, which prevents using - // the window with other APIs (by crashing in weird ways). - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - } +auto GLFWAnimationLoop::getPreferredSwapChainTextureFormat() -> wgpu::TextureFormat { + // TODO(ilija@unfolded.ai): Why do we flush here? + this->flush(); + return static_cast(this->_binding->GetPreferredSwapChainTextureFormat()); } -uint64_t GLFWAnimationLoop::_getSwapChainImplementation() { return this->_binding->GetSwapChainImplementation(); } - -auto GLFWAnimationLoop::_createCppDawnDevice(wgpu::BackendType backendType) -> wgpu::Device { +auto GLFWAnimationLoop::_createDevice(const wgpu::BackendType backendType) -> std::unique_ptr { this->_instance = std::make_unique(); - DiscoverAdapter(this->_instance.get(), this->window, backendType); + DiscoverAdapter(this->_instance.get(), this->_window, backendType); // Get an adapter for the backend to use, and create the device. dawn_native::Adapter backendAdapter; @@ -122,70 +98,55 @@ auto GLFWAnimationLoop::_createCppDawnDevice(wgpu::BackendType backendType) -> w backendAdapter = *adapterIt; } - WGPUDevice backendDevice = backendAdapter.CreateDevice(); - DawnProcTable backendProcs = dawn_native::GetProcs(); - - this->_binding = CreateBinding(backendType, this->window, backendDevice); - if (this->_binding == nullptr) { - return nullptr; - } - - // Choose whether to use the backend procs and devices directly, or set up the wire. - WGPUDevice cDevice = nullptr; - DawnProcTable procs; - - switch (cmdBufType) { - case CmdBufType::None: - procs = backendProcs; - cDevice = backendDevice; - break; + WGPUDevice cDevice = backendAdapter.CreateDevice(); + auto device = wgpu::Device::Acquire(cDevice); - case CmdBufType::Terrible: { - this->_c2sBuf = new TerribleCommandBuffer(); - this->_s2cBuf = new TerribleCommandBuffer(); + return std::make_unique(std::move(device)); +} - dawn_wire::WireServerDescriptor serverDesc = {}; - serverDesc.device = backendDevice; - serverDesc.procs = &backendProcs; - serverDesc.serializer = this->_s2cBuf; +auto GLFWAnimationLoop::_createSwapchain(std::shared_ptr device) -> std::unique_ptr { + wgpu::SwapChainDescriptor swapChainDesc; + swapChainDesc.implementation = this->_binding->GetSwapChainImplementation(); + auto swapchain = device->CreateSwapChain(nullptr, &swapChainDesc); + swapchain.Configure(this->getPreferredSwapChainTextureFormat(), wgpu::TextureUsage::OutputAttachment, this->width, + this->height); - this->_wireServer = new dawn_wire::WireServer(serverDesc); - this->_c2sBuf->SetHandler(this->_wireServer); + return std::make_unique(std::move(swapchain)); +} - dawn_wire::WireClientDescriptor clientDesc = {}; - clientDesc.serializer = this->_c2sBuf; +auto GLFWAnimationLoop::_initializeGLFW(const wgpu::BackendType backendType) -> GLFWwindow* { + // Set up an error logging callback + glfwSetErrorCallback( + [](int code, const char* message) { probegl::ErrorLog() << "GLFW error: " << code << " - " << message; }); - this->_wireClient = new dawn_wire::WireClient(clientDesc); - WGPUDevice clientDevice = this->_wireClient->GetDevice(); - DawnProcTable clientProcs = dawn_wire::WireClient::GetProcs(); - this->_s2cBuf->SetHandler(this->_wireClient); + // Init the library + if (!glfwInit()) { + throw new std::runtime_error("Failed to initialize GLFW"); + } - procs = clientProcs; - cDevice = clientDevice; - } break; + // Configure graphics context creation + switch (backendType) { + case wgpu::BackendType::OpenGL: + // Ask for OpenGL 4.4 which is what the GL backend requires for compute shaders and texture views. + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + break; + default: + // Without this GLFW will initialize a GL context on the window, which prevents using + // the window with other APIs (by crashing in weird ways). + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); } - dawnProcSetProcs(&procs); - procs.deviceSetUncapturedErrorCallback( - cDevice, - [](WGPUErrorType errorType, const char* message, void*) { - probegl::ErrorLog() << getWebGPUErrorName(errorType) << " error: " << message; - }, - nullptr); - return wgpu::Device::Acquire(cDevice); -} + auto window = glfwCreateWindow(this->width, this->height, "deck.gl window", nullptr, nullptr); + if (!window) { + throw new std::runtime_error("Failed to create GLFW window"); + } + // TODO(ilija@unfolded.ai): Handle window resizing + // glfwSetFramebufferSizeCallback(window, [this](GLFWwindow* window, int width, int height) { + // this->setSize(width, height); + // }); -auto GLFWAnimationLoop::_createDefaultDepthStencilView(const wgpu::Device& device) -> wgpu::TextureView { - wgpu::TextureDescriptor descriptor; - descriptor.dimension = wgpu::TextureDimension::e2D; - descriptor.size.width = 640; - descriptor.size.height = 480; - descriptor.size.depth = 1; - descriptor.arrayLayerCount = 1; - descriptor.sampleCount = 1; - descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8; - descriptor.mipLevelCount = 1; - descriptor.usage = wgpu::TextureUsage::OutputAttachment; - auto depthStencilTexture = device.CreateTexture(&descriptor); - return depthStencilTexture.CreateView(); + return window; } diff --git a/cpp/modules/luma.gl/core/src/glfw-animation-loop.h b/cpp/modules/luma.gl/core/src/glfw-animation-loop.h index f755c274..bef02b2f 100644 --- a/cpp/modules/luma.gl/core/src/glfw-animation-loop.h +++ b/cpp/modules/luma.gl/core/src/glfw-animation-loop.h @@ -22,41 +22,41 @@ #define LUMAGL_CORE_GLFW_ANIMATION_LOOP_H #include -#include -#include + +#include #include "./animation-loop.h" #include "luma.gl/webgpu/src/backends/backend-binding.h" -#include "luma.gl/webgpu/src/terrible-command-buffer.h" +#include "luma.gl/webgpu/src/webgpu-utils.h" namespace lumagl { class GLFWAnimationLoop : public AnimationLoop { public: - explicit GLFWAnimationLoop(wgpu::BackendType backendType); + GLFWAnimationLoop(const wgpu::BackendType backendType = utils::getDefaultWebGPUBackendType(), + std::shared_ptr device = nullptr); + ~GLFWAnimationLoop(); + + void frame(std::function onRender) override; - auto createDevice(wgpu::BackendType) -> wgpu::Device override; bool shouldQuit() override; void flush() override; + auto getPreferredSwapChainTextureFormat() -> wgpu::TextureFormat override; - auto getPreferredSwapChainTextureFormat() -> wgpu::TextureFormat; - auto getSwapChain(const wgpu::Device& device) -> wgpu::SwapChain; - - GLFWwindow* window{nullptr}; + protected: + auto _createDevice(const wgpu::BackendType backendType) -> std::unique_ptr override; + auto _createSwapchain(std::shared_ptr device) -> std::unique_ptr override; private: - void _initializeGLFW(wgpu::BackendType); - uint64_t _getSwapChainImplementation(); - auto _createCppDawnDevice(wgpu::BackendType backendType) -> wgpu::Device; - auto _createDefaultDepthStencilView(const wgpu::Device& device) -> wgpu::TextureView; + auto _initializeGLFW(const wgpu::BackendType) -> GLFWwindow*; - std::unique_ptr _instance; + /// \brief Instance used for adapter discovery and device creation. It has to be kept around as Dawn objects' + /// lifecycle seems to depend on it. + /// \note From Dawn docs: This is an RAII class for Dawn instances and also controls the lifetime of all adapters + /// for this instance. + std::unique_ptr _instance{nullptr}; utils::BackendBinding* _binding{nullptr}; - - dawn_wire::WireServer* _wireServer{nullptr}; - dawn_wire::WireClient* _wireClient{nullptr}; - utils::TerribleCommandBuffer* _c2sBuf{nullptr}; - utils::TerribleCommandBuffer* _s2cBuf{nullptr}; + GLFWwindow* _window{nullptr}; }; } // namespace lumagl diff --git a/cpp/modules/luma.gl/core/src/model.cpp b/cpp/modules/luma.gl/core/src/model.cpp index 4b9a8dc9..8bc0447e 100644 --- a/cpp/modules/luma.gl/core/src/model.cpp +++ b/cpp/modules/luma.gl/core/src/model.cpp @@ -23,36 +23,33 @@ #include "luma.gl/webgpu.h" using namespace lumagl; +using namespace lumagl::utils; -namespace lumagl { +Model::Model(std::shared_ptr device) : Model(device, Options{}) {} -// TODO(ib): -auto getBackendBinding() -> utils::BackendBinding * { return nullptr; }; +Model::Model(std::shared_ptr device, const Model::Options& options) { + auto deviceValue = *device.get(); -auto GetPreferredSwapChainTextureFormat() -> wgpu::TextureFormat { - utils::BackendBinding *binding = getBackendBinding(); - return static_cast(binding->GetPreferredSwapChainTextureFormat()); -} - -} // namespace lumagl - -Model::Model(wgpu::Device device) : Model(device, Options{}) {} + auto vsModule = createShaderModule(deviceValue, SingleShaderStage::Vertex, options.vs.c_str()); + auto fsModule = createShaderModule(deviceValue, SingleShaderStage::Fragment, options.fs.c_str()); -Model::Model(wgpu::Device device, const Model::Options &options) { - this->vsModule = utils::createShaderModule(device, utils::SingleShaderStage::Vertex, options.vs.c_str()); - this->fsModule = utils::createShaderModule(device, utils::SingleShaderStage::Fragment, options.fs.c_str()); + auto uniformBindGroupLayout = + makeBindGroupLayout(deviceValue, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::UniformBuffer, true}}); - this->uniformBindGroupLayout = - utils::makeBindGroupLayout(device, {{0, wgpu::ShaderStage::Vertex, wgpu::BindingType::UniformBuffer, true}}); - - utils::ComboRenderPipelineDescriptor descriptor{device}; + ComboRenderPipelineDescriptor descriptor{deviceValue}; descriptor.vertexStage.module = vsModule; descriptor.cFragmentStage.module = fsModule; - descriptor.cColorStates[0].format = GetPreferredSwapChainTextureFormat(); + descriptor.cColorStates[0].format = options.textureFormat; + descriptor.layout = makeBasicPipelineLayout(deviceValue, &uniformBindGroupLayout); - descriptor.layout = utils::makeBasicPipelineLayout(device, &this->uniformBindGroupLayout); + auto pipeline = deviceValue.CreateRenderPipeline(&descriptor); - this->pipeline = device.CreateRenderPipeline(&descriptor); + this->vsModule = std::make_unique(std::move(vsModule)); + this->fsModule = std::make_unique(std::move(fsModule)); + this->uniformBindGroupLayout = std::make_unique(std::move(uniformBindGroupLayout)); + this->pipeline = std::make_unique(std::move(pipeline)); } -void Model::draw() {} +void Model::draw() { + // TODO(ilija@unfolded.ai): Implement +} diff --git a/cpp/modules/luma.gl/core/src/model.h b/cpp/modules/luma.gl/core/src/model.h index 1487c14c..e416d07d 100644 --- a/cpp/modules/luma.gl/core/src/model.h +++ b/cpp/modules/luma.gl/core/src/model.h @@ -23,6 +23,7 @@ #include +#include #include #include "luma.gl/webgpu.h" @@ -35,24 +36,35 @@ class Model { class Options; /// \brief construct a new Model - explicit Model(wgpu::Device device, const Options&); - explicit Model(wgpu::Device device); + explicit Model(std::shared_ptr device, const Options&); + + // TODO(ilija@unfolded.ai): Remove once integration is complete and layers provide valid options + explicit Model(std::shared_ptr device); void draw(); - wgpu::RenderPipeline pipeline; // Rendering pipeline (pass.SetPipeline(model.pipeline)) - wgpu::BindGroupLayout uniformBindGroupLayout; // Uniform buffer - wgpu::ShaderModule vsModule; // Compiled vertex shader - wgpu::ShaderModule fsModule; // Compiled fragment shader + /// \brief Rendering pipeline. + std::unique_ptr pipeline; + /// \brief Layout of the bind group. + std::unique_ptr uniformBindGroupLayout; + /// \brief Compiled vertex shader. + std::unique_ptr vsModule; + /// \brief Compiled fragment shader. + std::unique_ptr fsModule; }; class Model::Options { public: Options() {} - Options(const std::string& vs, const std::string& fs) : vs{vs}, fs{fs} {} + Options(const std::string& vs, const std::string& fs, const wgpu::TextureFormat& textureFormat) + : vs{vs}, fs{fs}, textureFormat{textureFormat} {} - std::string vs; // vertex shader source - std::string fs; // fragment shader source + /// \brief Vertex shader source. + std::string vs; + /// \brief Fragment shader source. + std::string fs; + /// \brief Texture format that the pipeline will use. + wgpu::TextureFormat textureFormat; }; } // namespace lumagl diff --git a/cpp/modules/luma.gl/webgpu.h b/cpp/modules/luma.gl/webgpu.h index 23a23d24..f74f4c43 100644 --- a/cpp/modules/luma.gl/webgpu.h +++ b/cpp/modules/luma.gl/webgpu.h @@ -25,7 +25,6 @@ #include "./webgpu/src/combo-render-pipeline-descriptor.h" #include "./webgpu/src/shaderc-utils.h" #include "./webgpu/src/swap-chain-utils.h" -#include "./webgpu/src/terrible-command-buffer.h" #include "./webgpu/src/webgpu-constants.h" #include "./webgpu/src/webgpu-helpers.h" #include "./webgpu/src/webgpu-utils.h" diff --git a/cpp/modules/luma.gl/webgpu/src/terrible-command-buffer.cpp b/cpp/modules/luma.gl/webgpu/src/terrible-command-buffer.cpp deleted file mode 100644 index 2cdaacb3..00000000 --- a/cpp/modules/luma.gl/webgpu/src/terrible-command-buffer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2020 Unfolded Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -// Note: This file was inspired by the Dawn codebase at https://dawn.googlesource.com/dawn/ -// Copyright 2017 The Dawn Authors http://www.apache.org/licenses/LICENSE-2.0 - -#include "./terrible-command-buffer.h" // NOLINT(build/include) - -#include "probe.gl/core.h" - -using namespace lumagl; -using namespace lumagl::utils; - -TerribleCommandBuffer::TerribleCommandBuffer() {} - -TerribleCommandBuffer::TerribleCommandBuffer(dawn_wire::CommandHandler* handler) : mHandler(handler) {} - -void TerribleCommandBuffer::SetHandler(dawn_wire::CommandHandler* handler) { mHandler = handler; } - -void* TerribleCommandBuffer::GetCmdSpace(size_t size) { - // TODO(kainino@chromium.org): Should we early-out if size is 0? - // (Here and/or in the caller?) It might be good to make the wire receiver get a nullptr - // instead of pointer to zero-sized allocation in mBuffer. - - // Cannot have commands in mBuffer and mLargeBuffer at same time. - ASSERT(mOffset == 0 || mLargeBufferCmdSize == 0); - - if (size > sizeof(mBuffer)) { - // Flush current cmds in mBuffer to keep order. - if (mOffset > 0) { - if (!Flush()) { - return nullptr; - } - return GetCmdSpace(size); - } - - // Resize large buffer to the size that can - // contain incoming command if needed. - if (mLargeBuffer.size() < size) { - mLargeBuffer.resize(size); - } - - // Record whole cmd space. - mLargeBufferCmdSize = size; - - return mLargeBuffer.data(); - } - - // Trigger flush if large buffer contain cmds. - if (mLargeBufferCmdSize > 0) { - if (!Flush()) { - return nullptr; - } - return GetCmdSpace(size); - } - - // Need to flush large buffer first. - ASSERT(mLargeBufferCmdSize == 0); - - char* result = &mBuffer[mOffset]; - - if (sizeof(mBuffer) - size < mOffset) { - if (!Flush()) { - return nullptr; - } - return GetCmdSpace(size); - } - - mOffset += size; - - return result; -} - -bool TerribleCommandBuffer::Flush() { - // Cannot have commands in mBuffer and mLargeBuffer at same time. - ASSERT(mOffset == 0 || mLargeBufferCmdSize == 0); - - bool success = false; - // Big buffer not empty, flush it! - if (mLargeBufferCmdSize > 0) { - success = mHandler->HandleCommands(mLargeBuffer.data(), mLargeBufferCmdSize) != nullptr; - // Clear big command buffers. - mLargeBufferCmdSize = 0; - return success; - } - - success = mHandler->HandleCommands(mBuffer, mOffset) != nullptr; - mOffset = 0; - - return success; -} diff --git a/cpp/modules/luma.gl/webgpu/src/terrible-command-buffer.h b/cpp/modules/luma.gl/webgpu/src/terrible-command-buffer.h deleted file mode 100644 index 08f15697..00000000 --- a/cpp/modules/luma.gl/webgpu/src/terrible-command-buffer.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017 The Dawn Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#ifndef LUMAGL_WEBGPU_TERRIBLE_COMMAND_BUFFER_H -#define LUMAGL_WEBGPU_TERRIBLE_COMMAND_BUFFER_H - -#include - -#include "dawn_wire/Wire.h" - -namespace lumagl { -namespace utils { - -class TerribleCommandBuffer : public dawn_wire::CommandSerializer { - public: - TerribleCommandBuffer(); - explicit TerribleCommandBuffer(dawn_wire::CommandHandler* handler); - - void SetHandler(dawn_wire::CommandHandler* handler); - - void* GetCmdSpace(size_t size) override; - bool Flush() override; - - private: - dawn_wire::CommandHandler* mHandler = nullptr; - size_t mOffset = 0; - // Cannot have commands in mBuffer and mLargeBuffer - // at the same time to ensure commands order. - char mBuffer[1000000]; - std::vector mLargeBuffer; - size_t mLargeBufferCmdSize = 0; -}; - -} // namespace utils -} // namespace lumagl - -#endif // LUMAGL_WEBGPU_TERRIBLE_COMMAND_BUFFER_H diff --git a/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.cpp b/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.cpp index 3c93977b..a019d405 100644 --- a/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.cpp +++ b/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.cpp @@ -196,6 +196,21 @@ auto makeBindGroupLayout(const wgpu::Device& device, return device.CreateBindGroupLayout(&descriptor); } +auto createDefaultDepthStencilView(const wgpu::Device& device) -> wgpu::TextureView { + wgpu::TextureDescriptor descriptor; + descriptor.dimension = wgpu::TextureDimension::e2D; + descriptor.size.width = 640; + descriptor.size.height = 480; + descriptor.size.depth = 1; + descriptor.arrayLayerCount = 1; + descriptor.sampleCount = 1; + descriptor.format = wgpu::TextureFormat::Depth24PlusStencil8; + descriptor.mipLevelCount = 1; + descriptor.usage = wgpu::TextureUsage::OutputAttachment; + auto depthStencilTexture = device.CreateTexture(&descriptor); + return depthStencilTexture.CreateView(); +} + BindingInitializationHelper::BindingInitializationHelper(uint32_t binding, const wgpu::Sampler& sampler) : binding{binding}, sampler{sampler} {} diff --git a/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.h b/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.h index da75a7ec..f916d0fb 100644 --- a/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.h +++ b/cpp/modules/luma.gl/webgpu/src/webgpu-helpers.h @@ -84,6 +84,8 @@ auto makeBindGroupLayout(const wgpu::Device& device, std::initializer_list bindingsInitializer) -> wgpu::BindGroupLayout; +auto createDefaultDepthStencilView(const wgpu::Device& device) -> wgpu::TextureView; + // Helpers to make creating bind groups look nicer: // // utils::MakeBindGroup(device, layout, { diff --git a/cpp/modules/luma.gl/webgpu/src/webgpu-utils.cpp b/cpp/modules/luma.gl/webgpu/src/webgpu-utils.cpp index 1cb6c108..b397d0dc 100644 --- a/cpp/modules/luma.gl/webgpu/src/webgpu-utils.cpp +++ b/cpp/modules/luma.gl/webgpu/src/webgpu-utils.cpp @@ -36,8 +36,10 @@ auto getDefaultWebGPUBackendType() -> wgpu::BackendType { return wgpu::BackendType::Vulkan; #elif defined(LUMAGL_ENABLE_BACKEND_OPENGL) return wgpu::BackendType::OpenGL; -#else +#elif defined(LUMAGL_ENABLE_BACKEND_NULL) return wgpu::BackendType::Null; +#else + #error No backends enabled #endif }