webgpu improvements

This commit is contained in:
Jorijn van der Graaf 2026-05-24 13:32:08 +02:00
commit 8347467e1e
18 changed files with 1932 additions and 153 deletions

View file

@ -0,0 +1,113 @@
/*
Crafter®.Graphics
Copyright (C) 2026 Catcrafts®
catcrafts.net
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation;
*/
// Standalone compute pipeline. Dispatches at any point in the frame
// (inside or outside the UI render pass) via the JS bridge's
// wgpuDispatchCompute, which mirrors the wgpuBuildTLAS pattern of
// attaching to the active encoder when one exists or creating an
// ephemeral encoder+submit when not.
//
// This is the WebGPU counterpart to the Vulkan `:ComputeShader` partition.
// They expose the same conceptual API — Load + Dispatch — but with
// backend-specific binding plumbing. See `:GraphicsTypes` for the
// `GraphicsComputeShader` alias picking the right one per target.
//
// WGSL contract:
// @group(0) @binding(0) uniform PushData // optional; only if pushUniformSize>0
// @group(1+) @binding(N) // user bindings via UICustomBinding
// When rayQuery is on, @group(1) is reserved for the RT heap; user
// bindings start at @group(2).
module;
export module Crafter.Graphics:PlainComputeShader;
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
import std;
import :WebGPU;
import :WebGPUComputeShader; // for UICustomBinding + UICustomBindingKind
export namespace Crafter {
class PlainComputeShader {
public:
std::uint32_t pipelineHandle = 0;
std::uint32_t pushUniformSize = 0;
bool rayQueryCapable = false;
std::vector<UICustomBinding> customBindings;
PlainComputeShader() = default;
PlainComputeShader(const PlainComputeShader&) = delete;
PlainComputeShader& operator=(const PlainComputeShader&) = delete;
PlainComputeShader(PlainComputeShader&& o) noexcept
: pipelineHandle(o.pipelineHandle),
pushUniformSize(o.pushUniformSize),
rayQueryCapable(o.rayQueryCapable),
customBindings(std::move(o.customBindings)) {
o.pipelineHandle = 0;
}
// Compile + link a standalone compute shader.
// wgsl — source.
// pushUniformSize — byte size of the @group(0)@binding(0) uniform
// struct, or 0 if the shader doesn't declare one.
// bindings — every user-declared resource the dispatch
// should bind (groups 1+ if no rayQuery, 2+ if
// rayQuery). Order MUST match `handles` at
// Dispatch time.
// rayQuery — prepend the RT prelude + rayQuery library
// so the shader can call `rayQuery*` helpers.
void Load(std::string_view wgsl,
std::uint32_t pushUniformSize_,
std::span<const UICustomBinding> bindings = {},
bool rayQuery = false) {
pushUniformSize = pushUniformSize_;
rayQueryCapable = rayQuery;
customBindings.assign(bindings.begin(), bindings.end());
pipelineHandle = WebGPU::wgpuLoadComputePipeline(
wgsl.data(), static_cast<std::int32_t>(wgsl.size()),
static_cast<std::int32_t>(pushUniformSize),
customBindings.empty() ? nullptr : customBindings.data(),
static_cast<std::int32_t>(customBindings.size()),
rayQuery ? 1 : 0);
}
void Load(const std::filesystem::path& wgslPath,
std::uint32_t pushUniformSize_,
std::span<const UICustomBinding> bindings = {},
bool rayQuery = false) {
std::ifstream f(wgslPath, std::ios::binary);
if (!f) {
std::println(std::cerr,
"PlainComputeShader::Load: cannot open {}", wgslPath.string());
std::abort();
}
std::string wgsl((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
Load(std::string_view{wgsl}, pushUniformSize_, bindings, rayQuery);
}
// Bind, push, dispatch. `handles` is parallel to the
// UICustomBinding[] passed at Load — order matches.
void Dispatch(const void* push, std::uint32_t pushBytes,
std::span<const std::uint32_t> handles,
std::uint32_t gx,
std::uint32_t gy = 1,
std::uint32_t gz = 1) const {
if (pipelineHandle == 0) return;
WebGPU::wgpuDispatchCompute(
pipelineHandle,
push, static_cast<std::int32_t>(pushBytes),
handles.empty() ? nullptr : handles.data(),
static_cast<std::int32_t>(handles.size()),
static_cast<std::int32_t>(gx),
static_cast<std::int32_t>(gy),
static_cast<std::int32_t>(gz));
}
};
}
#endif // CRAFTER_GRAPHICS_WINDOW_DOM