summaryrefslogtreecommitdiffstats
path: root/Graphics/GraphicsEngineD3D12
diff options
context:
space:
mode:
authorassiduous <assiduous@diligentgraphics.com>2020-08-08 21:05:23 +0000
committerassiduous <assiduous@diligentgraphics.com>2020-08-08 21:05:23 +0000
commit87d23dc98343ad4e4a2308826ed5f4f12125953e (patch)
tree2861f5ece258aacde52f8f37bce4702043e8f5b4 /Graphics/GraphicsEngineD3D12
parentMerge branch 'master' (diff)
downloadDiligentCore-87d23dc98343ad4e4a2308826ed5f4f12125953e.tar.gz
DiligentCore-87d23dc98343ad4e4a2308826ed5f4f12125953e.zip
Initial implementation of render passes in D3D12
Diffstat (limited to 'Graphics/GraphicsEngineD3D12')
-rw-r--r--Graphics/GraphicsEngineD3D12/include/CommandContext.hpp13
-rw-r--r--Graphics/GraphicsEngineD3D12/include/DeviceContextD3D12Impl.hpp7
-rw-r--r--Graphics/GraphicsEngineD3D12/src/CommandListManager.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/D3D12TypeConversions.cpp2
-rw-r--r--Graphics/GraphicsEngineD3D12/src/DeviceContextD3D12Impl.cpp208
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)