| // 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 == | |
| wgpu::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 |