diff options
| author | assiduous <assiduous@diligentgraphics.com> | 2020-08-08 21:05:23 +0000 |
|---|---|---|
| committer | assiduous <assiduous@diligentgraphics.com> | 2020-08-08 21:05:23 +0000 |
| commit | 87d23dc98343ad4e4a2308826ed5f4f12125953e (patch) | |
| tree | 2861f5ece258aacde52f8f37bce4702043e8f5b4 /Graphics/GraphicsEngineD3D12 | |
| parent | Merge branch 'master' (diff) | |
| download | DiligentCore-87d23dc98343ad4e4a2308826ed5f4f12125953e.tar.gz DiligentCore-87d23dc98343ad4e4a2308826ed5f4f12125953e.zip | |
Initial implementation of render passes in D3D12
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
5 files changed, 227 insertions, 5 deletions
diff --git a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp index a8211db6..2ef40103 100644 --- a/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp +++ b/Graphics/GraphicsEngineD3D12/include/CommandContext.hpp @@ -339,6 +339,19 @@ public: FlushResourceBarriers(); m_pCommandList->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); } + + void BeginRenderPass(UINT NumRenderTargets, + const D3D12_RENDER_PASS_RENDER_TARGET_DESC* pRenderTargets, + const D3D12_RENDER_PASS_DEPTH_STENCIL_DESC* pDepthStencil, + D3D12_RENDER_PASS_FLAGS Flags) + { + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->BeginRenderPass(NumRenderTargets, pRenderTargets, pDepthStencil, Flags); + } + + void EndRenderPass() + { + static_cast<ID3D12GraphicsCommandList4*>(m_pCommandList.p)->EndRenderPass(); + } }; class ComputeContext : public CommandContext diff --git a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp index eea40064..0aae73af 100644 --- a/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp +++ b/Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp @@ -31,6 +31,7 @@ /// Declaration of Diligent::DeviceContextD3D12Impl class #include <unordered_map> +#include <vector> #include "DeviceContextD3D12.h" #include "DeviceContextNextGenBase.hpp" @@ -318,6 +319,8 @@ private: void CommitRenderTargets(RESOURCE_STATE_TRANSITION_MODE StateTransitionMode); void CommitViewports(); void CommitScissorRects(class GraphicsContext& GraphCtx, bool ScissorEnable); + void TransitionSubpassAttachments(); + void CommitSubpassRenderTargets(); void Flush(bool RequestNewCmdCtx); __forceinline void RequestCommandContext(RenderDeviceD3D12Impl* pDeviceD3D12Impl); @@ -425,6 +428,10 @@ private: std::unordered_map<MappedTextureKey, TextureUploadSpace, MappedTextureKey::Hasher> m_MappedTextures; Int32 m_ActiveQueriesCounter = 0; + + std::vector<OptimizedClearValue> m_AttachmentClearValues; + + std::vector<D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS> m_AttachmentResolveInfo; }; } // namespace Diligent diff --git a/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp b/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp index f1099ac7..c4d6e1b5 100644 --- a/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp +++ b/Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp @@ -50,7 +50,7 @@ void CommandListManager::CreateNewCommandList(ID3D12GraphicsCommandList** List, { RequestAllocator(Allocator); auto* pd3d12Device = m_DeviceD3D12Impl.GetD3D12Device(); - auto hr = pd3d12Device->CreateCommandList(1, D3D12_COMMAND_LIST_TYPE_DIRECT, *Allocator, nullptr, __uuidof(*List), reinterpret_cast<void**>(List)); + auto hr = pd3d12Device->CreateCommandList(1, D3D12_COMMAND_LIST_TYPE_DIRECT, *Allocator, nullptr, __uuidof(ID3D12GraphicsCommandList4), reinterpret_cast<void**>(List)); VERIFY(SUCCEEDED(hr), "Failed to create command list"); (*List)->SetName(L"CommandList"); } diff --git a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp index 04304938..1759663f 100644 --- a/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp +++ b/Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp @@ -349,7 +349,7 @@ static D3D12_RESOURCE_STATES ResourceStateFlagToD3D12ResourceState(RESOURCE_STAT case RESOURCE_STATE_COPY_SOURCE: return D3D12_RESOURCE_STATE_COPY_SOURCE; case RESOURCE_STATE_RESOLVE_DEST: return D3D12_RESOURCE_STATE_RESOLVE_DEST; case RESOURCE_STATE_RESOLVE_SOURCE: return D3D12_RESOURCE_STATE_RESOLVE_SOURCE; - case RESOURCE_STATE_INPUT_ATTACHMENT: UNSUPPORTED("Input attachments are not currently supported in D3D12"); return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; + case RESOURCE_STATE_INPUT_ATTACHMENT: return D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; case RESOURCE_STATE_PRESENT: return D3D12_RESOURCE_STATE_PRESENT; // clang-format on default: diff --git a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp index 85d0154b..2c8eb45e 100644 --- a/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp +++ b/Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp @@ -617,6 +617,12 @@ void DeviceContextD3D12Impl::ClearDepthStencil(ITextureView* pV Uint8 Stencil, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Direct3D12 does not allow depth-stencil clears inside a render pass"); + return; + } + if (!TDeviceContextBase::ClearDepthStencil(pView)) return; @@ -639,6 +645,12 @@ void DeviceContextD3D12Impl::ClearDepthStencil(ITextureView* pV void DeviceContextD3D12Impl::ClearRenderTarget(ITextureView* pView, const float* RGBA, RESOURCE_STATE_TRANSITION_MODE StateTransitionMode) { + if (m_pActiveRenderPass != nullptr) + { + LOG_ERROR_MESSAGE("Direct3D12 does not allow render target clears inside a render pass"); + return; + } + if (!TDeviceContextBase::ClearRenderTarget(pView)) return; @@ -992,22 +1004,212 @@ void DeviceContextD3D12Impl::SetRenderTargets(Uint32 Num } } +void DeviceContextD3D12Impl::TransitionSubpassAttachments() +{ + VERIFY_EXPR(m_pActiveRenderPass); + //const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + VERIFY_EXPR(m_pBoundFramebuffer); + //const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); +} + +void DeviceContextD3D12Impl::CommitSubpassRenderTargets() +{ + VERIFY_EXPR(m_pActiveRenderPass); + const auto& RPDesc = m_pActiveRenderPass->GetDesc(); + VERIFY_EXPR(m_pBoundFramebuffer); + const auto& FBDesc = m_pBoundFramebuffer->GetDesc(); + VERIFY_EXPR(m_SubpassIndex < RPDesc.SubpassCount); + const auto& Subpass = RPDesc.pSubpasses[m_SubpassIndex]; + VERIFY(Subpass.RenderTargetAttachmentCount == m_NumBoundRenderTargets, + "The number of currently bound render targets (", m_NumBoundRenderTargets, + ") is not consistent with the number of redner target attachments (", Subpass.RenderTargetAttachmentCount, + ") in current subpass"); + + D3D12_RENDER_PASS_RENDER_TARGET_DESC RenderPassRTs[MAX_RENDER_TARGETS]; + for (Uint32 rt = 0; rt < m_NumBoundRenderTargets; ++rt) + { + const auto& RTRef = Subpass.pRenderTargetAttachments[rt]; + if (RTRef.AttachmentIndex != ATTACHMENT_UNUSED) + { + TextureViewD3D12Impl* pRTV = m_pBoundRenderTargets[rt]; + VERIFY(pRTV == FBDesc.ppAttachments[RTRef.AttachmentIndex], + "Render target bound in the device context at slot ", rt, " is not consistent with the corresponding framebuffer attachment"); + const auto FirstLastUse = m_pActiveRenderPass->GetAttachmentFirstLastUse(RTRef.AttachmentIndex); + const auto& RTAttachmentDesc = RPDesc.pAttachments[RTRef.AttachmentIndex]; + + auto& RPRT = RenderPassRTs[rt]; + RPRT = D3D12_RENDER_PASS_RENDER_TARGET_DESC{}; + + RPRT.cpuDescriptor = pRTV->GetCPUDescriptorHandle(); + if (FirstLastUse.first == m_SubpassIndex) + { + // This is the first use of this attachment - use LoadOp + RPRT.BeginningAccess.Type = AttachmentLoadOpToD3D12BeginningAccessType(RTAttachmentDesc.LoadOp); + } + else + { + // Preserve the attachment contents + RPRT.BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE; + } + + if (RPRT.BeginningAccess.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) + { + RPRT.BeginningAccess.Clear.ClearValue.Format = TexFormatToDXGI_Format(RTAttachmentDesc.Format); + + const auto ClearColor = m_AttachmentClearValues[RTRef.AttachmentIndex].Color; + for (Uint32 i = 0; i < 4; ++i) + RPRT.BeginningAccess.Clear.ClearValue.Color[i] = ClearColor[i]; + } + + if (FirstLastUse.second == m_SubpassIndex) + { + // This is the last use of this attachment - use StoreOp or resolve parameters + if (Subpass.pResolveAttachments != nullptr && Subpass.pResolveAttachments[rt].AttachmentIndex != ATTACHMENT_UNUSED) + { + VERIFY_EXPR(Subpass.pResolveAttachments[rt].AttachmentIndex < RPDesc.AttachmentCount); + auto* pDstView = FBDesc.ppAttachments[Subpass.pResolveAttachments[rt].AttachmentIndex]; + auto* pSrcTexD3D12 = pRTV->GetTexture<TextureD3D12Impl>(); + auto* pDstTexD3D12 = ValidatedCast<TextureViewD3D12Impl>(pDstView)->GetTexture<TextureD3D12Impl>(); + + const auto& SrcRTVDesc = pRTV->GetDesc(); + const auto& DstViewDesc = pDstView->GetDesc(); + const auto& SrcTexDesc = pSrcTexD3D12->GetDesc(); + const auto& DstTexDesc = pDstTexD3D12->GetDesc(); + + VERIFY_EXPR(SrcRTVDesc.NumArraySlices == 1); + Uint32 SubresourceCount = SrcRTVDesc.NumArraySlices; + m_AttachmentResolveInfo.resize(SubresourceCount); + const auto MipProps = GetMipLevelProperties(SrcTexDesc, SrcRTVDesc.MostDetailedMip); + for (Uint32 slice = 0; slice < SrcRTVDesc.NumArraySlices; ++slice) + { + auto& ARI = m_AttachmentResolveInfo[slice]; + + ARI.SrcSubresource = D3D12CalcSubresource(SrcRTVDesc.MostDetailedMip, SrcRTVDesc.FirstArraySlice + slice, 0, SrcTexDesc.MipLevels, SrcTexDesc.ArraySize); + ARI.DstSubresource = D3D12CalcSubresource(DstViewDesc.MostDetailedMip, DstViewDesc.FirstArraySlice + slice, 0, DstTexDesc.MipLevels, DstTexDesc.ArraySize); + ARI.DstX = 0; + ARI.DstY = 0; + ARI.SrcRect.left = 0; + ARI.SrcRect.top = 0; + ARI.SrcRect.right = MipProps.LogicalWidth; + ARI.SrcRect.bottom = MipProps.LogicalHeight; + } + + RPRT.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE; + auto& ResolveInfo = RPRT.EndingAccess.Resolve; + ResolveInfo.pSrcResource = pSrcTexD3D12->GetD3D12Resource(); + ResolveInfo.pDstResource = pDstTexD3D12->GetD3D12Resource(); + ResolveInfo.SubresourceCount = SubresourceCount; + // This pointer is directly referenced by the command list, and the memory for this array + // must remain alive and intact until EndRenderPass is called. + ResolveInfo.pSubresourceParameters = m_AttachmentResolveInfo.data(); + ResolveInfo.Format = TexFormatToDXGI_Format(RTAttachmentDesc.Format); + ResolveInfo.ResolveMode = D3D12_RESOLVE_MODE_AVERAGE; + ResolveInfo.PreserveResolveSource = RTAttachmentDesc.StoreOp == ATTACHMENT_STORE_OP_STORE; + } + else + { + RPRT.EndingAccess.Type = AttachmentStoreOpToD3D12EndingAccessType(RTAttachmentDesc.StoreOp); + } + } + else + { + // The attachment will be used in subsequent subpasses - preserve its contents + RPRT.EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + } + } + else + { + // Attachment is not used + RenderPassRTs[rt].BeginningAccess.Type = D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS; + RenderPassRTs[rt].EndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS; + continue; + } + } + + D3D12_RENDER_PASS_DEPTH_STENCIL_DESC RenderPassDS; + if (m_pBoundDepthStencil) + { + RenderPassDS = D3D12_RENDER_PASS_DEPTH_STENCIL_DESC{}; + + const auto& DSAttachmentRef = *Subpass.pDepthStencilAttachment; + VERIFY_EXPR(Subpass.pDepthStencilAttachment != nullptr && DSAttachmentRef.AttachmentIndex != ATTACHMENT_UNUSED); + VERIFY(m_pBoundDepthStencil == FBDesc.ppAttachments[DSAttachmentRef.AttachmentIndex], + "Depth-stencil bufer in the device context is inconsistent with the framebuffer"); + const auto FirstLastUse = m_pActiveRenderPass->GetAttachmentFirstLastUse(DSAttachmentRef.AttachmentIndex); + const auto& DSAttachmentDesc = RPDesc.pAttachments[DSAttachmentRef.AttachmentIndex]; + + RenderPassDS.cpuDescriptor = m_pBoundDepthStencil->GetCPUDescriptorHandle(); + if (FirstLastUse.first == m_SubpassIndex) + { + RenderPassDS.DepthBeginningAccess.Type = AttachmentLoadOpToD3D12BeginningAccessType(DSAttachmentDesc.LoadOp); + RenderPassDS.StencilBeginningAccess.Type = AttachmentLoadOpToD3D12BeginningAccessType(DSAttachmentDesc.StencilLoadOp); + } + + if (RenderPassDS.DepthBeginningAccess.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) + { + RenderPassDS.DepthBeginningAccess.Clear.ClearValue.Format = TexFormatToDXGI_Format(DSAttachmentDesc.Format); + RenderPassDS.DepthBeginningAccess.Clear.ClearValue.DepthStencil.Depth = + m_AttachmentClearValues[DSAttachmentRef.AttachmentIndex].DepthStencil.Depth; + } + + if (RenderPassDS.StencilBeginningAccess.Type == D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_CLEAR) + { + RenderPassDS.StencilBeginningAccess.Clear.ClearValue.Format = TexFormatToDXGI_Format(DSAttachmentDesc.Format); + RenderPassDS.StencilBeginningAccess.Clear.ClearValue.DepthStencil.Stencil = + m_AttachmentClearValues[DSAttachmentRef.AttachmentIndex].DepthStencil.Stencil; + } + + if (FirstLastUse.second == m_SubpassIndex) + { + RenderPassDS.DepthEndingAccess.Type = AttachmentStoreOpToD3D12EndingAccessType(DSAttachmentDesc.StoreOp); + RenderPassDS.StencilEndingAccess.Type = AttachmentStoreOpToD3D12EndingAccessType(DSAttachmentDesc.StencilStoreOp); + } + else + { + RenderPassDS.DepthEndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + RenderPassDS.StencilEndingAccess.Type = D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE; + } + } + + auto& CmdCtx = GetCmdContext(); + CmdCtx.AsGraphicsContext().BeginRenderPass( + Subpass.RenderTargetAttachmentCount, + RenderPassRTs, + m_pBoundDepthStencil ? &RenderPassDS : nullptr, + D3D12_RENDER_PASS_FLAG_NONE); + + // Set the viewport to match the framebuffer size + SetViewports(1, nullptr, 0, 0); +} + void DeviceContextD3D12Impl::BeginRenderPass(const BeginRenderPassAttribs& Attribs) { TDeviceContextBase::BeginRenderPass(Attribs); - UNEXPECTED("Method not implemented"); + + m_AttachmentClearValues.resize(Attribs.ClearValueCount); + for (Uint32 i = 0; i < Attribs.ClearValueCount; ++i) + m_AttachmentClearValues[i] = Attribs.pClearValues[i]; + + TransitionSubpassAttachments(); + CommitSubpassRenderTargets(); } void DeviceContextD3D12Impl::NextSubpass() { + auto& CmdCtx = GetCmdContext(); + CmdCtx.AsGraphicsContext().EndRenderPass(); TDeviceContextBase::NextSubpass(); - UNEXPECTED("Method not implemented"); + TransitionSubpassAttachments(); + CommitSubpassRenderTargets(); + //auto& CmdCtx = GetCmdContext(); } void DeviceContextD3D12Impl::EndRenderPass(bool UpdateResourceStates) { + auto& CmdCtx = GetCmdContext(); + CmdCtx.AsGraphicsContext().EndRenderPass(); TDeviceContextBase::EndRenderPass(UpdateResourceStates); - UNEXPECTED("Method not implemented"); + TransitionSubpassAttachments(); } D3D12DynamicAllocation DeviceContextD3D12Impl::AllocateDynamicSpace(size_t NumBytes, size_t Alignment) |
