From a704e6d27e75abf19831587e49dd3d02f7828e49 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 27 Jun 2019 15:30:31 +0200 Subject: [PATCH] [d3d11] Fix UAV binding in OMSetRenderTargets{,AndUnorderedAccessViews} Unlike for compute shaders, we're supposed to replace all UAV bindings when binding render targets. We also should spill the render pass when disabling UAV rendering to avoid read-after-write hazards. Fixes a potential synchronization bug encountered in Devil May Cry 5. --- src/d3d11/d3d11_context.cpp | 75 +++++++++++++++++++++++---------- src/d3d11/d3d11_context_state.h | 3 ++ 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 6444577a..c2b1eb4b 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -215,6 +215,9 @@ namespace dxvk { m_state.om.sampleMask = D3D11_DEFAULT_SAMPLE_MASK; m_state.om.stencilRef = D3D11_DEFAULT_STENCIL_REFERENCE; + + m_state.om.maxRtv = 0; + m_state.om.maxUav = 0; // Default RS state m_state.rs.state = nullptr; @@ -2566,10 +2569,9 @@ namespace dxvk { UINT NumViews, ID3D11RenderTargetView* const* ppRenderTargetViews, ID3D11DepthStencilView* pDepthStencilView) { - D3D10DeviceLock lock = LockContext(); - - SetRenderTargets(NumViews, ppRenderTargetViews, pDepthStencilView); - BindFramebuffer(false); + OMSetRenderTargetsAndUnorderedAccessViews( + NumViews, ppRenderTargetViews, pDepthStencilView, + NumViews, 0, nullptr, nullptr); } @@ -2583,27 +2585,54 @@ namespace dxvk { const UINT* pUAVInitialCounts) { D3D10DeviceLock lock = LockContext(); - bool isUavRendering = false; - - if (NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) - SetRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView); - - if (NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS) { - // Check whether there actually are any UAVs bound - for (uint32_t i = 0; i < NumUAVs && !isUavRendering; i++) - isUavRendering = ppUnorderedAccessViews[i] != nullptr; - - // UAVs are made available to all shader stages in - // the graphics pipeline even though this code may - // suggest that they are limited to the pixel shader. - SetUnorderedAccessViews( - m_state.ps.unorderedAccessViews, - UAVStartSlot, NumUAVs, - ppUnorderedAccessViews, - pUAVInitialCounts); + if (likely(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL)) { + // Native D3D11 does not change the render targets if + // the parameters passed to this method are invalid. + if (!ValidateRenderTargets(NumRTVs, ppRenderTargetViews, pDepthStencilView)) + return; + + for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) + m_state.om.renderTargetViews[i] = i < NumRTVs + ? static_cast(ppRenderTargetViews[i]) + : nullptr; + + m_state.om.depthStencilView = static_cast(pDepthStencilView); + m_state.om.maxRtv = NumRTVs; } - BindFramebuffer(isUavRendering); + bool spillRenderPass = false; + + if (unlikely(NumUAVs || m_state.om.maxUav)) { + uint32_t uavSlotId = computeUavBinding (DxbcProgramType::PixelShader, 0); + uint32_t ctrSlotId = computeUavCounterBinding(DxbcProgramType::PixelShader, 0); + + if (likely(NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS)) { + uint32_t newMaxUav = NumUAVs ? UAVStartSlot + NumUAVs : 0; + uint32_t oldMaxUav = std::exchange(m_state.om.maxUav, newMaxUav); + + for (uint32_t i = 0; i < std::max(oldMaxUav, newMaxUav); i++) { + D3D11UnorderedAccessView* uav = nullptr; + uint32_t ctr = ~0u; + + if (i >= UAVStartSlot && i < UAVStartSlot + NumUAVs) { + uav = static_cast(ppUnorderedAccessViews[i - UAVStartSlot]); + ctr = pUAVInitialCounts ? pUAVInitialCounts[i - UAVStartSlot] : ~0u; + } + + if (m_state.ps.unorderedAccessViews[i] != uav || ctr != ~0u) { + m_state.ps.unorderedAccessViews[i] = uav; + + BindUnorderedAccessView( + uavSlotId + i, uav, + ctrSlotId + i, ctr); + + spillRenderPass = true; + } + } + } + } + + BindFramebuffer(spillRenderPass); } diff --git a/src/d3d11/d3d11_context_state.h b/src/d3d11/d3d11_context_state.h index 03ba842f..1408f014 100644 --- a/src/d3d11/d3d11_context_state.h +++ b/src/d3d11/d3d11_context_state.h @@ -127,6 +127,9 @@ namespace dxvk { FLOAT blendFactor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; UINT sampleMask = 0xFFFFFFFFu; UINT stencilRef = 0u; + + UINT maxRtv = 0u; + UINT maxUav = 0u; };