Crafter.Graphics/interfaces/Crafter.Graphics-ShaderBindingTableWebGPU.cppm
catbot 321fe596a7 feat(webgpu-rt): add intersection stage, procedural hit group, AABB BLAS API
Extends the cross-backend RT type surface for procedural geometry +
any-hit on the WebGPU path:

- RTShaderGroupType::ProceduralHitGroup + RTShaderGroup::intersectionShader
  (mirror VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_KHR).
- WebGPURTStage::Intersection for AABB intersection shaders.
- Mesh::BuildProcedural(span<RTAabb>, opaque) — the WebGPU analog of a
  VK_GEOMETRY_TYPE_AABBS_KHR geometry.
- wgpuRegisterMeshBLAS gains geomType / opaqueFlag / primCount.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 22:09:14 +00:00

80 lines
3.5 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,
// Intersection shader for AABB (procedural) geometry. Run for each
// AABB primitive the ray enters during TRACE; reports whether the
// procedural surface is hit and at what distance. Signature:
// fn <entryFn>(ray: RayDesc, aabbMin: vec3<f32>, aabbMax: vec3<f32>,
// primitiveId: u32) -> IntersectionResult
// `ray` is in object space. IntersectionResult{ hit, t, attribs,
// hitKind } is declared by the library prelude.
Intersection = 5,
};
// 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.
// Intersection: fn <entryFn>(ray: RayDesc, aabbMin: vec3<f32>, aabbMax: vec3<f32>,
// primitiveId: u32) -> IntersectionResult
// IntersectionResult{ hit: bool, t: f32, attribs: vec2<f32>, hitKind: u32 }.
//
// `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