Allow sampling multisampled render targets on WebGPU - #9167
Conversation
There was a problem hiding this comment.
Pull request overview
Adds WebGPU support for shader access to multisampled render-target color attachments for custom MSAA resolves.
Changes:
- Exposes bindable multisampled color textures from render targets.
- Adds multisampled texture bind-group and WGSL reflection support.
- Preserves MSAA samples and adds unit coverage.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/platform/graphics/bind-group-format.js |
Adds multisampled texture formats. |
src/platform/graphics/null/null-render-target.js |
Stubs multisampled color textures. |
src/platform/graphics/render-pass.js |
Stores bindable MSAA samples. |
src/platform/graphics/render-target.js |
Adds the render-target API. |
src/platform/graphics/texture.js |
Tracks texture sample counts. |
src/platform/graphics/webgpu/webgpu-bind-group-format.js |
Emits multisampled layouts. |
src/platform/graphics/webgpu/webgpu-render-target.js |
Creates bindable MSAA attachments. |
src/platform/graphics/webgpu/webgpu-shader-processor-wgsl.js |
Reflects multisampled WGSL textures. |
src/platform/graphics/webgpu/webgpu-texture.js |
Wraps render-target-owned textures. |
test/platform/graphics/bind-group-format.test.mjs |
Tests format behavior. |
test/platform/graphics/render-pass.test.mjs |
Tests MSAA storage. |
test/platform/graphics/render-target.test.mjs |
Tests the public API. |
test/platform/graphics/webgpu/webgpu-bind-group-format.test.mjs |
Tests WebGPU layouts. |
test/platform/graphics/webgpu/webgpu-render-target.test.mjs |
Tests texture usage flags. |
test/platform/graphics/webgpu/webgpu-shader-processor-wgsl-compute.test.mjs |
Tests WGSL reflection. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (multisampled) { | ||
| Debug.assert(textureDimension === TEXTUREDIMENSION_2D, `Multisampled texture binding '${name}' requires TEXTUREDIMENSION_2D.`); | ||
| Debug.assert(!hasSampler, `Multisampled texture binding '${name}' cannot have a sampler.`); | ||
| } |
There was a problem hiding this comment.
Agreed — this assert contradicted the documented API.
hasSampler defaults to true, so the natural call new BindTextureFormat(name, visibility, dim, type, undefined, undefined, true) (or just the 7th argument) hit Debug.assert(!hasSampler) in debug builds even though we already coerce this.hasSampler = false.
Removed the hasSampler assert. Coercion stays (multisampled still forces hasSampler = false and samplerName = null). The TEXTUREDIMENSION_2D assert stays — that one is a real WebGPU invariant, not a default-parameter clash.
Shader reflection already strips a following sampler (hasSampler && !resource.multisampled) and asserts at the WGSL source if someone declares sampler after a multisampled texture.
| this._storage = options.storage ?? false; | ||
| this._samples = options.samples ?? 1; | ||
| this._importedGpuTexture = options._importedGpuTexture ?? null; |
There was a problem hiding this comment.
Agreed — Texture.samples is not a public way to allocate an MSAA texture, and we should not pretend it is.
WebgpuTexture.create still hardcodes sampleCount: 1 for a normal allocation. The sample count is only meaningful on the wrapper around the render target’s existing MSAA GPUTexture.
What we did:
- Dropped
options.samplesfrom the publicTextureconstructor JSDoc and from API Changes. - Stopped reading
options.samplesentirely.new Texture(device, { samples: 4 })now stays at sample count 1, matching the GPU texture that is actually created. - The wrapper uses an internal
_samplesoption together with_importedGpuTexture(both@ignore).Texture#samplesstays@ignoresogetMultisampledColorBuffer()can still describe the imported GPU texture to WebGPU (sampleCounton the adopted descriptor).
We are not adding public multisampled Texture allocation in this PR.
Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
Allows a multisampled render target to be sampled in a user shader on
WebGPU (
textureLoadontexture_multisampled_2d/texture_depth_multisampled_2d), so applications can implement customMSAA resolves the hardware box resolve cannot express.
Fixes #9059
Changes:
be bound through
BindGroupFormat.bindMultisampledis set,so a later pass can
textureLoadthe samples.texture_depth_multisampled_2dand emitsthe correct multisampled type.
API Changes:
RenderTargetoptionbindMultisampled(boolean, defaultfalse).WebGPU,
samples > 1. Ignored iftransientColoractually applies.RenderTarget#bindMultisampled— resolved flag.RenderTarget#getMultisampledColorBuffer(index = 0)— bind thisTexture, notcolorBuffer. Owned by the render target.The public bindable texture is the MSAA color attachment.
Auto-allocated MS depth already has
TEXTURE_BINDING, andtexture_depth_multisampled_2dreflects; a publicgetMultisampledDepthBuffer()is a follow-up.BindTextureFormat7th parametermultisampled(defaultfalse).Forces no sampler;
SAMPLETYPE_FLOATbecomes unfilterable-float.No example added.
Checklist