Crafter.Graphics/interfaces/Crafter.Graphics-ShaderBindingTableWebGPU.cppm
catbot 4e42d663a6 WebGPU RT: wavefront tracer core (GENERATE/PREP/TRACE/SHADE/RESOLVE)
Replace the megakernel @compute entry with five wavefront kernels sharing
one module, connected by GPU ray/hit/payload buffers and a GPU-driven
indirect bounce loop:

  GENERATE -> (PREP -> TRACE -> SHADE) x maxDepth -> RESOLVE

- TRACE contains zero user code (pure _rtwTraverseTlas/Blas, opaque-only).
- PREP publishes dispatchWorkgroupsIndirect args from the live ray count;
  the indirect-args buffer lives in its own bind group so it is never
  bound read-write in the same dispatch that consumes it as INDIRECT.
- New emit/accumulate API: rtEmitPrimaryRay / rtEmitRay / rtAccumulate,
  plus an optional user Resolve stage (tonemap hook; identity by default).
- Per-pass WfParams via a dynamic-offset uniform ring (curIsA/bounce vary
  between passes within one submit).
- Payload-typed wfPayload binding emitted in the codegen region after the
  user's struct Payload; payload travels with each ray (2*W*H slots).
- Request maxBufferSize / maxStorageBufferBindingSize / maxComputeWorkgroups
  PerDimension so the W*H-sized work buffers fit past the 128MB baseline.

VulkanTriangle ported to the new API and renders bit-identical to the
megakernel baseline at maxDepth=1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 16:24:41 +00:00

69 lines
2.8 KiB
C++

/*
Crafter®.Graphics
Copyright (C) 2026 Catcrafts®
catcrafts.net
*/
// DOM-mode shader-binding-table analog. Stores raw WGSL source strings
// plus an explicit entry-function name per shader. PipelineRTWebGPU::Init
// concatenates these into the megakernel WGSL at pipeline-build time.
export module Crafter.Graphics:ShaderBindingTableWebGPU;
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
import std;
export namespace Crafter {
enum class WebGPURTStage : std::uint8_t {
Raygen = 0,
Miss = 1,
ClosestHit = 2,
AnyHit = 3,
// Wavefront RESOLVE-stage tonemap/output hook. Optional: if no
// Resolve shader is registered, RESOLVE writes the linear accum
// buffer through unchanged. Signature:
// fn <entryFn>(coord: vec2<u32>, hdr: vec4<f32>) -> vec4<f32>
Resolve = 4,
};
// One WGSL shader source + the function name PipelineRTWebGPU should
// call from the megakernel switch. The source may declare any helper
// functions and (in exactly one raygen file) the `Payload` struct.
//
// Required signatures inside `source` for `entryFn`:
// Raygen: fn <entryFn>(gid: vec3<u32>)
// Miss: fn <entryFn>(ray: RayDesc, payload: ptr<function, Payload>)
// ClosestHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>)
// AnyHit: fn <entryFn>(ray: RayDesc, hit: HitInfo, payload: ptr<function, Payload>) -> u32
// returns RT_ANYHIT_ACCEPT / RT_ANYHIT_IGNORE / RT_ANYHIT_END_SEARCH.
//
// `RayDesc`, `HitInfo`, the `RT_*` flag/return constants, the `tlas` /
// BLAS / mesh-record bindings, and the `traceRay` function are all
// injected by the library prelude — see the rtWgslPrelude block in
// additional/dom-webgpu.js.
struct WebGPUShader {
std::string source;
std::string entryFn;
WebGPURTStage stage = WebGPURTStage::Raygen;
WebGPUShader() = default;
WebGPUShader(std::string src, std::string fn, WebGPURTStage s)
: source(std::move(src)), entryFn(std::move(fn)), stage(s) {}
// Construct from a WGSL source file path. Reads via the WASI VFS
// so apps shipping their shaders as static files (see the
// `cfg.files.emplace_back("raygen.wgsl")` pattern in
// examples/VulkanTriangle/project.cpp) get them at runtime.
WebGPUShader(const std::filesystem::path& wgslPath,
std::string fn,
WebGPURTStage s);
};
class ShaderBindingTableWebGPU {
public:
std::vector<WebGPUShader> shaders;
void Init(std::span<const WebGPUShader> shaders_) {
shaders.assign(shaders_.begin(), shaders_.end());
}
};
}
#endif // CRAFTER_GRAPHICS_WINDOW_DOM