From a26a5c0665335c3da919756c2e168bf9932882ce Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 17 Jun 2016 20:03:25 +0200 Subject: [PATCH] Handle UpdateSubresource workaround needed on software command lists --- renderdoc/driver/d3d11/d3d11_context.cpp | 9 +++ renderdoc/driver/d3d11/d3d11_context.h | 2 + .../driver/d3d11/d3d11_context1_wrap.cpp | 81 ++++++++++++++++++- renderdoc/driver/d3d11/d3d11_context_wrap.cpp | 60 +++++++++++++- 4 files changed, 147 insertions(+), 5 deletions(-) diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 2bdd5b536..3d8a3e2a9 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -111,6 +111,15 @@ WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device *real const bool debugSerialiser = true; #endif + m_NeedUpdateSubWorkaround = false; + { + D3D11_FEATURE_DATA_THREADING caps = {FALSE, FALSE}; + + hr = m_pDevice->CheckFeatureSupport(D3D11_FEATURE_THREADING, &caps, sizeof(caps)); + if(SUCCEEDED(hr) && !caps.DriverCommandLists) + m_NeedUpdateSubWorkaround = true; + } + if(RenderDoc::Inst().IsReplayApp()) { m_State = READING; diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h index c9f51d43f..bcab22c9f 100644 --- a/renderdoc/driver/d3d11/d3d11_context.h +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -188,6 +188,8 @@ private: ID3D11DeviceContext2 *m_pRealContext2; + bool m_NeedUpdateSubWorkaround; + set m_DeferredRecords; map m_MapResourceRecordAllocs; diff --git a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp index 02b025a06..3a9cbde31 100644 --- a/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context1_wrap.cpp @@ -147,11 +147,63 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD if(m_State == READING) RecordUpdateStats(DestResource, SourceDataLength, true); - if(flags == 0) + if(flags == ~0U) { + byte *adjustedData = SourceData; + + if(pBox && m_NeedUpdateSubWorkaround && GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + RDCWARN("oops!"); + // apply the workaround for the data we're about to pass + + D3D11_BOX alignedBox = *pBox; + + DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN; + + if(WrappedID3D11Texture1D::IsAlloc(DestResource)) + { + D3D11_TEXTURE1D_DESC desc; + ((WrappedID3D11Texture1D *)DestResource)->GetDesc(&desc); + fmt = desc.Format; + } + else if(WrappedID3D11Texture2D::IsAlloc(DestResource)) + { + D3D11_TEXTURE2D_DESC desc; + ((WrappedID3D11Texture2D *)DestResource)->GetDesc(&desc); + fmt = desc.Format; + } + else if(WrappedID3D11Texture3D::IsAlloc(DestResource)) + { + D3D11_TEXTURE3D_DESC desc; + ((WrappedID3D11Texture3D *)DestResource)->GetDesc(&desc); + fmt = desc.Format; + } + else + { + RDCASSERT(WrappedID3D11Buffer::IsAlloc(DestResource)); + } + + // convert from pixels to blocks + if(IsBlockFormat(fmt)) + { + alignedBox.left /= 4; + alignedBox.right /= 4; + alignedBox.top /= 4; + alignedBox.bottom /= 4; + } + + // if we couldn't get a format it's a buffer, so work in bytes + if(fmt != DXGI_FORMAT_UNKNOWN) + adjustedData = adjustedData - (alignedBox.front * SourceDepthPitch) - + (alignedBox.top * SourceRowPitch) - + (alignedBox.left * GetByteSize(1, 1, 1, fmt, 0)); + else + adjustedData = adjustedData - alignedBox.left; + } + m_pRealContext->UpdateSubresource( m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, pBox, - SourceData, SourceRowPitch, SourceDepthPitch); + adjustedData, SourceRowPitch, SourceDepthPitch); } else { @@ -161,6 +213,16 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, pBox, SourceData, SourceRowPitch, SourceDepthPitch, flags); } + else if(flags == 0) + { + // if flags is 0 UpdateSubresource1 behaves identically to UpdateSubresource + // according to the docs. The only case is the deferred context bug workaround + // isn't needed, but this wasn't properly handled before, and now this ambiguity + // is resolved by passing ~0U as the flags to indicate a 'real' call to UpdateSubresource + m_pRealContext->UpdateSubresource( + m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, pBox, + SourceData, SourceRowPitch, SourceDepthPitch); + } else { RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); @@ -246,7 +308,7 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD RecordUpdateStats(DestResource, SourceRowPitch * subHeight + SourceDepthPitch * subWidth * subHeight, true); - if(flags == 0) + if(flags == ~0U) { m_pRealContext->UpdateSubresource( m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, NULL, @@ -260,9 +322,22 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource1(ID3D11Resource *pD m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, NULL, bufData, SourceRowPitch, SourceDepthPitch, flags); } + else if(flags == 0) + { + // if flags is 0 UpdateSubresource1 behaves identically to UpdateSubresource + // according to the docs. The only case is the deferred context bug workaround + // isn't needed, but this wasn't properly handled before, and now this ambiguity + // is resolved by passing ~0U as the flags to indicate a 'real' call to UpdateSubresource + m_pRealContext->UpdateSubresource( + m_pDevice->GetResourceManager()->UnwrapResource(DestResource), DestSubresource, NULL, + bufData, SourceRowPitch, SourceDepthPitch); + } else { RDCERR("Replaying a D3D11.1 context without D3D11.1 available"); + m_pDevice->AddDebugMessage( + eDbgCategory_Portability, eDbgSeverity_High, eDbgSoruce_UnsupportedConfiguration, + "Replaying a call to UpdateSubresource1() without D3D11.1 available"); } } } diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index bd8ed87cd..f803b5906 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -5628,8 +5628,10 @@ bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource(ID3D11Resource *pDs const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) { + // pass ~0U as the flags to indicate this came for UpdateSubresource, so we know to apply + // deferred context workarounds or not return Serialise_UpdateSubresource1(pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, - SrcDepthPitch, 0); + SrcDepthPitch, ~0U); } void WrappedID3D11DeviceContext::UpdateSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, @@ -5640,6 +5642,57 @@ void WrappedID3D11DeviceContext::UpdateSubresource(ID3D11Resource *pDstResource, m_EmptyCommandList = false; + const void *pOrigSrcData = pSrcData; + + if(pDstBox && m_NeedUpdateSubWorkaround && GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + // we need to apply the *inverse* of the workaround, which matches the broken D3D behaviour + // so that we end up pointing at the expected data. + + D3D11_BOX alignedBox = *pDstBox; + + DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN; + + if(WrappedID3D11Texture1D::IsAlloc(pDstResource)) + { + D3D11_TEXTURE1D_DESC desc; + ((WrappedID3D11Texture1D *)pDstResource)->GetDesc(&desc); + fmt = desc.Format; + } + else if(WrappedID3D11Texture2D::IsAlloc(pDstResource)) + { + D3D11_TEXTURE2D_DESC desc; + ((WrappedID3D11Texture2D *)pDstResource)->GetDesc(&desc); + fmt = desc.Format; + } + else if(WrappedID3D11Texture3D::IsAlloc(pDstResource)) + { + D3D11_TEXTURE3D_DESC desc; + ((WrappedID3D11Texture3D *)pDstResource)->GetDesc(&desc); + fmt = desc.Format; + } + else + { + RDCASSERT(WrappedID3D11Buffer::IsAlloc(pDstResource)); + } + + // convert from pixels to blocks + if(IsBlockFormat(fmt)) + { + alignedBox.left /= 4; + alignedBox.right /= 4; + alignedBox.top /= 4; + alignedBox.bottom /= 4; + } + + // if we couldn't get a format it's a buffer, so work in bytes + if(fmt != DXGI_FORMAT_UNKNOWN) + pSrcData = ((const BYTE *)pSrcData) + (alignedBox.front * SrcDepthPitch) + + (alignedBox.top * SrcRowPitch) + (alignedBox.left * GetByteSize(1, 1, 1, fmt, 0)); + else + pSrcData = ((const BYTE *)pSrcData) + (alignedBox.left); + } + if(m_State == WRITING_CAPFRAME) { SCOPED_SERIALISE_CONTEXT(UPDATE_SUBRESOURCE); @@ -5842,8 +5895,11 @@ void WrappedID3D11DeviceContext::UpdateSubresource(ID3D11Resource *pDstResource, } } + // pass pOrigSrcData here because any workarounds etc need to be preserved as if we were never + // in the way intercepting things. m_pRealContext->UpdateSubresource(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), - DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); + DstSubresource, pDstBox, pOrigSrcData, SrcRowPitch, + SrcDepthPitch); } bool WrappedID3D11DeviceContext::Serialise_CopyStructureCount(ID3D11Buffer *pDstBuffer,