playcanvas / playcanvas/engine
Improve MRT support
Open
@mvaligursky is already working on this.
Since May 30, 2023.
area: graphics
enhancement
- Dominant language
- JavaScript
- Stars
- 16.8k
- Forks
- 2k
- Avg merge
- 4h 32m
- Merged PRs (30d)
- 222
Description
Issue for initial implementation of MRT: https://github.com/playcanvas/engine/issues/4230
Possible improvements:
- Per-attachment clear colors and clear flags on the render pass.
RenderPass#setClearColoraccepts an optional attachment index, and WebGL clears the color attachments individually using clearBufferfv, applying their own clear colors and clear flags. Previously a single gl.clear applied attachment 0's clear color to all attachments, and ignored the per-attachment clear flags. Done in #9142. - Per-attachment blend state and color write mask.
BlendState#setAttachmentgives an individual color attachment its own blend state and write mask - supported natively on WebGPU, and using the OES_draw_buffers_indexed extension on WebGL2, withGraphicsDevice#supportsIndependentBlendingreporting the support. Done in #9140. - Expand the API on the camera to specify the clear color per color attachment, and use those with MRT.
CameraComponent#setClearColor(index, color)/getClearColor(index)give each color attachment of the camera's render target its own clear color, applied by the forward render pass at the pass start. Attachment 0 isclearColor, and the other attachments clear to it until given their own. Done in #9333. - Attachment-aware mid-render-pass clears.
Renderer#clear->GraphicsDevice#clearis the single path for a clear which happens during a render pass (a camera whoserect/scissorRectdoes not cover the render target, or a layer withclearColorBufferwhich is not the first one rendering to the target), and it ignores the per-attachment clear colors of #9333: WebGL applies the attachment 0 color to every attachment viagl.clear(undefined for integer formats), and WebGPU fails outright -WebgpuClearRendererdraws with a single@location(0)output while every target has an all-channel write mask, which Dawn rejects (Color target has no corresponding fragment stage output but writeMask is not zero), so any mid-pass clear into an MRT target is a validation error today, independently of the new API. Plan: an additive per-attachmentcolorsoption plus an attachment enable mask onGraphicsDevice#clear(the existingcolorkeeps meaning all attachments), filled byRenderer#clearfromCamera#getClearColor(i). WebGL: lift theclearBufferfv/iv/uivloop ofstartRenderPassinto a helper shared withclear()- the scissor test is always enabled andclearBuffer*honours it, so the viewport-scoped semantics are preserved, and integer formats come for free. WebGPU: generate clear shader variants keyed by the attachment format classes (float / sint / uint) with a typed output at every location (Dawn requires an output wherever the write mask is non-zero, with a matching base type - a null target is not an option, as the pass still has the attachment), carry the colors as avec4ubit-pattern array in the uniform buffer (written through the Int32 storage view) with abitcastper output, and select the cleared attachments with a per-attachmentBlendState(setAttachmentNOBLEND / NOWRITE). The enable mask also letsRenderPassForwardclear only the attachment 0 in the scene-textures passes, removing the debug assert which currently forbids in-pass clears there. Verification: the multi-render-targets example with the texture camera'srectset to (0.1, 0.1, 0.8, 0.8) should show each attachment's own clear color in the border on both backends, with no WebGPU errors. - Expand the layer clear color flag to be per color attachment. Depends on the attachment-aware mid-pass clear above, which provides the per-attachment colors and the attachment enable mask on
GraphicsDevice#clear; on top of it this is the public API only: a per-attachment mask forLayer#clearColorBufferandCamera#clearColorBuffer, composed byRenderAction#setupClearsin place of the booleans onRenderAction/LayerRenderStep. - Clearing of integer format color attachments at the render pass start (clearBufferiv / clearBufferuiv on WebGL - WebGPU supports this natively via clearValue), which would also allow the Picker to use a uint32 format instead of encoding the id into RGBA8. Note the picker migration additionally needs uint fragment outputs for the pick shader variants. Mid-render-pass integer clears (layers) are excluded - on WebGPU the clear shader would need integer output variants, and nothing currently needs it. Done in #9143.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.