Crafter.Graphics/interfaces/Crafter.Graphics-PipelineRTWebGPU.cppm
catbot 097cc37347 feat(webgpu): HDR post-process primitives — float textures, storage-texture bindings, RESOLVE→HDR target (#27)
Adds the minimal WebGPU-backend surface an HDR bloom/post chain needs:

1. wgpuCreateStorageImage2D + StorageImage2D<>: runtime rgba16float (or
   other format) textures with STORAGE_BINDING|TEXTURE_BINDING usage, no
   CompressedTextureAsset upload — GPU-produced HDR targets.
2. UICustomBindingKind::StorageTexture (kind 5): write-only storage-texture
   binding carrying a texel format (the freed UICustomBinding::format byte),
   wired through all three binding paths (UI custom / RT / plain compute).
   Float textures already sample via SampledTexture (sampleType float).
3. PipelineRTWebGPU::Init(..., hdrOutputFormat): RESOLVE writes the linear
   accumulator into a user rgba16float texture (RTPass::outTexHandle)
   instead of the rgba8unorm canvas, leaving the composite→swapchain pass to
   the app. Default RGBA8Unorm keeps the canvas path byte-identical.

Existing RT examples updated for the _pad→format field rename; the default
paths are unchanged (verified RTStress builds + renders).

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

71 lines
3.4 KiB
C++

/*
Crafter®.Graphics
Copyright (C) 2026 Catcrafts®
catcrafts.net
*/
// DOM-mode RT pipeline. Mirrors PipelineRTVulkan's surface — Init takes
// the same kind of (raygen, miss, hit) shader-group spans plus an SBT.
// The big difference is implementation: there's no native RT pipeline on
// WebGPU, so Init assembles a single megakernel WGSL by concatenating
// 1. library prelude (types, bindings, ray-flag constants)
// 2. user closesthit / anyhit / miss source files
// 3. library mega-switches dispatched on per-hit hit-group index
// 4. library helpers (rayAabb / rayTriangle / traverseBlas / traverseTlas)
// 5. library traceRay function
// 6. user raygen source files
// 7. @compute entry calling the registered raygen
// and hands the result to wgpuLoadRTPipeline.
//
// The library WGSL itself lives in additional/dom-webgpu.js (rtWgslPrelude
// + rtWgslDispatchTemplate). C++ side only knows the substitution markers.
export module Crafter.Graphics:PipelineRTWebGPU;
#ifdef CRAFTER_GRAPHICS_WINDOW_DOM
import std;
import :RT;
import :WebGPU;
import :ShaderBindingTableWebGPU;
import :WebGPUComputeShader;
export namespace Crafter {
class PipelineRTWebGPU {
public:
std::uint32_t pipelineHandle = 0;
// Mirror of the bindings handed to Init. Kept for the example /
// RTPass to consult when packing the handles[] array at dispatch
// time (one resolved u32 handle per binding, in declaration order).
std::vector<UICustomBinding> userBindings;
// True when Init was given a non-default hdrOutputFormat: RESOLVE
// writes a user storage texture instead of the canvas, and RTPass
// must supply its handle via RTPass::outTexHandle.
bool hdrOutput = false;
// Build the megakernel pipeline. Groups carry indices into
// `sbt.shaders`. The library generates one `case` per registered
// group: closest-hit groups dispatch to their closestHitShader's
// entryFn, miss groups to their generalShader's entryFn, etc.
// The `cmd` parameter is unused on WebGPU; kept for API symmetry.
// `userBindings` declares extra @group(2)+ resources the user's
// closest-hit / miss / raygen WGSL touches (material SSBOs,
// albedo textures, samplers).
// `hdrOutputFormat` defaults to RGBA8Unorm — the canvas ping-pong
// path, unchanged. Pass RGBA16Float (or another float format) to
// have RESOLVE write the linear accumulator into a user storage
// texture instead, for an HDR post-process chain. The app then owns
// the composite→swapchain pass and must set RTPass::outTexHandle.
void Init(WebGPUCommandEncoderRef cmd,
std::span<const RTShaderGroup> raygenGroups,
std::span<const RTShaderGroup> missGroups,
std::span<const RTShaderGroup> hitGroups,
const ShaderBindingTableWebGPU& sbt,
std::span<const UICustomBinding> bindings = {},
WebGPUTexelFormat hdrOutputFormat
= WebGPUTexelFormat::RGBA8Unorm);
PipelineRTWebGPU() = default;
PipelineRTWebGPU(const PipelineRTWebGPU&) = delete;
PipelineRTWebGPU& operator=(const PipelineRTWebGPU&) = delete;
};
}
#endif // CRAFTER_GRAPHICS_WINDOW_DOM