feat(webgpu): HDR post-process primitives for bloom (#27) #28
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Catcrafts/Crafter.Graphics!28
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "claude/issue-27"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Implements the minimal WebGPU-backend surface to unblock a cross-backend HDR bloom / post-process chain (3DForts #130). Closes the four gaps from the scoping issue.
What changed
Gap 1 — float/HDR textures.
WebGPU::wgpuCreateStorageImage2D(w, h, format)+ aStorageImage2Dtype allocate a runtime texture withSTORAGE_BINDING | TEXTURE_BINDING | COPY_SRC | COPY_DSTand a caller-chosenWebGPUTexelFormat(rgba16float / r32float / rgba8unorm), with noCompressedTextureAssetupload.Gap 2 — writable storage-texture binding. New
UICustomBindingKind::StorageTexture(kind 5) carries a texel format in the freedUICustomBinding::formatbyte and maps totexture_storage_2d<FMT, write>across all three binding paths (UI custom shader, RT pipeline, plain compute). Float textures already sample through the existingSampledTexturekind (sampleType: float, filterable per spec), so a pass can write anrgba16floatmip and a later pass can sample it.Gap 3 — pre-tonemap linear radiance (option 3a).
PipelineRTWebGPU::Init(..., hdrOutputFormat)makes the wavefront RESOLVE stage write the linear accumulator into a userrgba16floattexture (RTPass::outTexHandle) instead of the rgba8unorm canvas. The JS bridge swaps binding(6)'s WGSL declaration + bind-group-layout format and skips the ping-pong flip (canvas untouched). DefaultRGBA8Unormkeeps the canvas path byte-identical — existing RT examples are unaffected.Gap 4 — Vulkan symmetry (confirmed, no code). The native present path (
Window.cpp) recordswindow.passesgenerically, inserts aSHADER_WRITE → SHADER_READ|WRITEmemory barrier between passes, then transitions whatever swapchain image is bound toPRESENT_SRCand presents. It makes no assumption that the final RT/UI pass targets the swapchain, so RT → offscreenrgba16floatheap image → compositeRenderPass→ swapchain already works today.Validation
crafter-build test(native) — green (PushConstantRewrite).examples/HDRBloombuilds forwasm32-wasip1and runs in Firefox with WebGPU: RT → linearrgba16floatscene → threshold → blur (both over float storage targets) → composite (Reinhard tonemap + gamma) → canvas. No WGSL/validation errors; bright emitter cubes bloom, dim Lambert cubes stay sharp.examples/RTStressrebuilds + renders unchanged (backward-compat of the RT path and the_pad→formatrename).The threshold/blur passes dispatch from
onBeforeUpdateso each lands on its own queue submit — WebGPU only provides the storage-write → sampled-read barrier between submits (or between compute passes), never between dispatches within one pass. The composite runs in-frame as a UI custom shader so it owns the canvas ping-pong.Screenshots
Resolves #27