2026-05-18 04:58:52 +02:00
|
|
|
/*
|
|
|
|
|
Crafter®.Graphics
|
|
|
|
|
Copyright (C) 2026 Catcrafts®
|
|
|
|
|
catcrafts.net
|
|
|
|
|
*/
|
|
|
|
|
|
2026-05-18 05:39:17 +02:00
|
|
|
// User-authored compute shader for DOM mode.
|
|
|
|
|
//
|
|
|
|
|
// Contract:
|
|
|
|
|
// - WGSL source authored by the user.
|
|
|
|
|
// - Group 0 binding 0 is reserved for the UIDispatchHeader uniform
|
|
|
|
|
// (with dynamic offset). The library writes it from the first 48
|
|
|
|
|
// bytes of the push data each dispatch.
|
|
|
|
|
// - Group 1 is reserved for the ping-pong textures: binding 0 is the
|
|
|
|
|
// storage `out` (texture_storage_2d<rgba8unorm, write>), binding 1
|
|
|
|
|
// is the sampled `prev` (texture_2d<f32>). The library auto-binds
|
|
|
|
|
// the right textures depending on the current ping-pong state.
|
|
|
|
|
// - Groups 2+ are user-defined. The user declares each binding via a
|
|
|
|
|
// UICustomBinding descriptor at Load time, naming:
|
|
|
|
|
// - the @group(N) and @binding(N) numbers,
|
|
|
|
|
// - the resource KIND (buffer / sampled texture / sampler),
|
|
|
|
|
// - the BYTE OFFSET in the per-dispatch push data where a
|
|
|
|
|
// uint32 heap slot index lives.
|
|
|
|
|
// At Dispatch time the renderer reads each declared slot out of
|
|
|
|
|
// push data, looks the GPU handle up in the heap (bufferTable /
|
|
|
|
|
// imageTable / samplerTable), and assembles the bind group.
|
2026-05-18 04:58:52 +02:00
|
|
|
|
|
|
|
|
export module Crafter.Graphics:WebGPUComputeShader;
|
|
|
|
|
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
|
|
|
|
|
import std;
|
2026-05-18 05:39:17 +02:00
|
|
|
import :WebGPU;
|
2026-05-18 04:58:52 +02:00
|
|
|
|
|
|
|
|
export namespace Crafter {
|
2026-05-18 05:39:17 +02:00
|
|
|
enum class UICustomBindingKind : std::uint8_t {
|
|
|
|
|
Buffer = 0, // read-only-storage SSBO, handle is a slot into heap.bufferTable
|
|
|
|
|
SampledTexture = 1, // sampled texture_2d<f32>, handle is a slot into heap.imageTable
|
|
|
|
|
Sampler = 2, // filtering sampler, handle is a slot into heap.samplerTable
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct UICustomBinding {
|
|
|
|
|
std::uint8_t group; // @group(N), must be >= 2 (0 and 1 are reserved)
|
|
|
|
|
std::uint8_t binding; // @binding(N)
|
|
|
|
|
UICustomBindingKind kind;
|
|
|
|
|
std::uint8_t _pad;
|
|
|
|
|
std::uint32_t pushOffset; // offset in push data where the slot uint32 lives
|
|
|
|
|
};
|
|
|
|
|
static_assert(sizeof(UICustomBinding) == 8);
|
|
|
|
|
|
|
|
|
|
class WebGPUComputeShader {
|
|
|
|
|
public:
|
|
|
|
|
std::uint32_t pipelineHandle = 0;
|
2026-05-18 18:43:30 +02:00
|
|
|
bool rayQueryCapable = false;
|
2026-05-18 05:39:17 +02:00
|
|
|
std::vector<UICustomBinding> customBindings;
|
|
|
|
|
|
|
|
|
|
WebGPUComputeShader() = default;
|
|
|
|
|
WebGPUComputeShader(const WebGPUComputeShader&) = delete;
|
|
|
|
|
WebGPUComputeShader& operator=(const WebGPUComputeShader&) = delete;
|
|
|
|
|
WebGPUComputeShader(WebGPUComputeShader&& o) noexcept
|
|
|
|
|
: pipelineHandle(o.pipelineHandle),
|
2026-05-18 18:43:30 +02:00
|
|
|
rayQueryCapable(o.rayQueryCapable),
|
2026-05-18 05:39:17 +02:00
|
|
|
customBindings(std::move(o.customBindings)) {
|
|
|
|
|
o.pipelineHandle = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compile + link a custom compute shader. `wgsl` is the source
|
2026-05-18 18:43:30 +02:00
|
|
|
// string; the library does NOT add anything to it (except when
|
|
|
|
|
// `rayQuery` is true — then a RT prelude exposing the rayQuery*
|
|
|
|
|
// API is prepended). The user's shader must declare
|
|
|
|
|
// @group(0)/@group(1) bindings matching the contract above
|
|
|
|
|
// (rayQuery shaders MUST NOT redeclare group(1)).
|
|
|
|
|
// `bindings` lists every additional resource (groups 2+) that the
|
|
|
|
|
// renderer should bind at dispatch time.
|
2026-05-18 05:39:17 +02:00
|
|
|
void Load(std::string_view wgsl,
|
2026-05-18 18:43:30 +02:00
|
|
|
std::span<const UICustomBinding> bindings = {},
|
|
|
|
|
bool rayQuery = false);
|
2026-05-18 05:39:17 +02:00
|
|
|
|
|
|
|
|
// Path-based overload for symmetry with the Vulkan ComputeShader.
|
|
|
|
|
// Reads the file from disk (browser VFS) and forwards to Load(wgsl).
|
|
|
|
|
void Load(const std::filesystem::path& wgslPath,
|
2026-05-18 18:43:30 +02:00
|
|
|
std::span<const UICustomBinding> bindings = {},
|
|
|
|
|
bool rayQuery = false);
|
2026-05-18 04:58:52 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
#endif // CRAFTER_GRAPHICS_WINDOW_DOM
|