From 7fa26f1c87a0047affc102e15448e1c212382f08 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 15 Jun 2018 20:49:24 +0200 Subject: [PATCH] [d3d11] Implement render pass spilling for UAV rendering Spilling the render pass should make shader storage buffer/image writes visible due to how external subpass dependencies are defined. For UAV rendering, we need to do this when changing the UAVs, even if the render targets themselves do not change. --- src/d3d11/d3d11_context.cpp | 59 +++++++++++++++++++++------------ src/d3d11/d3d11_context.h | 8 ++++- src/d3d11/d3d11_context_state.h | 2 ++ src/dxgi/dxgi_presenter.cpp | 2 +- src/dxvk/dxvk_context.cpp | 7 +++- src/dxvk/dxvk_context.h | 9 +++-- src/dxvk/dxvk_renderpass.cpp | 4 +++ src/dxvk/hud/dxvk_hud.cpp | 2 +- 8 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index bc9fb54a1..a7a8370a6 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -2069,20 +2069,8 @@ namespace dxvk { UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView) { - // Native D3D11 does not change the render targets if - // the parameters passed to this method are invalid. - if (!ValidateRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView)) - return; - - for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { - m_state.om.renderTargetViews.at(i) = i < NumViews - ? static_cast(ppRenderTargetViews[i]) - : nullptr; - } - - m_state.om.depthStencilView = static_cast(pDepthStencilView); - - BindFramebuffer(); + SetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView); + BindFramebuffer(std::exchange(m_state.om.isUavRendering, false)); } @@ -2094,14 +2082,17 @@ namespace dxvk { UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, const UINT* pUAVInitialCounts) { + bool spillOnBind = m_state.om.isUavRendering; + if (NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) - OMSetRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView); + SetRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView); if (NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) { - static std::atomic s_warningShown = { false }; + // Check whether there actually are any UAVs bound + m_state.om.isUavRendering = false; - if (NumUAVs != 0 && !s_warningShown.exchange(true)) - Logger::warn("D3D11: UAV rendering not properly implemented yet"); + for (uint32_t i = 0; i < NumUAVs && !m_state.om.isUavRendering; i++) + m_state.om.isUavRendering = ppUnorderedAccessViews[i] != nullptr; // UAVs are made available to all shader stages in // the graphics pipeline even though this code may @@ -2118,6 +2109,8 @@ namespace dxvk { ppUnorderedAccessViews, pUAVInitialCounts); } } + + BindFramebuffer(spillOnBind); } @@ -2554,7 +2547,7 @@ namespace dxvk { } - void D3D11DeviceContext::BindFramebuffer() { + void D3D11DeviceContext::BindFramebuffer(BOOL Spill) { // NOTE According to the Microsoft docs, we are supposed to // unbind overlapping shader resource views. Since this comes // with a large performance penalty we'll ignore this until an @@ -2579,8 +2572,11 @@ namespace dxvk { } // Create and bind the framebuffer object to the context - EmitCs([cAttachments = std::move(attachments)] (DxvkContext* ctx) { - ctx->bindRenderTargets(cAttachments); + EmitCs([ + cAttachments = std::move(attachments), + cSpill = Spill + ] (DxvkContext* ctx) { + ctx->bindRenderTargets(cAttachments, cSpill); }); } @@ -2786,6 +2782,25 @@ namespace dxvk { } } } + + + void D3D11DeviceContext::SetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView) { + // Native D3D11 does not change the render targets if + // the parameters passed to this method are invalid. + if (!ValidateRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView)) + return; + + for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { + m_state.om.renderTargetViews.at(i) = i < NumViews + ? static_cast(ppRenderTargetViews[i]) + : nullptr; + } + + m_state.om.depthStencilView = static_cast(pDepthStencilView); + } void D3D11DeviceContext::InitUnorderedAccessViewCounters( @@ -2835,7 +2850,7 @@ namespace dxvk { void D3D11DeviceContext::RestoreState() { - BindFramebuffer(); + BindFramebuffer(m_state.om.isUavRendering); BindShader(m_state.vs.shader.ptr(), VK_SHADER_STAGE_VERTEX_BIT); BindShader(m_state.hs.shader.ptr(), VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT); diff --git a/src/d3d11/d3d11_context.h b/src/d3d11/d3d11_context.h index 1d073095b..576a152a2 100644 --- a/src/d3d11/d3d11_context.h +++ b/src/d3d11/d3d11_context.h @@ -667,7 +667,8 @@ namespace dxvk { void ApplyViewportState(); - void BindFramebuffer(); + void BindFramebuffer( + BOOL Spill); template void BindShader( @@ -739,6 +740,11 @@ namespace dxvk { UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews); + void SetRenderTargets( + UINT NumViews, + ID3D11RenderTargetView* const* ppRenderTargetViews, + ID3D11DepthStencilView* pDepthStencilView); + void InitUnorderedAccessViewCounters( UINT NumUAVs, ID3D11UnorderedAccessView* const* ppUnorderedAccessViews, diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h index 1a385a0ac..010988055 100644 --- a/src/d3d11/d3d11_context_state.h +++ b/src/d3d11/d3d11_context_state.h @@ -120,6 +120,8 @@ namespace dxvk { FLOAT blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; UINT sampleMask = 0xFFFFFFFFu; UINT stencilRef = 0u; + + BOOL isUavRendering = FALSE; }; diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index e4bb397f8..b708119d1 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -180,7 +180,7 @@ namespace dxvk { DxvkRenderTargets renderTargets; renderTargets.color[0].view = swapImage; renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - m_context->bindRenderTargets(renderTargets); + m_context->bindRenderTargets(renderTargets, false); VkViewport viewport; viewport.x = 0.0f; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 521eb507c..d2457b4d3 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -87,7 +87,9 @@ namespace dxvk { } - void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) { + void DxvkContext::bindRenderTargets( + const DxvkRenderTargets& targets, + bool spill) { m_state.om.renderTargets = targets; // If necessary, perform clears on the active render targets @@ -108,6 +110,9 @@ namespace dxvk { // the same render targets are bound again m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); } + + if (spill) + this->spillRenderPass(); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index f198bd101..e2b3f6c3c 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -77,12 +77,15 @@ namespace dxvk { * \brief Sets render targets * * Creates a framebuffer on the fly if necessary - * and binds it using \c bindFramebuffer. Prefer - * this method over doing the same thing manually. + * and binds it using \c bindFramebuffer. Set the + * \c spill flag in order to make shader writes + * from previous rendering operations visible. * \param [in] targets Render targets to bind + * \param [in] spill Spill render pass if true */ void bindRenderTargets( - const DxvkRenderTargets& targets); + const DxvkRenderTargets& targets, + bool spill); /** * \brief Binds index buffer diff --git a/src/dxvk/dxvk_renderpass.cpp b/src/dxvk/dxvk_renderpass.cpp index 7d2908ab0..ee47e05c7 100644 --- a/src/dxvk/dxvk_renderpass.cpp +++ b/src/dxvk/dxvk_renderpass.cpp @@ -135,6 +135,8 @@ namespace dxvk { VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | @@ -144,6 +146,8 @@ namespace dxvk { VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VK_ACCESS_SHADER_READ_BIT | + VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp index 8f55c43ff..c594cfc67 100644 --- a/src/dxvk/hud/dxvk_hud.cpp +++ b/src/dxvk/hud/dxvk_hud.cpp @@ -108,7 +108,7 @@ namespace dxvk::hud { clearRect.layerCount = 1; m_context->bindRenderTargets( - m_renderTargetInfo); + m_renderTargetInfo, false); m_context->clearRenderTarget( m_renderTargetView, clearRect,