| // Copyright 2019 The Dawn Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "dawn/native/d3d12/RenderPassBuilderD3D12.h" |
| |
| #include <algorithm> |
| |
| #include "dawn/native/Format.h" |
| #include "dawn/native/d3d12/CommandBufferD3D12.h" |
| #include "dawn/native/d3d12/Forward.h" |
| #include "dawn/native/d3d12/TextureD3D12.h" |
| #include "dawn/native/dawn_platform.h" |
| |
| namespace dawn::native::d3d12 { |
| |
| namespace { |
| D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE D3D12BeginningAccessType(wgpu::LoadOp loadOp) { |
| switch (loadOp) { |
| case wgpu::LoadOp::Clear: |
| return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR; |
| case wgpu::LoadOp::Load: |
| return D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; |
| case wgpu::LoadOp::Undefined: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| D3D12_RENDER_PASS_ENDING_ACCESS_TYPE D3D12EndingAccessType(wgpu::StoreOp storeOp) { |
| switch (storeOp) { |
| case wgpu::StoreOp::Discard: |
| return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_DISCARD; |
| case wgpu::StoreOp::Store: |
| return D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; |
| case wgpu::StoreOp::Undefined: |
| UNREACHABLE(); |
| break; |
| } |
| } |
| |
| D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS D3D12EndingAccessResolveParameters( |
| wgpu::StoreOp storeOp, |
| TextureView* resolveSource, |
| TextureView* resolveDestination) { |
| D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_PARAMETERS resolveParameters; |
| |
| resolveParameters.Format = resolveDestination->GetD3D12Format(); |
| resolveParameters.pSrcResource = ToBackend(resolveSource->GetTexture())->GetD3D12Resource(); |
| resolveParameters.pDstResource = |
| ToBackend(resolveDestination->GetTexture())->GetD3D12Resource(); |
| |
| // Clear or preserve the resolve source. |
| if (storeOp == wgpu::StoreOp::Discard) { |
| resolveParameters.PreserveResolveSource = false; |
| } else if (storeOp == wgpu::StoreOp::Store) { |
| resolveParameters.PreserveResolveSource = true; |
| } |
| |
| // RESOLVE_MODE_AVERAGE is only valid for non-integer formats. |
| ASSERT(resolveDestination->GetFormat().GetAspectInfo(Aspect::Color).baseType == |
| TextureComponentType::Float); |
| resolveParameters.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE; |
| |
| resolveParameters.SubresourceCount = 1; |
| |
| return resolveParameters; |
| } |
| |
| D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS |
| D3D12EndingAccessResolveSubresourceParameters(TextureView* resolveDestination) { |
| D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS subresourceParameters; |
| Texture* resolveDestinationTexture = ToBackend(resolveDestination->GetTexture()); |
| ASSERT(resolveDestinationTexture->GetFormat().aspects == Aspect::Color); |
| |
| subresourceParameters.DstX = 0; |
| subresourceParameters.DstY = 0; |
| subresourceParameters.SrcSubresource = 0; |
| subresourceParameters.DstSubresource = resolveDestinationTexture->GetSubresourceIndex( |
| resolveDestination->GetBaseMipLevel(), resolveDestination->GetBaseArrayLayer(), |
| Aspect::Color); |
| // Resolving a specified sub-rect is only valid on hardware that supports sample |
| // positions. This means even {0, 0, width, height} would be invalid if unsupported. To |
| // avoid this, we assume sub-rect resolves never work by setting them to all zeros or |
| // "empty" to resolve the entire region. |
| subresourceParameters.SrcRect = {0, 0, 0, 0}; |
| |
| return subresourceParameters; |
| } |
| } // anonymous namespace |
| |
| RenderPassBuilder::RenderPassBuilder(bool hasUAV) { |
| if (hasUAV) { |
| mRenderPassFlags = D3D12_RENDER_PASS_FLAG_ALLOW_UAV_WRITES; |
| } |
| } |
| |
| void RenderPassBuilder::SetRenderTargetView(ColorAttachmentIndex attachmentIndex, |
| D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor, |
| bool isNullRTV) { |
| mRenderTargetViews[attachmentIndex] = baseDescriptor; |
| mRenderPassRenderTargetDescriptors[attachmentIndex].cpuDescriptor = baseDescriptor; |
| if (!isNullRTV) { |
| mHighestColorAttachmentIndexPlusOne = std::max( |
| mHighestColorAttachmentIndexPlusOne, |
| ColorAttachmentIndex{static_cast<uint8_t>(static_cast<uint8_t>(attachmentIndex) + 1u)}); |
| } |
| } |
| |
| void RenderPassBuilder::SetDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE baseDescriptor) { |
| mRenderPassDepthStencilDesc.cpuDescriptor = baseDescriptor; |
| } |
| |
| ColorAttachmentIndex RenderPassBuilder::GetHighestColorAttachmentIndexPlusOne() const { |
| return mHighestColorAttachmentIndexPlusOne; |
| } |
| |
| bool RenderPassBuilder::HasDepthOrStencil() const { |
| return mHasDepthOrStencil; |
| } |
| |
| ityp::span<ColorAttachmentIndex, const D3D12_RENDER_PASS_RENDER_TARGET_DESC> |
| RenderPassBuilder::GetRenderPassRenderTargetDescriptors() const { |
| return {mRenderPassRenderTargetDescriptors.data(), mHighestColorAttachmentIndexPlusOne}; |
| } |
| |
| const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* RenderPassBuilder::GetRenderPassDepthStencilDescriptor() |
| const { |
| return &mRenderPassDepthStencilDesc; |
| } |
| |
| D3D12_RENDER_PASS_FLAGS RenderPassBuilder::GetRenderPassFlags() const { |
| return mRenderPassFlags; |
| } |
| |
| const D3D12_CPU_DESCRIPTOR_HANDLE* RenderPassBuilder::GetRenderTargetViews() const { |
| return mRenderTargetViews.data(); |
| } |
| |
| void RenderPassBuilder::SetRenderTargetBeginningAccess(ColorAttachmentIndex attachment, |
| wgpu::LoadOp loadOp, |
| dawn::native::Color clearColor, |
| DXGI_FORMAT format) { |
| mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Type = |
| D3D12BeginningAccessType(loadOp); |
| if (loadOp == wgpu::LoadOp::Clear) { |
| mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Clear.ClearValue.Color[0] = |
| clearColor.r; |
| mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Clear.ClearValue.Color[1] = |
| clearColor.g; |
| mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Clear.ClearValue.Color[2] = |
| clearColor.b; |
| mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Clear.ClearValue.Color[3] = |
| clearColor.a; |
| mRenderPassRenderTargetDescriptors[attachment].BeginningAccess.Clear.ClearValue.Format = |
| format; |
| } |
| } |
| |
| void RenderPassBuilder::SetRenderTargetEndingAccess(ColorAttachmentIndex attachment, |
| wgpu::StoreOp storeOp) { |
| mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Type = |
| D3D12EndingAccessType(storeOp); |
| } |
| |
| void RenderPassBuilder::SetRenderTargetEndingAccessResolve(ColorAttachmentIndex attachment, |
| wgpu::StoreOp storeOp, |
| TextureView* resolveSource, |
| TextureView* resolveDestination) { |
| mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Type = |
| D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; |
| mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Resolve = |
| D3D12EndingAccessResolveParameters(storeOp, resolveSource, resolveDestination); |
| |
| mSubresourceParams[attachment] = |
| D3D12EndingAccessResolveSubresourceParameters(resolveDestination); |
| |
| mRenderPassRenderTargetDescriptors[attachment].EndingAccess.Resolve.pSubresourceParameters = |
| &mSubresourceParams[attachment]; |
| } |
| |
| void RenderPassBuilder::SetDepthAccess(wgpu::LoadOp loadOp, |
| wgpu::StoreOp storeOp, |
| float clearDepth, |
| DXGI_FORMAT format) { |
| mHasDepthOrStencil = true; |
| mRenderPassDepthStencilDesc.DepthBeginningAccess.Type = D3D12BeginningAccessType(loadOp); |
| if (loadOp == wgpu::LoadOp::Clear) { |
| mRenderPassDepthStencilDesc.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = |
| clearDepth; |
| mRenderPassDepthStencilDesc.DepthBeginningAccess.Clear.ClearValue.Format = format; |
| } |
| mRenderPassDepthStencilDesc.DepthEndingAccess.Type = D3D12EndingAccessType(storeOp); |
| } |
| |
| void RenderPassBuilder::SetStencilAccess(wgpu::LoadOp loadOp, |
| wgpu::StoreOp storeOp, |
| uint8_t clearStencil, |
| DXGI_FORMAT format) { |
| mHasDepthOrStencil = true; |
| mRenderPassDepthStencilDesc.StencilBeginningAccess.Type = D3D12BeginningAccessType(loadOp); |
| if (loadOp == wgpu::LoadOp::Clear) { |
| mRenderPassDepthStencilDesc.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = |
| clearStencil; |
| mRenderPassDepthStencilDesc.StencilBeginningAccess.Clear.ClearValue.Format = format; |
| } |
| mRenderPassDepthStencilDesc.StencilEndingAccess.Type = D3D12EndingAccessType(storeOp); |
| } |
| |
| void RenderPassBuilder::SetDepthNoAccess() { |
| mRenderPassDepthStencilDesc.DepthBeginningAccess.Type = |
| D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; |
| mRenderPassDepthStencilDesc.DepthEndingAccess.Type = |
| D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; |
| } |
| |
| void RenderPassBuilder::SetDepthStencilNoAccess() { |
| SetDepthNoAccess(); |
| SetStencilNoAccess(); |
| } |
| |
| void RenderPassBuilder::SetStencilNoAccess() { |
| mRenderPassDepthStencilDesc.StencilBeginningAccess.Type = |
| D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; |
| mRenderPassDepthStencilDesc.StencilEndingAccess.Type = |
| D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; |
| } |
| |
| } // namespace dawn::native::d3d12 |