From 764aee6995d50bf758452d3ced882d2e6b8af94e Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Sat, 13 Dec 2014 00:32:08 +0100 Subject: [PATCH 1/2] D3D: Fixed D3D validation error during EFB to texture copy Texture was being bound as a render target while still being set as a shader resource. D3D automatically unbinds the SRV in this case and generates a validation error. The fix is to manually unbind SRV, render into it and then re-bind to old slots. --- Source/Core/VideoBackends/D3D/D3DState.cpp | 16 ++++++++++++++++ Source/Core/VideoBackends/D3D/D3DState.h | 3 +++ Source/Core/VideoBackends/D3D/TextureCache.cpp | 13 +++++++++++++ 3 files changed, 32 insertions(+) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 33310c9957..ff4b547e28 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -199,6 +199,22 @@ void StateManager::Apply() m_dirtyFlags = 0; } +u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv) +{ + u32 mask = 0; + + for (u32 index = 0; index < 8; ++index) + { + if (m_current.textures[index] == srv) + { + SetTexture(index, nullptr); + mask |= 1 << index; + } + } + + return mask; +} + } // namespace D3D ID3D11SamplerState* StateCache::Get(SamplerState state) diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index af2d7f2adb..e53c997908 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -234,6 +234,9 @@ public: } } + // removes currently set texture from all slots, returns mask of previously bound slots + u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv); + // call this immediately before any drawing operation or to explicitly apply pending resource state changes void Apply(); diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index 4ed4d6045f..e679398d50 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -156,6 +156,10 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo else D3D::SetPointCopySampler(); + // if texture is currently in use, it needs to be temporarily unset + u32 textureSlotMask = D3D::stateman->UnsetTexture(texture->GetSRV()); + D3D::stateman->Apply(); + D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); // Create texture copy @@ -168,6 +172,15 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); g_renderer->RestoreAPIState(); + + // Restore old texture in all previously used slots, if any + while (textureSlotMask) + { + unsigned long index; + _BitScanForward(&index, textureSlotMask); + D3D::stateman->SetTexture(index, texture->GetSRV()); + textureSlotMask &= ~(1 << index); + } } if (!g_ActiveConfig.bCopyEFBToTexture) From 5688c27610f2a6d67b62e8f90f689e3c1d90a953 Mon Sep 17 00:00:00 2001 From: Yuriy O'Donnell Date: Wed, 17 Dec 2014 20:31:08 +0100 Subject: [PATCH 2/2] D3D: Moved setting texture by slot mask into StateManager --- Source/Core/VideoBackends/D3D/D3DState.cpp | 11 +++++++++++ Source/Core/VideoBackends/D3D/D3DState.h | 3 ++- Source/Core/VideoBackends/D3D/TextureCache.cpp | 8 +------- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index ff4b547e28..d4d98e35b8 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -215,6 +215,17 @@ u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv) return mask; } +void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv) +{ + while (textureSlotMask) + { + unsigned long index; + _BitScanForward(&index, textureSlotMask); + SetTexture(index, srv); + textureSlotMask &= ~(1 << index); + } +} + } // namespace D3D ID3D11SamplerState* StateCache::Get(SamplerState state) diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index e53c997908..5c22d26733 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -235,7 +235,8 @@ public: } // removes currently set texture from all slots, returns mask of previously bound slots - u32 StateManager::UnsetTexture(ID3D11ShaderResourceView* srv); + u32 UnsetTexture(ID3D11ShaderResourceView* srv); + void SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceView* srv); // call this immediately before any drawing operation or to explicitly apply pending resource state changes void Apply(); diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index e679398d50..3661155f37 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -174,13 +174,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo g_renderer->RestoreAPIState(); // Restore old texture in all previously used slots, if any - while (textureSlotMask) - { - unsigned long index; - _BitScanForward(&index, textureSlotMask); - D3D::stateman->SetTexture(index, texture->GetSRV()); - textureSlotMask &= ~(1 << index); - } + D3D::stateman->SetTextureByMask(textureSlotMask, texture->GetSRV()); } if (!g_ActiveConfig.bCopyEFBToTexture)