| # Dawn partial Load Resolve Texture |
| |
| The `dawn-partial-load-resolve-texture` feature is an extension to `dawn-load-resolve-texture`, which in addition allows to specify a rect sub-region of texture, where load and resolve will take effect only. The feature can't be available unless `dawn-load-resolve-texture` is available. |
| |
| Additional functionalities: |
| - Adds `wgpu::RenderPassDescriptorResolveRect` as chained struct for `wgpu::RenderPassDescriptor`. It defines an expanding rect of {`colorOffsetX`, `colorOffsetY`, `width`, `height`} and a resolving rect {`resolveOffsetX`, `resolveOffsetY`, `width`, `height`} to indicate that expanding and resolving are only performed partially on the texels within this rect region of texture. The texels outside of the rect are not impacted. |
| |
| Example Usage 1, ExpandResolveTexture and RenderPassDescriptorResolveRect: |
| |
| When the load operation is set to wgpu::LoadOp::ExpandResolveTexture: |
| 1. Expand the resolve texture's region {resolveOffsetX, resolveOffsetY, width, height} into the MSAA texture's region {colorOffsetX, colorOffsetY, width, height}. |
| 2. Optional user draws to the MSAA texture. |
| 3. Resolve the MSAA texture's region {colorOffsetX, colorOffsetY, width, height} into the resolve texture's region {resolveOffsetX, resolveOffsetY, width, height}. |
| |
| ``` |
| // Create MSAA texture |
| wgpu::TextureDescriptor desc = ...; |
| desc.usage = wgpu::TextureUsage::RenderAttachment; |
| desc.sampleCount = 4; |
| |
| auto msaaTexture = device.CreateTexture(&desc); |
| |
| // Create resolve texture with TextureBinding usage. |
| wgpu::TextureDescriptor desc = ...; |
| desc.usage = wgpu::TextureUsage::RenderAttachment | wgpu::TextureUsage::TextureBinding; |
| |
| auto resolveTexture = device.CreateTexture(&desc); |
| |
| // Create a render pass which will discard the MSAA texture. |
| wgpu::RenderPassDescriptor renderPassDesc = ...; |
| renderPassDesc.colorAttachments[0].view = msaaTexture.CreateView(); |
| renderPassDesc.colorAttachments[0].resolveTarget |
| = resolveTexture.CreateView(); |
| renderPassDesc.colorAttachments[0].storeOp |
| = wgpu::StoreOp::Discard; |
| |
| auto renderPassEncoder = encoder.BeginRenderPass(&renderPassDesc); |
| renderPassEncoder.Draw(3); |
| renderPassEncoder.End(); |
| |
| // Create a render pipeline with wgpu::ColorTargetStateExpandResolveTextureDawn. |
| wgpu::ColorTargetStateExpandResolveTextureDawn pipelineExpandResolveTextureState; |
| pipelineExpandResolveTextureState.enabled = true; |
| |
| wgpu::RenderPipelineDescriptor pipelineDesc = ...; |
| pipelineDesc.multisample.count = 4; |
| |
| pipelineDesc->fragment->targets[0].nextInChain = &pipelineExpandResolveTextureState; |
| |
| auto pipeline = device.CreateRenderPipeline(&pipelineDesc); |
| |
| // Create another render pass with "ExpandResolveTexture" LoadOp. |
| // Even though we discard the previous content of the MSAA texture, |
| // the old pixels of the resolve texture will be reserved across |
| // render passes. |
| wgpu::RenderPassDescriptor renderPassDesc2 = ...; |
| renderPassDesc2.colorAttachments[0].view = msaaTexture.CreateView(); |
| renderPassDesc2.colorAttachments[0].resolveTarget |
| = resolveTexture.CreateView(); |
| renderPassDesc2.colorAttachments[0].loadOp |
| = wgpu::LoadOp::ExpandResolveTexture; |
| |
| // If there is no need to expand and resolve the whole texture, |
| // RenderPassDescriptorResolveRect can be used to specify a |
| // subregion of texture to be updated only. |
| wgpu::RenderPassDescriptorResolveRect rect{}; |
| rect.colorOffsetX = rect.colorOffsetY = 1; |
| rect.resolveOffsetX = rect.resolveOffsetY = 1; |
| rect.width = rect.height = 32; |
| renderPassDesc2.nextInChain = ▭ |
| |
| auto renderPassEncoder2 = encoder.BeginRenderPass(&renderPassDesc2); |
| renderPassEncoder2.SetPipeline(pipeline); |
| renderPassEncoder2.Draw(3); |
| renderPassEncoder2.End(); |
| ``` |
| |
| Example Usage 2, Clear and RenderPassDescriptorResolveRect: |
| |
| Similar to the above example, but using wgpu::LoadOp::Clear: |
| 1. Clear the entire MSAA texture using the clearValue. |
| 2. Optional user draws to the MSAA texture. |
| 3. Resolve the MSAA texture's region {colorOffsetX, colorOffsetY, width, height} into the resolve texture's region {resolveOffsetX, resolveOffsetY, width, height}. |
| |
| ``` |
| // Create another render pass with "Clear" LoadOp. |
| wgpu::RenderPassDescriptor renderPassDesc2 = ...; |
| renderPassDesc2.colorAttachments[0].view = msaaTexture.CreateView(); |
| renderPassDesc2.colorAttachments[0].resolveTarget |
| = resolveTexture.CreateView(); |
| renderPassDesc2.colorAttachments[0].loadOp = wgpu::LoadOp::Clear; |
| renderPassDesc2.colorAttachments[0].clearValue = clearValue; |
| |
| wgpu::RenderPassDescriptorResolveRect rect{}; |
| rect.colorOffsetX = rect.colorOffsetY = 1; |
| rect.resolveOffsetX = rect.resolveOffsetY = 1; |
| rect.width = rect.height = 32; |
| renderPassDesc2.nextInChain = ▭ |
| ``` |
| |
| Example Usage 3, Load and RenderPassDescriptorResolveRect: |
| |
| Similar to the first example, but using wgpu::LoadOp::Load: |
| 1. Load the MSAA texture. |
| 2. Optional user draws to the MSAA texture. |
| 3. Resolve the MSAA texture's region {colorOffsetX, colorOffsetY, width, height} into the resolve texture's region {resolveOffsetX, resolveOffsetY, width, height}. |
| |
| ``` |
| // Create another render pass with "Load" LoadOp. |
| wgpu::RenderPassDescriptor renderPassDesc2 = ...; |
| renderPassDesc2.colorAttachments[0].view = msaaTexture.CreateView(); |
| renderPassDesc2.colorAttachments[0].resolveTarget |
| = resolveTexture.CreateView(); |
| renderPassDesc2.colorAttachments[0].loadOp = wgpu::LoadOp::Load; |
| |
| wgpu::RenderPassDescriptorResolveRect rect{}; |
| rect.colorOffsetX = rect.colorOffsetY = 1; |
| rect.resolveOffsetX = rect.resolveOffsetY = 1; |
| rect.width = rect.height = 32; |
| renderPassDesc2.nextInChain = ▭ |
| ``` |
| |
| Notes: |
| - In case that the target size of a render pass is very large, the cost of using `wgpu::LoadOp::ExpandResolveTexture` can be rather expensive, as it always assumes full-size expand and resolve. More commonly in reality, each frame we only need to re-draw a small damage region, of which UI frameworks usually have the knowledge, instead of the full window, or webpage. This feature aims to eliminate the waste by doing partial expand and resolve with the hint of `wgpu::RenderPassDescriptorResolveRect`, the actual damage region. |
| - This feature is also useful to some scenarios where the applications want to use a smaller MSAA texture to render to a larger single sampled texture. |
| - If the color attachment's loadOp is Load or Clear, then RenderPassDescriptorResolveRect will be ignored in the loading step. It will still be used in the resolving step to do a partial resolve. |
| - The feature currently is only available on dawn d3d11 backend. Internally, both expand and resolve are implemented with a dedicated `wgpu::RenderPipeline`. `wgpu::RenderPassEncoder::APISetScissorRect` is used to set the scissor rect to `wgpu::RenderPassDescriptorResolveRect`, when using the pipeline. The major difference is that expand lives in the original render pass, while resolve requires a separate one. |