1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-03 04:24:11 +01:00

[d3d11] Check for shader resource view hazards

Fixes incorrect behaviour in games that try to use a currently bound
UAV or render target as a shader resource at the same time.

Fixes visual artifacts in Shining Resonance Refrain on AMD hardware.
This commit is contained in:
Philip Rebohle 2019-08-26 18:08:05 +02:00
parent 137589d755
commit 5756e5c921
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
4 changed files with 131 additions and 4 deletions

View File

@ -2492,6 +2492,8 @@ namespace dxvk {
BindUnorderedAccessView(
uavSlotId + i, uav,
ctrSlotId + i, ctr);
TestCsSrvHazards(uav);
}
}
}
@ -2601,13 +2603,25 @@ namespace dxvk {
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
for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) {
auto rtv = i < NumRTVs
? static_cast<D3D11RenderTargetView*>(ppRenderTargetViews[i])
: nullptr;
if (m_state.om.renderTargetViews[i] != rtv) {
m_state.om.renderTargetViews[i] = rtv;
TestOmSrvHazards(rtv);
}
}
auto dsv = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
if (m_state.om.depthStencilView != dsv) {
m_state.om.depthStencilView = dsv;
TestOmSrvHazards(dsv);
}
m_state.om.depthStencilView = static_cast<D3D11DepthStencilView*>(pDepthStencilView);
m_state.om.maxRtv = NumRTVs;
m_state.om.maxRtv = NumRTVs;
}
bool spillRenderPass = false;
@ -2635,6 +2649,8 @@ namespace dxvk {
BindUnorderedAccessView(
uavSlotId + i, uav,
ctrSlotId + i, ctr);
TestOmSrvHazards(uav);
spillRenderPass = true;
}
@ -3535,6 +3551,16 @@ namespace dxvk {
auto resView = static_cast<D3D11ShaderResourceView*>(ppResources[i]);
if (Bindings.views[StartSlot + i] != resView) {
if (unlikely(resView && resView->TestHazards())) {
if (TestSrvHazards<ShaderStage>(resView))
resView = nullptr;
// Only set if necessary, but don't reset it on every
// bind as this would be more expensive than a few
// redundant checks in OMSetRenderTargets and friends.
Bindings.hazardous.set(StartSlot + i, resView);
}
Bindings.views[StartSlot + i] = resView;
BindShaderResource(slotId + i, resView);
}
@ -3711,6 +3737,81 @@ namespace dxvk {
}
template<DxbcProgramType ShaderStage>
bool D3D11DeviceContext::TestSrvHazards(
D3D11ShaderResourceView* pView) {
bool hazard = false;
if (ShaderStage == DxbcProgramType::ComputeShader) {
int32_t uav = m_state.cs.uavMask.findNext(0);
while (uav >= 0 && !hazard) {
hazard = CheckViewOverlap(pView, m_state.cs.unorderedAccessViews[uav].ptr());
uav = m_state.cs.uavMask.findNext(uav + 1);
}
} else {
hazard = CheckViewOverlap(pView, m_state.om.depthStencilView.ptr());
for (uint32_t i = 0; !hazard && i < m_state.om.maxRtv; i++)
hazard = CheckViewOverlap(pView, m_state.om.renderTargetViews[i].ptr());
for (uint32_t i = 0; !hazard && i < m_state.om.maxUav; i++)
hazard = CheckViewOverlap(pView, m_state.ps.unorderedAccessViews[i].ptr());
}
return hazard;
}
template<DxbcProgramType ShaderStage, typename T>
void D3D11DeviceContext::TestSrvHazards(
T* pView,
D3D11ShaderResourceBindings& Bindings) {
uint32_t slotId = computeSrvBinding(ShaderStage, 0);
int32_t srvId = Bindings.hazardous.findNext(0);
while (srvId >= 0) {
auto srv = Bindings.views[srvId].ptr();
if (likely(srv && srv->TestHazards())) {
bool hazard = CheckViewOverlap(pView, srv);
if (unlikely(hazard)) {
Bindings.views[srvId] = nullptr;
Bindings.hazardous.clr(srvId);
BindShaderResource(slotId + srvId, nullptr);
}
} else {
// Avoid further redundant iterations
Bindings.hazardous.clr(srvId);
}
srvId = Bindings.hazardous.findNext(srvId + 1);
}
}
template<typename T>
void D3D11DeviceContext::TestOmSrvHazards(
T* pView) {
if (!pView) return;
TestSrvHazards<DxbcProgramType::VertexShader> (pView, m_state.vs.shaderResources);
TestSrvHazards<DxbcProgramType::HullShader> (pView, m_state.hs.shaderResources);
TestSrvHazards<DxbcProgramType::DomainShader> (pView, m_state.ds.shaderResources);
TestSrvHazards<DxbcProgramType::GeometryShader> (pView, m_state.gs.shaderResources);
TestSrvHazards<DxbcProgramType::PixelShader> (pView, m_state.ps.shaderResources);
}
template<typename T>
void D3D11DeviceContext::TestCsSrvHazards(
T* pView) {
if (!pView) return;
TestSrvHazards<DxbcProgramType::ComputeShader> (pView, m_state.cs.shaderResources);
}
bool D3D11DeviceContext::ValidateRenderTargets(
UINT NumViews,
ID3D11RenderTargetView* const* ppRenderTargetViews,

View File

@ -800,6 +800,23 @@ namespace dxvk {
const D3D11CommonTexture* pTexture,
VkImageSubresource Subresource);
template<DxbcProgramType ShaderStage>
bool TestSrvHazards(
D3D11ShaderResourceView* pView);
template<DxbcProgramType ShaderStage, typename T>
void TestSrvHazards(
T* pView,
D3D11ShaderResourceBindings& Bindings);
template<typename T>
void TestOmSrvHazards(
T* pView);
template<typename T>
void TestCsSrvHazards(
T* pView);
bool ValidateRenderTargets(
UINT NumViews,
ID3D11RenderTargetView* const* ppRenderTargetViews,

View File

@ -73,4 +73,9 @@ namespace dxvk {
}
}
template<typename T1, typename T2>
bool CheckViewOverlap(const T1* a, const T2* b) {
return a && b && CheckViewOverlap(a->GetViewInfo(), b->GetViewInfo());
}
}

View File

@ -37,6 +37,10 @@ namespace dxvk {
return m_info;
}
BOOL TestHazards() const {
return m_info.BindFlags & (D3D11_BIND_RENDER_TARGET | D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_UNORDERED_ACCESS);
}
D3D11_RESOURCE_DIMENSION GetResourceType() const {
D3D11_RESOURCE_DIMENSION type;
m_resource->GetType(&type);