/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2015-2018 Baldur Karlsson * Copyright (c) 2014 Crytek * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ #include "d3d11_context.h" #include "3rdparty/tinyfiledialogs/tinyfiledialogs.h" #include "driver/dx/official/dxgi1_3.h" #include "strings/string_utils.h" #include "d3d11_debug.h" #include "d3d11_renderstate.h" #include "d3d11_resources.h" #ifndef DXGI_ERROR_INVALID_CALL #define DXGI_ERROR_INVALID_CALL MAKE_DXGI_HRESULT(1) #endif uint32_t NullCBOffsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; uint32_t NullCBCounts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; #pragma region D3DPERF template bool WrappedID3D11DeviceContext::Serialise_SetMarker(SerialiserType &ser, uint32_t Color, const wchar_t *MarkerNameW) { SERIALISE_ELEMENT(Color); SERIALISE_ELEMENT_LOCAL(MarkerName, StringFormat::Wide2UTF8(MarkerNameW ? MarkerNameW : L"")); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { D3D11MarkerRegion::Set(MarkerName); if(IsLoading(m_State)) { DrawcallDescription draw; draw.name = MarkerName; draw.flags |= DrawFlags::SetMarker; byte alpha = (Color >> 24) & 0xff; byte red = (Color >> 16) & 0xff; byte green = (Color >> 8) & 0xff; byte blue = (Color >> 0) & 0xff; draw.markerColor[0] = float(red) / 255.0f; draw.markerColor[1] = float(green) / 255.0f; draw.markerColor[2] = float(blue) / 255.0f; draw.markerColor[3] = float(alpha) / 255.0f; AddEvent(); AddDrawcall(draw, false); } } return true; } template bool WrappedID3D11DeviceContext::Serialise_PushMarker(SerialiserType &ser, uint32_t Color, const wchar_t *MarkerNameW) { SERIALISE_ELEMENT(Color); SERIALISE_ELEMENT_LOCAL(MarkerName, StringFormat::Wide2UTF8(MarkerNameW ? MarkerNameW : L"")); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { D3D11MarkerRegion::Begin(MarkerName); m_pDevice->ReplayPushEvent(); if(IsLoading(m_State)) { DrawcallDescription draw; draw.name = MarkerName; draw.flags |= DrawFlags::PushMarker; byte alpha = (Color >> 24) & 0xff; byte red = (Color >> 16) & 0xff; byte green = (Color >> 8) & 0xff; byte blue = (Color >> 0) & 0xff; draw.markerColor[0] = float(red) / 255.0f; draw.markerColor[1] = float(green) / 255.0f; draw.markerColor[2] = float(blue) / 255.0f; draw.markerColor[3] = float(alpha) / 255.0f; AddEvent(); AddDrawcall(draw, false); } } return true; } template bool WrappedID3D11DeviceContext::Serialise_PopMarker(SerialiserType &ser) { if(IsReplayingAndReading()) { D3D11MarkerRegion::End(); m_pDevice->ReplayPopEvent(); if(IsLoading(m_State) && !m_CurEvents.empty()) { DrawcallDescription draw; draw.name = "API Calls"; draw.flags |= DrawFlags::APICalls; AddEvent(); AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::SetMarker(uint32_t Color, const wchar_t *MarkerName) { SERIALISE_TIME_CALL(); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetMarker); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_SetMarker(GET_SERIALISER, Color, MarkerName); m_ContextRecord->AddChunk(scope.Get()); } } int WrappedID3D11DeviceContext::PushMarker(uint32_t Color, const wchar_t *MarkerName) { SERIALISE_TIME_CALL(); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PushMarker); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PushMarker(GET_SERIALISER, Color, MarkerName); m_ContextRecord->AddChunk(scope.Get()); } return m_MarkerIndentLevel++; } int WrappedID3D11DeviceContext::PopMarker() { SERIALISE_TIME_CALL(); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PopMarker); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PopMarker(GET_SERIALISER); m_ContextRecord->AddChunk(scope.Get()); } return --m_MarkerIndentLevel; } void WrappedID3D11DeviceContext::ThreadSafe_SetMarker(uint32_t col, const wchar_t *name) { Annotation annot; annot.m_Type = Annotation::ANNOT_SETMARKER; annot.m_Col = col; annot.m_Name = name; { SCOPED_LOCK(m_AnnotLock); m_AnnotationQueue.push_back(annot); } } int WrappedID3D11DeviceContext::ThreadSafe_BeginEvent(uint32_t col, const wchar_t *name) { Annotation annot; annot.m_Type = Annotation::ANNOT_BEGINEVENT; annot.m_Col = col; annot.m_Name = name; { SCOPED_LOCK(m_AnnotLock); m_AnnotationQueue.push_back(annot); } // not thread safe but I don't want to lock over access to this - if people use D3DPERF + MT // they shouldn't rely on this return value anyway :). return m_MarkerIndentLevel; } int WrappedID3D11DeviceContext::ThreadSafe_EndEvent() { Annotation annot; annot.m_Type = Annotation::ANNOT_ENDEVENT; { SCOPED_LOCK(m_AnnotLock); m_AnnotationQueue.push_back(annot); } // not thread safe but I don't want to lock over access to this - if people use D3DPERF + MT // they shouldn't rely on this return value anyway :). return m_MarkerIndentLevel - 1; } void WrappedID3D11DeviceContext::DrainAnnotationQueue() { if(!IsActiveCapturing(m_State)) return; m_AnnotLock.Lock(); // fastest possible early-out if(m_AnnotationQueue.empty()) { m_AnnotLock.Unlock(); return; } std::vector annotations; annotations.swap(m_AnnotationQueue); m_AnnotLock.Unlock(); for(size_t i = 0; i < annotations.size(); i++) { const Annotation &a = annotations[i]; switch(a.m_Type) { case Annotation::ANNOT_SETMARKER: SetMarker(a.m_Col, a.m_Name.c_str()); break; case Annotation::ANNOT_BEGINEVENT: PushMarker(a.m_Col, a.m_Name.c_str()); break; case Annotation::ANNOT_ENDEVENT: PopMarker(); break; } } } #pragma endregion D3DPERF #pragma region Input Assembly void WrappedID3D11DeviceContext::IAGetInputLayout(ID3D11InputLayout **ppInputLayout) { if(ppInputLayout) { ID3D11InputLayout *real = NULL; m_pRealContext->IAGetInputLayout(&real); SAFE_RELEASE_NOCLEAR(real); *ppInputLayout = (ID3D11InputLayout *)m_pDevice->GetResourceManager()->GetWrapper(real); SAFE_ADDREF(*ppInputLayout); RDCASSERT(*ppInputLayout == m_CurrentPipelineState->IA.Layout); } } void WrappedID3D11DeviceContext::IAGetVertexBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppVertexBuffers, UINT *pStrides, UINT *pOffsets) { ID3D11Buffer *real[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->IAGetVertexBuffers(StartSlot, NumBuffers, real, pStrides, pOffsets); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); if(ppVertexBuffers) { ppVertexBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppVertexBuffers[i]); RDCASSERT(ppVertexBuffers[i] == m_CurrentPipelineState->IA.VBs[i + StartSlot]); } // D3D11 really inconsistently tracks these. // RDCASSERT(pStrides[i] == m_CurrentPipelineState->IA.Strides[i+StartSlot]); // RDCASSERT(pOffsets[i] == m_CurrentPipelineState->IA.Offsets[i+StartSlot]); } } void WrappedID3D11DeviceContext::IAGetIndexBuffer(ID3D11Buffer **pIndexBuffer, DXGI_FORMAT *Format, UINT *Offset) { if(pIndexBuffer) { ID3D11Buffer *real = NULL; m_pRealContext->IAGetIndexBuffer(&real, Format, Offset); SAFE_RELEASE_NOCLEAR(real); *pIndexBuffer = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real); SAFE_ADDREF(*pIndexBuffer); RDCASSERT(*pIndexBuffer == m_CurrentPipelineState->IA.IndexBuffer); if(Format) RDCASSERT(*Format == m_CurrentPipelineState->IA.IndexFormat); if(Offset) RDCASSERT(*Offset == m_CurrentPipelineState->IA.IndexOffset); } } void WrappedID3D11DeviceContext::IAGetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY *pTopology) { m_pRealContext->IAGetPrimitiveTopology(pTopology); if(pTopology) RDCASSERT(*pTopology == m_CurrentPipelineState->IA.Topo); } template bool WrappedID3D11DeviceContext::Serialise_IASetPrimitiveTopology(SerialiserType &ser, D3D11_PRIMITIVE_TOPOLOGY Topology) { SERIALISE_ELEMENT(Topology); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Topo, Topology); m_pRealContext->IASetPrimitiveTopology(Topology); VerifyState(); } return true; } void WrappedID3D11DeviceContext::IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->IASetPrimitiveTopology(Topology)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::IASetPrimitiveTopology); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_IASetPrimitiveTopology(GET_SERIALISER, Topology); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Topo, Topology); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_IASetInputLayout(SerialiserType &ser, ID3D11InputLayout *pInputLayout) { SERIALISE_ELEMENT(pInputLayout); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordLayoutBindStats(pInputLayout); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.Layout, pInputLayout); m_pRealContext->IASetInputLayout(UNWRAP(WrappedID3D11InputLayout, pInputLayout)); VerifyState(); } return true; } void WrappedID3D11DeviceContext::IASetInputLayout(ID3D11InputLayout *pInputLayout) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL( m_pRealContext->IASetInputLayout(UNWRAP(WrappedID3D11InputLayout, pInputLayout))); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::IASetInputLayout); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_IASetInputLayout(GET_SERIALISER, pInputLayout); MarkResourceReferenced(GetIDForResource(pInputLayout), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.Layout, pInputLayout); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_IASetVertexBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppVertexBuffers, const UINT *pStrides, const UINT *pOffsets) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppVertexBuffers, NumBuffers); SERIALISE_ELEMENT_ARRAY(pStrides, NumBuffers); SERIALISE_ELEMENT_ARRAY(pOffsets, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordVertexBindStats(NumBuffers, ppVertexBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.VBs, ppVertexBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Strides, pStrides, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Offsets, pOffsets, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppVertexBuffers[i]); m_pRealContext->IASetVertexBuffers(StartSlot, NumBuffers, bufs, pStrides, pOffsets); VerifyState(); } return true; } void WrappedID3D11DeviceContext::IASetVertexBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppVertexBuffers, const UINT *pStrides, const UINT *pOffsets) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) { if(ppVertexBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppVertexBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppVertexBuffers[i]); } SERIALISE_TIME_CALL( m_pRealContext->IASetVertexBuffers(StartSlot, NumBuffers, bufs, pStrides, pOffsets)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::IASetVertexBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_IASetVertexBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppVertexBuffers, pStrides, pOffsets); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.VBs, ppVertexBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Strides, pStrides, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.Offsets, pOffsets, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_IASetIndexBuffer(SerialiserType &ser, ID3D11Buffer *pIndexBuffer, DXGI_FORMAT Format, UINT Offset) { SERIALISE_ELEMENT(pIndexBuffer); SERIALISE_ELEMENT(Format); SERIALISE_ELEMENT(Offset); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordIndexBindStats(pIndexBuffer); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.IndexBuffer, pIndexBuffer); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexFormat, Format); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexOffset, Offset); m_pRealContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, pIndexBuffer), Format, Offset); VerifyState(); } return true; } void WrappedID3D11DeviceContext::IASetIndexBuffer(ID3D11Buffer *pIndexBuffer, DXGI_FORMAT Format, UINT Offset) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL( m_pRealContext->IASetIndexBuffer(UNWRAP(WrappedID3D11Buffer, pIndexBuffer), Format, Offset)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::IASetIndexBuffer); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_IASetIndexBuffer(GET_SERIALISER, pIndexBuffer, Format, Offset); m_ContextRecord->AddChunk(scope.Get()); } if(pIndexBuffer && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(pIndexBuffer), eFrameRef_Read); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->IA.IndexBuffer, pIndexBuffer); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexFormat, Format); m_CurrentPipelineState->Change(m_CurrentPipelineState->IA.IndexOffset, Offset); VerifyState(); } #pragma endregion Input Assembly #pragma region Vertex Shader void WrappedID3D11DeviceContext::VSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) { if(ppConstantBuffers) { ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; m_pRealContext->VSGetConstantBuffers(StartSlot, NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppConstantBuffers[i]); RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->VS.ConstantBuffers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::VSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) { if(ppShaderResourceViews) { ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->VSGetShaderResources(StartSlot, NumViews, real); for(UINT i = 0; i < NumViews; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppShaderResourceViews[i]); RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->VS.SRVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::VSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) { if(ppSamplers) { ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; m_pRealContext->VSGetSamplers(StartSlot, NumSamplers, real); for(UINT i = 0; i < NumSamplers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSamplers[i]); RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->VS.Samplers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::VSGetShader(ID3D11VertexShader **ppVertexShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) { if(ppVertexShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) return; ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; UINT numInsts = 0; ID3D11VertexShader *realShader = NULL; m_pRealContext->VSGetShader(&realShader, realInsts, &numInsts); SAFE_RELEASE_NOCLEAR(realShader); for(UINT i = 0; i < numInsts; i++) SAFE_RELEASE_NOCLEAR(realInsts[i]); if(ppVertexShader) { *ppVertexShader = (ID3D11VertexShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); SAFE_ADDREF(*ppVertexShader); RDCASSERT(*ppVertexShader == m_CurrentPipelineState->VS.Object); } if(ppClassInstances) { for(UINT i = 0; i < numInsts; i++) { ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); SAFE_ADDREF(ppClassInstances[i]); RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->VS.Instances[i]); } } if(pNumClassInstances) { *pNumClassInstances = numInsts; } } template bool WrappedID3D11DeviceContext::Serialise_VSSetConstantBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppConstantBuffers, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordConstantStats(ShaderStage::Vertex, NumBuffers, ppConstantBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBCounts, NullCBCounts, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); m_pRealContext->VSSetConstantBuffers(StartSlot, NumBuffers, bufs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::VSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) { if(ppConstantBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); } SERIALISE_TIME_CALL(m_pRealContext->VSSetConstantBuffers(StartSlot, NumBuffers, bufs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::VSSetConstantBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_VSSetConstantBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppConstantBuffers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.CBCounts, NullCBCounts, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_VSSetShaderResources( SerialiserType &ser, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppShaderResourceViews, NumViews); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordResourceStats(ShaderStage::Vertex, NumViews, ppShaderResourceViews); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.SRVs, ppShaderResourceViews, StartSlot, NumViews); ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); m_pRealContext->VSSetShaderResources(StartSlot, NumViews, SRVs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::VSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) { if(ppShaderResourceViews[i] && IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppShaderResourceViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppShaderResourceViews[i]), eFrameRef_Read); } SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); } SERIALISE_TIME_CALL(m_pRealContext->VSSetShaderResources(StartSlot, NumViews, SRVs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::VSSetShaderResources); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_VSSetShaderResources(GET_SERIALISER, StartSlot, NumViews, ppShaderResourceViews); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.SRVs, ppShaderResourceViews, StartSlot, NumViews); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_VSSetSamplers(SerialiserType &ser, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumSamplers); SERIALISE_ELEMENT_ARRAY(ppSamplers, NumSamplers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordSamplerStats(ShaderStage::Vertex, NumSamplers, ppSamplers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Samplers, ppSamplers, StartSlot, NumSamplers); ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); m_pRealContext->VSSetSamplers(StartSlot, NumSamplers, samps); VerifyState(); } return true; } void WrappedID3D11DeviceContext::VSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) { if(ppSamplers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppSamplers[i]), eFrameRef_Read); samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); } SERIALISE_TIME_CALL(m_pRealContext->VSSetSamplers(StartSlot, NumSamplers, samps)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::VSSetSamplers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_VSSetSamplers(GET_SERIALISER, StartSlot, NumSamplers, ppSamplers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Samplers, ppSamplers, StartSlot, NumSamplers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_VSSetShader(SerialiserType &ser, ID3D11VertexShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { SERIALISE_ELEMENT(pShader); SERIALISE_ELEMENT_ARRAY(ppClassInstances, NumClassInstances); SERIALISE_ELEMENT(NumClassInstances); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordShaderStats(ShaderStage::Vertex, m_CurrentPipelineState->VS.Object, pShader); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Instances, ppClassInstances, 0, NumClassInstances); m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Object, (ID3D11DeviceChild *)pShader); ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); m_pRealContext->VSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); VerifyState(); } return true; } void WrappedID3D11DeviceContext::VSSetShader(ID3D11VertexShader *pVertexShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; if(ppClassInstances && NumClassInstances > 0) for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); SERIALISE_TIME_CALL(m_pRealContext->VSSetShader( UNWRAP(WrappedID3D11Shader, pVertexShader), insts, NumClassInstances)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::VSSetShader); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_VSSetShader(GET_SERIALISER, pVertexShader, ppClassInstances, NumClassInstances); MarkResourceReferenced(GetIDForResource(pVertexShader), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Object, (ID3D11DeviceChild *)pVertexShader); m_CurrentPipelineState->Change(m_CurrentPipelineState->VS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->VS.Instances, ppClassInstances, 0, NumClassInstances); VerifyState(); } #pragma endregion Vertex Shader #pragma region Hull Shader void WrappedID3D11DeviceContext::HSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) { if(ppConstantBuffers) { ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; m_pRealContext->HSGetConstantBuffers(StartSlot, NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppConstantBuffers[i]); RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->HS.ConstantBuffers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::HSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) { if(ppShaderResourceViews) { ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->HSGetShaderResources(StartSlot, NumViews, real); for(UINT i = 0; i < NumViews; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppShaderResourceViews[i]); RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->HS.SRVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::HSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) { if(ppSamplers) { ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; m_pRealContext->HSGetSamplers(StartSlot, NumSamplers, real); for(UINT i = 0; i < NumSamplers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSamplers[i]); RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->HS.Samplers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::HSGetShader(ID3D11HullShader **ppHullShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) { if(ppHullShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) return; ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; UINT numInsts = 0; ID3D11HullShader *realShader = NULL; m_pRealContext->HSGetShader(&realShader, realInsts, &numInsts); SAFE_RELEASE_NOCLEAR(realShader); for(UINT i = 0; i < numInsts; i++) SAFE_RELEASE_NOCLEAR(realInsts[i]); if(ppHullShader) { *ppHullShader = (ID3D11HullShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); SAFE_ADDREF(*ppHullShader); RDCASSERT(*ppHullShader == m_CurrentPipelineState->HS.Object); } if(ppClassInstances) { for(UINT i = 0; i < numInsts; i++) { ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); SAFE_ADDREF(ppClassInstances[i]); RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->HS.Instances[i]); } } if(pNumClassInstances) { *pNumClassInstances = numInsts; } } template bool WrappedID3D11DeviceContext::Serialise_HSSetConstantBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppConstantBuffers, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordConstantStats(ShaderStage::Hull, NumBuffers, ppConstantBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBCounts, NullCBCounts, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); m_pRealContext->HSSetConstantBuffers(StartSlot, NumBuffers, bufs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::HSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) { if(ppConstantBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); } SERIALISE_TIME_CALL(m_pRealContext->HSSetConstantBuffers(StartSlot, NumBuffers, bufs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::HSSetConstantBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_HSSetConstantBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppConstantBuffers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.CBCounts, NullCBCounts, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_HSSetShaderResources( SerialiserType &ser, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppShaderResourceViews, NumViews); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordResourceStats(ShaderStage::Hull, NumViews, ppShaderResourceViews); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.SRVs, ppShaderResourceViews, StartSlot, NumViews); ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); m_pRealContext->HSSetShaderResources(StartSlot, NumViews, SRVs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::HSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) { if(ppShaderResourceViews[i] && IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppShaderResourceViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppShaderResourceViews[i]), eFrameRef_Read); } SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); } SERIALISE_TIME_CALL(m_pRealContext->HSSetShaderResources(StartSlot, NumViews, SRVs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::HSSetShaderResources); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_HSSetShaderResources(GET_SERIALISER, StartSlot, NumViews, ppShaderResourceViews); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.SRVs, ppShaderResourceViews, StartSlot, NumViews); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_HSSetSamplers(SerialiserType &ser, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumSamplers); SERIALISE_ELEMENT_ARRAY(ppSamplers, NumSamplers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordSamplerStats(ShaderStage::Hull, NumSamplers, ppSamplers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Samplers, ppSamplers, StartSlot, NumSamplers); ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); m_pRealContext->HSSetSamplers(StartSlot, NumSamplers, samps); VerifyState(); } return true; } void WrappedID3D11DeviceContext::HSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) { if(ppSamplers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppSamplers[i]), eFrameRef_Read); samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); } SERIALISE_TIME_CALL(m_pRealContext->HSSetSamplers(StartSlot, NumSamplers, samps)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::HSSetSamplers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_HSSetSamplers(GET_SERIALISER, StartSlot, NumSamplers, ppSamplers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Samplers, ppSamplers, StartSlot, NumSamplers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_HSSetShader(SerialiserType &ser, ID3D11HullShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { SERIALISE_ELEMENT(pShader); SERIALISE_ELEMENT_ARRAY(ppClassInstances, NumClassInstances); SERIALISE_ELEMENT(NumClassInstances); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordShaderStats(ShaderStage::Hull, m_CurrentPipelineState->HS.Object, pShader); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Instances, ppClassInstances, 0, NumClassInstances); m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Object, (ID3D11DeviceChild *)pShader); ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); m_pRealContext->HSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); VerifyState(); } return true; } void WrappedID3D11DeviceContext::HSSetShader(ID3D11HullShader *pHullShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; if(ppClassInstances && NumClassInstances > 0) for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); SERIALISE_TIME_CALL(m_pRealContext->HSSetShader( UNWRAP(WrappedID3D11Shader, pHullShader), insts, NumClassInstances)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::HSSetShader); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_HSSetShader(GET_SERIALISER, pHullShader, ppClassInstances, NumClassInstances); MarkResourceReferenced(GetIDForResource(pHullShader), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Object, (ID3D11DeviceChild *)pHullShader); m_CurrentPipelineState->Change(m_CurrentPipelineState->HS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->HS.Instances, ppClassInstances, 0, NumClassInstances); VerifyState(); } #pragma endregion Hull Shader #pragma region Domain Shader void WrappedID3D11DeviceContext::DSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) { if(ppConstantBuffers) { ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; m_pRealContext->DSGetConstantBuffers(StartSlot, NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppConstantBuffers[i]); RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->DS.ConstantBuffers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::DSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) { if(ppShaderResourceViews) { ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->DSGetShaderResources(StartSlot, NumViews, real); for(UINT i = 0; i < NumViews; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppShaderResourceViews[i]); RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->DS.SRVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::DSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) { if(ppSamplers) { ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; m_pRealContext->DSGetSamplers(StartSlot, NumSamplers, real); for(UINT i = 0; i < NumSamplers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSamplers[i]); RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->DS.Samplers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::DSGetShader(ID3D11DomainShader **ppDomainShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) { if(ppDomainShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) return; ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; UINT numInsts = 0; ID3D11DomainShader *realShader = NULL; m_pRealContext->DSGetShader(&realShader, realInsts, &numInsts); SAFE_RELEASE_NOCLEAR(realShader); for(UINT i = 0; i < numInsts; i++) SAFE_RELEASE_NOCLEAR(realInsts[i]); if(ppDomainShader) { *ppDomainShader = (ID3D11DomainShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); SAFE_ADDREF(*ppDomainShader); RDCASSERT(*ppDomainShader == m_CurrentPipelineState->DS.Object); } if(ppClassInstances) { for(UINT i = 0; i < numInsts; i++) { ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); SAFE_ADDREF(ppClassInstances[i]); RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->DS.Instances[i]); } } if(pNumClassInstances) { *pNumClassInstances = numInsts; } } template bool WrappedID3D11DeviceContext::Serialise_DSSetConstantBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppConstantBuffers, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordConstantStats(ShaderStage::Domain, NumBuffers, ppConstantBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBCounts, NullCBCounts, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); m_pRealContext->DSSetConstantBuffers(StartSlot, NumBuffers, bufs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::DSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) { if(ppConstantBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); } SERIALISE_TIME_CALL(m_pRealContext->DSSetConstantBuffers(StartSlot, NumBuffers, bufs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DSSetConstantBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DSSetConstantBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppConstantBuffers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.CBCounts, NullCBCounts, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_DSSetShaderResources( SerialiserType &ser, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppShaderResourceViews, NumViews); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordResourceStats(ShaderStage::Domain, NumViews, ppShaderResourceViews); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.SRVs, ppShaderResourceViews, StartSlot, NumViews); ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); m_pRealContext->DSSetShaderResources(StartSlot, NumViews, SRVs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::DSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) { if(ppShaderResourceViews[i] && IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppShaderResourceViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppShaderResourceViews[i]), eFrameRef_Read); } SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); } SERIALISE_TIME_CALL(m_pRealContext->DSSetShaderResources(StartSlot, NumViews, SRVs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DSSetShaderResources); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DSSetShaderResources(GET_SERIALISER, StartSlot, NumViews, ppShaderResourceViews); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.SRVs, ppShaderResourceViews, StartSlot, NumViews); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_DSSetSamplers(SerialiserType &ser, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumSamplers); SERIALISE_ELEMENT_ARRAY(ppSamplers, NumSamplers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordSamplerStats(ShaderStage::Domain, NumSamplers, ppSamplers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Samplers, ppSamplers, StartSlot, NumSamplers); ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); m_pRealContext->DSSetSamplers(StartSlot, NumSamplers, samps); VerifyState(); } return true; } void WrappedID3D11DeviceContext::DSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) { if(ppSamplers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppSamplers[i]), eFrameRef_Read); samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); } SERIALISE_TIME_CALL(m_pRealContext->DSSetSamplers(StartSlot, NumSamplers, samps)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DSSetSamplers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DSSetSamplers(GET_SERIALISER, StartSlot, NumSamplers, ppSamplers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Samplers, ppSamplers, StartSlot, NumSamplers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_DSSetShader(SerialiserType &ser, ID3D11DomainShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { SERIALISE_ELEMENT(pShader); SERIALISE_ELEMENT_ARRAY(ppClassInstances, NumClassInstances); SERIALISE_ELEMENT(NumClassInstances); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordShaderStats(ShaderStage::Domain, m_CurrentPipelineState->DS.Object, pShader); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Instances, ppClassInstances, 0, NumClassInstances); m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Object, (ID3D11DeviceChild *)pShader); ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); m_pRealContext->DSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); VerifyState(); } return true; } void WrappedID3D11DeviceContext::DSSetShader(ID3D11DomainShader *pDomainShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; if(ppClassInstances && NumClassInstances > 0) for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); SERIALISE_TIME_CALL(m_pRealContext->DSSetShader( UNWRAP(WrappedID3D11Shader, pDomainShader), insts, NumClassInstances)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DSSetShader); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DSSetShader(GET_SERIALISER, pDomainShader, ppClassInstances, NumClassInstances); MarkResourceReferenced(GetIDForResource(pDomainShader), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Object, (ID3D11DeviceChild *)pDomainShader); m_CurrentPipelineState->Change(m_CurrentPipelineState->DS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->DS.Instances, ppClassInstances, 0, NumClassInstances); VerifyState(); } #pragma endregion Domain Shader #pragma region Geometry Shader void WrappedID3D11DeviceContext::GSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) { if(ppConstantBuffers) { ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; m_pRealContext->GSGetConstantBuffers(StartSlot, NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppConstantBuffers[i]); RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->GS.ConstantBuffers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::GSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) { if(ppShaderResourceViews) { ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->GSGetShaderResources(StartSlot, NumViews, real); for(UINT i = 0; i < NumViews; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppShaderResourceViews[i]); RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->GS.SRVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::GSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) { if(ppSamplers) { ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; m_pRealContext->GSGetSamplers(StartSlot, NumSamplers, real); for(UINT i = 0; i < NumSamplers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSamplers[i]); RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->GS.Samplers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::GSGetShader(ID3D11GeometryShader **ppGeometryShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) { if(ppGeometryShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) return; ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; UINT numInsts = 0; ID3D11GeometryShader *realShader = NULL; m_pRealContext->GSGetShader(&realShader, realInsts, &numInsts); SAFE_RELEASE_NOCLEAR(realShader); for(UINT i = 0; i < numInsts; i++) SAFE_RELEASE_NOCLEAR(realInsts[i]); if(ppGeometryShader) { *ppGeometryShader = (ID3D11GeometryShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); SAFE_ADDREF(*ppGeometryShader); RDCASSERT(*ppGeometryShader == m_CurrentPipelineState->GS.Object); } if(ppClassInstances) { for(UINT i = 0; i < numInsts; i++) { ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); SAFE_ADDREF(ppClassInstances[i]); RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->GS.Instances[i]); } } if(pNumClassInstances) { *pNumClassInstances = numInsts; } } template bool WrappedID3D11DeviceContext::Serialise_GSSetConstantBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppConstantBuffers, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordConstantStats(ShaderStage::Geometry, NumBuffers, ppConstantBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBCounts, NullCBCounts, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); m_pRealContext->GSSetConstantBuffers(StartSlot, NumBuffers, bufs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::GSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) { if(ppConstantBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); } SERIALISE_TIME_CALL(m_pRealContext->GSSetConstantBuffers(StartSlot, NumBuffers, bufs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::GSSetConstantBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_GSSetConstantBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppConstantBuffers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.CBCounts, NullCBCounts, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_GSSetShaderResources( SerialiserType &ser, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppShaderResourceViews, NumViews); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordResourceStats(ShaderStage::Geometry, NumViews, ppShaderResourceViews); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.SRVs, ppShaderResourceViews, StartSlot, NumViews); ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); m_pRealContext->GSSetShaderResources(StartSlot, NumViews, SRVs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::GSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) { if(ppShaderResourceViews[i] && IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppShaderResourceViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppShaderResourceViews[i]), eFrameRef_Read); } SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); } SERIALISE_TIME_CALL(m_pRealContext->GSSetShaderResources(StartSlot, NumViews, SRVs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::GSSetShaderResources); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_GSSetShaderResources(GET_SERIALISER, StartSlot, NumViews, ppShaderResourceViews); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.SRVs, ppShaderResourceViews, StartSlot, NumViews); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_GSSetSamplers(SerialiserType &ser, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumSamplers); SERIALISE_ELEMENT_ARRAY(ppSamplers, NumSamplers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordSamplerStats(ShaderStage::Geometry, NumSamplers, ppSamplers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Samplers, ppSamplers, StartSlot, NumSamplers); ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); m_pRealContext->GSSetSamplers(StartSlot, NumSamplers, samps); VerifyState(); } return true; } void WrappedID3D11DeviceContext::GSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) { if(ppSamplers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppSamplers[i]), eFrameRef_Read); samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); } SERIALISE_TIME_CALL(m_pRealContext->GSSetSamplers(StartSlot, NumSamplers, samps)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::GSSetSamplers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_GSSetSamplers(GET_SERIALISER, StartSlot, NumSamplers, ppSamplers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Samplers, ppSamplers, StartSlot, NumSamplers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_GSSetShader(SerialiserType &ser, ID3D11GeometryShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { SERIALISE_ELEMENT(pShader); SERIALISE_ELEMENT_ARRAY(ppClassInstances, NumClassInstances); SERIALISE_ELEMENT(NumClassInstances); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordShaderStats(ShaderStage::Geometry, m_CurrentPipelineState->GS.Object, pShader); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Instances, ppClassInstances, 0, NumClassInstances); m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Object, (ID3D11DeviceChild *)pShader); ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); m_pRealContext->GSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); VerifyState(); } return true; } void WrappedID3D11DeviceContext::GSSetShader(ID3D11GeometryShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; if(ppClassInstances && NumClassInstances > 0) for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); SERIALISE_TIME_CALL(m_pRealContext->GSSetShader( UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::GSSetShader); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_GSSetShader(GET_SERIALISER, pShader, ppClassInstances, NumClassInstances); MarkResourceReferenced(GetIDForResource(pShader), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Object, (ID3D11DeviceChild *)pShader); m_CurrentPipelineState->Change(m_CurrentPipelineState->GS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->GS.Instances, ppClassInstances, 0, NumClassInstances); VerifyState(); } #pragma endregion Geometry Shader #pragma region Stream Out void WrappedID3D11DeviceContext::SOGetTargets(UINT NumBuffers, ID3D11Buffer **ppSOTargets) { if(ppSOTargets) { ID3D11Buffer *real[D3D11_SO_BUFFER_SLOT_COUNT] = {0}; m_pRealContext->SOGetTargets(NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSOTargets[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSOTargets[i]); RDCASSERT(ppSOTargets[i] == m_CurrentPipelineState->SO.Buffers[i]); } } } template bool WrappedID3D11DeviceContext::Serialise_SOSetTargets(SerialiserType &ser, UINT NumBuffers, ID3D11Buffer *const *ppSOTargets, const UINT *pOffsets) { SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppSOTargets, NumBuffers); SERIALISE_ELEMENT_ARRAY(pOffsets, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { // "If less than four [buffers] are defined by the call, the remaining buffer slots are set to // NULL." ID3D11Buffer *setbufs[D3D11_SO_STREAM_COUNT] = {0}; UINT setoffs[D3D11_SO_STREAM_COUNT] = {0}; for(UINT b = 0; b < NumBuffers; b++) { setbufs[b] = ppSOTargets ? ppSOTargets[b] : NULL; // passing NULL for pOffsets seems to act like -1 => append setoffs[b] = pOffsets ? pOffsets[b] : ~0U; } // end stream-out queries for outgoing targets for(UINT b = 0; b < D3D11_SO_STREAM_COUNT; b++) { ID3D11Buffer *buf = m_CurrentPipelineState->SO.Buffers[b]; if(buf) { ResourceId id = GetIDForResource(buf); m_pRealContext->End(m_StreamOutCounters[id].query); m_StreamOutCounters[id].running = false; } } // start new queries for incoming targets for(UINT b = 0; b < D3D11_SO_STREAM_COUNT; b++) { ID3D11Buffer *buf = setbufs[b]; if(buf) { ResourceId id = GetIDForResource(buf); // release any previous query as the hidden counter is overwritten SAFE_RELEASE(m_StreamOutCounters[id].query); D3D11_QUERY queryTypes[] = { D3D11_QUERY_SO_STATISTICS_STREAM0, D3D11_QUERY_SO_STATISTICS_STREAM1, D3D11_QUERY_SO_STATISTICS_STREAM2, D3D11_QUERY_SO_STATISTICS_STREAM3, }; D3D11_QUERY_DESC qdesc; qdesc.MiscFlags = 0; qdesc.Query = queryTypes[b]; m_pDevice->GetReal()->CreateQuery(&qdesc, &m_StreamOutCounters[id].query); m_pRealContext->Begin(m_StreamOutCounters[id].query); m_StreamOutCounters[id].running = true; } } m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->SO.Buffers, setbufs, 0, D3D11_SO_STREAM_COUNT); m_CurrentPipelineState->Change(m_CurrentPipelineState->SO.Offsets, setoffs, 0, D3D11_SO_STREAM_COUNT); for(UINT i = 0; i < NumBuffers; i++) setbufs[i] = UNWRAP(WrappedID3D11Buffer, setbufs[i]); m_pRealContext->SOSetTargets(NumBuffers, setbufs, setoffs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::SOSetTargets(UINT NumBuffers, ID3D11Buffer *const *ppSOTargets, const UINT *pOffsets) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) { if(ppSOTargets && ppSOTargets[i]) { // technically this isn't dirty until the draw call, but let's be conservative // to avoid having to track "possibly" dirty resources. // Besides, it's unlikely an application will set an output then not draw to it if(IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppSOTargets[i]), eFrameRef_Write); m_MissingTracks.insert(GetIDForResource(ppSOTargets[i])); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetIDForResource(ppSOTargets[i])); } bufs[i] = UNWRAP(WrappedID3D11Buffer, ppSOTargets[i]); } } SERIALISE_TIME_CALL(m_pRealContext->SOSetTargets(NumBuffers, bufs, pOffsets)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::SOSetTargets); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_SOSetTargets(GET_SERIALISER, NumBuffers, ppSOTargets, pOffsets); m_ContextRecord->AddChunk(scope.Get()); } // "If less than four [buffers] are defined by the call, the remaining buffer slots are set to // NULL." ID3D11Buffer *setbufs[D3D11_SO_STREAM_COUNT] = {0}; UINT setoffs[D3D11_SO_STREAM_COUNT] = {0}; for(UINT b = 0; b < NumBuffers; b++) { setbufs[b] = ppSOTargets ? ppSOTargets[b] : NULL; // passing NULL for pOffsets seems to act like -1 => append setoffs[b] = pOffsets ? pOffsets[b] : ~0U; } // end stream-out queries for outgoing targets for(UINT b = 0; b < D3D11_SO_STREAM_COUNT; b++) { ID3D11Buffer *buf = m_CurrentPipelineState->SO.Buffers[b]; if(buf) { ResourceId id = GetIDForResource(buf); m_pRealContext->End(m_StreamOutCounters[id].query); m_StreamOutCounters[id].running = false; } } // start new queries for incoming targets for(UINT b = 0; b < D3D11_SO_STREAM_COUNT; b++) { ID3D11Buffer *buf = setbufs[b]; if(buf) { ResourceId id = GetIDForResource(buf); // release any previous query as the hidden counter is overwritten SAFE_RELEASE(m_StreamOutCounters[id].query); D3D11_QUERY queryTypes[] = { D3D11_QUERY_SO_STATISTICS_STREAM0, D3D11_QUERY_SO_STATISTICS_STREAM1, D3D11_QUERY_SO_STATISTICS_STREAM2, D3D11_QUERY_SO_STATISTICS_STREAM3, }; D3D11_QUERY_DESC qdesc; qdesc.MiscFlags = 0; qdesc.Query = queryTypes[b]; m_pDevice->GetReal()->CreateQuery(&qdesc, &m_StreamOutCounters[id].query); m_pRealContext->Begin(m_StreamOutCounters[id].query); m_StreamOutCounters[id].running = true; } } m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->SO.Buffers, setbufs, 0, D3D11_SO_STREAM_COUNT); m_CurrentPipelineState->Change(m_CurrentPipelineState->SO.Offsets, setoffs, 0, D3D11_SO_STREAM_COUNT); VerifyState(); } #pragma endregion Stream Out #pragma region Rasterizer void WrappedID3D11DeviceContext::RSGetViewports(UINT *pNumViewports, D3D11_VIEWPORT *pViewports) { m_pRealContext->RSGetViewports(pNumViewports, pViewports); if(pViewports) RDCASSERT(memcmp(pViewports, m_CurrentPipelineState->RS.Viewports, sizeof(D3D11_VIEWPORT) * (*pNumViewports)) == 0); } void WrappedID3D11DeviceContext::RSGetScissorRects(UINT *pNumRects, D3D11_RECT *pRects) { m_pRealContext->RSGetScissorRects(pNumRects, pRects); if(pRects) RDCASSERT(memcmp(pRects, m_CurrentPipelineState->RS.Scissors, sizeof(D3D11_RECT) * (*pNumRects)) == 0); } void WrappedID3D11DeviceContext::RSGetState(ID3D11RasterizerState **ppRasterizerState) { if(ppRasterizerState) { ID3D11RasterizerState *real = NULL; m_pRealContext->RSGetState(&real); if(real != NULL) { real->Release(); ID3D11DeviceChild *state = m_pDevice->GetResourceManager()->GetWrapper(real); *ppRasterizerState = (ID3D11RasterizerState *)state; (*ppRasterizerState)->AddRef(); } else { *ppRasterizerState = NULL; } RDCASSERT(*ppRasterizerState == m_CurrentPipelineState->RS.State); } } template bool WrappedID3D11DeviceContext::Serialise_RSSetViewports(SerialiserType &ser, UINT NumViewports, const D3D11_VIEWPORT *pViewports) { SERIALISE_ELEMENT(NumViewports); SERIALISE_ELEMENT_ARRAY(pViewports, NumViewports); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordViewportStats(NumViewports, pViewports); m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Viewports, pViewports, 0, NumViewports); m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumViews, NumViewports); m_pRealContext->RSSetViewports(NumViewports, pViewports); VerifyState(); } return true; } void WrappedID3D11DeviceContext::RSSetViewports(UINT NumViewports, const D3D11_VIEWPORT *pViewports) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->RSSetViewports(NumViewports, pViewports)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::RSSetViewports); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_RSSetViewports(GET_SERIALISER, NumViewports, pViewports); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Viewports, pViewports, 0, NumViewports); m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumViews, NumViewports); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_RSSetScissorRects(SerialiserType &ser, UINT NumRects, const D3D11_RECT *pRects) { SERIALISE_ELEMENT(NumRects); SERIALISE_ELEMENT_ARRAY(pRects, NumRects); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordScissorStats(NumRects, pRects); m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Scissors, pRects, 0, NumRects); m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumScissors, NumRects); m_pRealContext->RSSetScissorRects(NumRects, pRects); VerifyState(); } return true; } void WrappedID3D11DeviceContext::RSSetScissorRects(UINT NumRects, const D3D11_RECT *pRects) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->RSSetScissorRects(NumRects, pRects)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::RSSetScissorRects); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_RSSetScissorRects(GET_SERIALISER, NumRects, pRects); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.Scissors, pRects, 0, NumRects); m_CurrentPipelineState->Change(m_CurrentPipelineState->RS.NumScissors, NumRects); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_RSSetState(SerialiserType &ser, ID3D11RasterizerState *pRasterizerState) { SERIALISE_ELEMENT(pRasterizerState); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordRasterizationStats(pRasterizerState); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->RS.State, pRasterizerState); m_pRealContext->RSSetState(UNWRAP(WrappedID3D11RasterizerState2, pRasterizerState)); VerifyState(); } return true; } void WrappedID3D11DeviceContext::RSSetState(ID3D11RasterizerState *pRasterizerState) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->RSSetState( (ID3D11RasterizerState *)UNWRAP(WrappedID3D11RasterizerState2, pRasterizerState))); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::RSSetState); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_RSSetState(GET_SERIALISER, pRasterizerState); MarkResourceReferenced(GetIDForResource(pRasterizerState), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->RS.State, pRasterizerState); VerifyState(); } #pragma endregion Rasterizer #pragma region Pixel Shader void WrappedID3D11DeviceContext::PSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) { if(ppConstantBuffers) { ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; m_pRealContext->PSGetConstantBuffers(StartSlot, NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppConstantBuffers[i]); RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->PS.ConstantBuffers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::PSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) { if(ppShaderResourceViews) { ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->PSGetShaderResources(StartSlot, NumViews, real); for(UINT i = 0; i < NumViews; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppShaderResourceViews[i]); RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->PS.SRVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::PSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) { if(ppSamplers) { ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; m_pRealContext->PSGetSamplers(StartSlot, NumSamplers, real); for(UINT i = 0; i < NumSamplers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSamplers[i]); RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->PS.Samplers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::PSGetShader(ID3D11PixelShader **ppPixelShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) { if(ppPixelShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) return; ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; UINT numInsts = 0; ID3D11PixelShader *realShader = NULL; m_pRealContext->PSGetShader(&realShader, realInsts, &numInsts); SAFE_RELEASE_NOCLEAR(realShader); for(UINT i = 0; i < numInsts; i++) SAFE_RELEASE_NOCLEAR(realInsts[i]); if(ppPixelShader) { *ppPixelShader = (ID3D11PixelShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); SAFE_ADDREF(*ppPixelShader); RDCASSERT(*ppPixelShader == m_CurrentPipelineState->PS.Object); } if(ppClassInstances) { for(UINT i = 0; i < numInsts; i++) { ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); SAFE_ADDREF(ppClassInstances[i]); RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->PS.Instances[i]); } } if(pNumClassInstances) { *pNumClassInstances = numInsts; } } template bool WrappedID3D11DeviceContext::Serialise_PSSetConstantBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppConstantBuffers, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordConstantStats(ShaderStage::Pixel, NumBuffers, ppConstantBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBCounts, NullCBCounts, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); m_pRealContext->PSSetConstantBuffers(StartSlot, NumBuffers, bufs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::PSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) { if(ppConstantBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); } SERIALISE_TIME_CALL(m_pRealContext->PSSetConstantBuffers(StartSlot, NumBuffers, bufs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PSSetConstantBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PSSetConstantBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppConstantBuffers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.CBCounts, NullCBCounts, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_PSSetShaderResources( SerialiserType &ser, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppShaderResourceViews, NumViews); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordResourceStats(ShaderStage::Pixel, NumViews, ppShaderResourceViews); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.SRVs, ppShaderResourceViews, StartSlot, NumViews); ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); m_pRealContext->PSSetShaderResources(StartSlot, NumViews, SRVs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::PSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) { if(ppShaderResourceViews[i] && IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppShaderResourceViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppShaderResourceViews[i]), eFrameRef_Read); } SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); } SERIALISE_TIME_CALL(m_pRealContext->PSSetShaderResources(StartSlot, NumViews, SRVs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PSSetShaderResources); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PSSetShaderResources(GET_SERIALISER, StartSlot, NumViews, ppShaderResourceViews); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.SRVs, ppShaderResourceViews, StartSlot, NumViews); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_PSSetSamplers(SerialiserType &ser, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumSamplers); SERIALISE_ELEMENT_ARRAY(ppSamplers, NumSamplers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordSamplerStats(ShaderStage::Pixel, NumSamplers, ppSamplers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Samplers, ppSamplers, StartSlot, NumSamplers); ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); m_pRealContext->PSSetSamplers(StartSlot, NumSamplers, samps); VerifyState(); } return true; } void WrappedID3D11DeviceContext::PSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) { if(ppSamplers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppSamplers[i]), eFrameRef_Read); samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); } SERIALISE_TIME_CALL(m_pRealContext->PSSetSamplers(StartSlot, NumSamplers, samps)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PSSetSamplers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PSSetSamplers(GET_SERIALISER, StartSlot, NumSamplers, ppSamplers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Samplers, ppSamplers, StartSlot, NumSamplers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_PSSetShader(SerialiserType &ser, ID3D11PixelShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { SERIALISE_ELEMENT(pShader); SERIALISE_ELEMENT_ARRAY(ppClassInstances, NumClassInstances); SERIALISE_ELEMENT(NumClassInstances); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordShaderStats(ShaderStage::Pixel, m_CurrentPipelineState->PS.Object, pShader); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Instances, ppClassInstances, 0, NumClassInstances); m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Object, (ID3D11DeviceChild *)pShader); ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); m_pRealContext->PSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); VerifyState(); } return true; } void WrappedID3D11DeviceContext::PSSetShader(ID3D11PixelShader *pPixelShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; if(ppClassInstances && NumClassInstances > 0) for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); SERIALISE_TIME_CALL(m_pRealContext->PSSetShader( UNWRAP(WrappedID3D11Shader, pPixelShader), insts, NumClassInstances)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PSSetShader); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PSSetShader(GET_SERIALISER, pPixelShader, ppClassInstances, NumClassInstances); MarkResourceReferenced(GetIDForResource(pPixelShader), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Object, (ID3D11DeviceChild *)pPixelShader); m_CurrentPipelineState->Change(m_CurrentPipelineState->PS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->PS.Instances, ppClassInstances, 0, NumClassInstances); VerifyState(); } #pragma endregion Pixel Shader #pragma region Output Merger void WrappedID3D11DeviceContext::OMGetRenderTargets(UINT NumViews, ID3D11RenderTargetView **ppRenderTargetViews, ID3D11DepthStencilView **ppDepthStencilView) { if(ppRenderTargetViews == NULL && ppDepthStencilView == NULL) return; ID3D11RenderTargetView *rtv[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; ID3D11DepthStencilView *dsv = NULL; m_pRealContext->OMGetRenderTargets(NumViews, rtv, &dsv); for(UINT i = 0; i < NumViews; i++) SAFE_RELEASE_NOCLEAR(rtv[i]); SAFE_RELEASE_NOCLEAR(dsv); if(ppRenderTargetViews) { for(UINT i = 0; i < NumViews; i++) { ppRenderTargetViews[i] = (ID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetWrapper(rtv[i]); SAFE_ADDREF(ppRenderTargetViews[i]); RDCASSERT(ppRenderTargetViews[i] == m_CurrentPipelineState->OM.RenderTargets[i]); } } if(ppDepthStencilView) { *ppDepthStencilView = (ID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetWrapper(dsv); SAFE_ADDREF(*ppDepthStencilView); RDCASSERT(*ppDepthStencilView == m_CurrentPipelineState->OM.DepthView); } } void WrappedID3D11DeviceContext::OMGetRenderTargetsAndUnorderedAccessViews( UINT NumRTVs, ID3D11RenderTargetView **ppRenderTargetViews, ID3D11DepthStencilView **ppDepthStencilView, UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView **ppUnorderedAccessViews) { if(ppRenderTargetViews == NULL && ppDepthStencilView == NULL && ppUnorderedAccessViews == NULL) return; ID3D11RenderTargetView *rtv[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; ID3D11UnorderedAccessView *uav[D3D11_1_UAV_SLOT_COUNT] = {0}; ID3D11DepthStencilView *dsv = NULL; m_pRealContext->OMGetRenderTargetsAndUnorderedAccessViews(NumRTVs, rtv, &dsv, UAVStartSlot, NumUAVs, uav); for(UINT i = 0; i < NumRTVs; i++) SAFE_RELEASE_NOCLEAR(rtv[i]); SAFE_RELEASE_NOCLEAR(dsv); for(UINT i = 0; i < NumUAVs; i++) SAFE_RELEASE_NOCLEAR(uav[i]); if(ppRenderTargetViews) { for(UINT i = 0; i < NumRTVs; i++) { ppRenderTargetViews[i] = (ID3D11RenderTargetView *)m_pDevice->GetResourceManager()->GetWrapper(rtv[i]); SAFE_ADDREF(ppRenderTargetViews[i]); RDCASSERT(ppRenderTargetViews[i] == m_CurrentPipelineState->OM.RenderTargets[i]); } } if(ppDepthStencilView) { *ppDepthStencilView = (ID3D11DepthStencilView *)m_pDevice->GetResourceManager()->GetWrapper(dsv); SAFE_ADDREF(*ppDepthStencilView); RDCASSERT(*ppDepthStencilView == m_CurrentPipelineState->OM.DepthView); } if(ppUnorderedAccessViews) { for(UINT i = 0; i < NumUAVs; i++) { ppUnorderedAccessViews[i] = (ID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetWrapper(uav[i]); SAFE_ADDREF(ppUnorderedAccessViews[i]); RDCASSERT(ppUnorderedAccessViews[i] == m_CurrentPipelineState->OM.UAVs[i]); } } } void WrappedID3D11DeviceContext::OMGetBlendState(ID3D11BlendState **ppBlendState, FLOAT BlendFactor[4], UINT *pSampleMask) { ID3D11BlendState *real = NULL; m_pRealContext->OMGetBlendState(&real, BlendFactor, pSampleMask); SAFE_RELEASE_NOCLEAR(real); if(ppBlendState) { if(real != NULL) { ID3D11DeviceChild *state = m_pDevice->GetResourceManager()->GetWrapper(real); *ppBlendState = (ID3D11BlendState *)state; (*ppBlendState)->AddRef(); } else { *ppBlendState = NULL; } RDCASSERT(*ppBlendState == m_CurrentPipelineState->OM.BlendState); } if(BlendFactor) RDCASSERT(memcmp(BlendFactor, m_CurrentPipelineState->OM.BlendFactor, sizeof(float) * 4) == 0); if(pSampleMask) RDCASSERT(*pSampleMask == m_CurrentPipelineState->OM.SampleMask); } void WrappedID3D11DeviceContext::OMGetDepthStencilState(ID3D11DepthStencilState **ppDepthStencilState, UINT *pStencilRef) { ID3D11DepthStencilState *real = NULL; m_pRealContext->OMGetDepthStencilState(&real, pStencilRef); SAFE_RELEASE_NOCLEAR(real); if(ppDepthStencilState) { if(real != NULL) { *ppDepthStencilState = (ID3D11DepthStencilState *)m_pDevice->GetResourceManager()->GetWrapper(real); SAFE_ADDREF(*ppDepthStencilState); } else { *ppDepthStencilState = NULL; } RDCASSERT(*ppDepthStencilState == m_CurrentPipelineState->OM.DepthStencilState); } if(pStencilRef) RDCASSERT(*pStencilRef == m_CurrentPipelineState->OM.StencRef); } template bool WrappedID3D11DeviceContext::Serialise_OMSetRenderTargets( SerialiserType &ser, UINT NumViews, ID3D11RenderTargetView *const *ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) { SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppRenderTargetViews, NumViews); SERIALISE_ELEMENT(pDepthStencilView); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; for(UINT i = 0; i < NumViews; i++) RTs[i] = ppRenderTargetViews[i]; if(m_CurrentPipelineState->ValidOutputMerger(ppRenderTargetViews, NumViews, pDepthStencilView, NULL, 0)) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RTs, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); } ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT] = {0}; m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_1_UAV_SLOT_COUNT); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, NumViews); for(UINT i = 0; i < NumViews; i++) RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, RTs[i]); if(IsLoading(m_State)) RecordOutputMergerStats(NumViews, RTs, pDepthStencilView, 0, 0, NULL); m_pRealContext->OMSetRenderTargets(NumViews, RTs, UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView)); VerifyState(); } return true; } void WrappedID3D11DeviceContext::OMSetRenderTargets(UINT NumViews, ID3D11RenderTargetView *const *ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; for(UINT i = 0; i < NumViews && ppRenderTargetViews; i++) RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, ppRenderTargetViews[i]); SERIALISE_TIME_CALL(m_pRealContext->OMSetRenderTargets( NumViews, RTs, UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView))); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::OMSetRenderTargets); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_OMSetRenderTargets(GET_SERIALISER, NumViews, ppRenderTargetViews, pDepthStencilView); m_ContextRecord->AddChunk(scope.Get()); } for(UINT i = 0; i < NumViews && ppRenderTargetViews; i++) RTs[i] = ppRenderTargetViews[i]; // this function always sets all render targets if(m_CurrentPipelineState->ValidOutputMerger(RTs, NumViews, pDepthStencilView, NULL, 0)) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RTs, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, NumViews); } ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT] = {0}; m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_1_UAV_SLOT_COUNT); for(UINT i = 0; i < NumViews; i++) { if(ppRenderTargetViews && ppRenderTargetViews[i]) { if(IsCaptureMode(m_State)) { // technically this isn't dirty until the draw call, but let's be conservative // to avoid having to track "possibly" dirty resources. // Besides, it's unlikely an application will set an output then not draw to it if(IsBackgroundCapturing(m_State)) MarkDirtyResource(GetViewResourceResID(ppRenderTargetViews[i])); else if(IsActiveCapturing(m_State)) m_MissingTracks.insert(GetViewResourceResID(ppRenderTargetViews[i])); } RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, ppRenderTargetViews[i]); } } if(pDepthStencilView && IsCaptureMode(m_State)) { if(IsBackgroundCapturing(m_State)) MarkDirtyResource(GetViewResourceResID(pDepthStencilView)); else if(IsActiveCapturing(m_State)) m_MissingTracks.insert(GetViewResourceResID(pDepthStencilView)); } if(IsActiveCapturing(m_State)) { // make sure to mark resources referenced even if the OM state is invalid, so they aren't // eliminated from the capture (which might make this combination valid on replay without some // of the targets!) for(UINT i = 0; i < NumViews; i++) { if(ppRenderTargetViews && ppRenderTargetViews[i]) { MarkResourceReferenced(GetIDForResource(ppRenderTargetViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppRenderTargetViews[i]), eFrameRef_Write); } } if(pDepthStencilView) { MarkResourceReferenced(GetIDForResource(pDepthStencilView), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(pDepthStencilView), eFrameRef_Write); } } VerifyState(); } // some helper enums with custom stringise to handle special cases enum D3D11RTVCount { }; DECLARE_REFLECTION_ENUM(D3D11RTVCount); template <> std::string DoStringise(const D3D11RTVCount &el) { RDCCOMPILE_ASSERT(sizeof(D3D11RTVCount) == sizeof(uint32_t), "Enum isn't uint sized"); if(el == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) return "D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL"; return ToStr(uint32_t(el)); } enum D3D11UAVCount { }; DECLARE_REFLECTION_ENUM(D3D11UAVCount); template <> std::string DoStringise(const D3D11UAVCount &el) { RDCCOMPILE_ASSERT(sizeof(D3D11UAVCount) == sizeof(uint32_t), "Enum isn't uint sized"); if(el == D3D11_KEEP_UNORDERED_ACCESS_VIEWS) return "D3D11_KEEP_UNORDERED_ACCESS_VIEWS"; return ToStr(uint32_t(el)); } template bool WrappedID3D11DeviceContext::Serialise_OMSetRenderTargetsAndUnorderedAccessViews( SerialiserType &ser, UINT NumRTVs, ID3D11RenderTargetView *const *ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView, UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, const UINT *pUAVInitialCounts) { // cast to a special enum so we print the two 'keep' constants nicely SERIALISE_ELEMENT_TYPED(D3D11RTVCount, NumRTVs); // handle special values for counts const bool KeepRTVs = (NumRTVs == D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL); const bool ModifyRTVs = !KeepRTVs; if(!ModifyRTVs) NumRTVs = 0; SERIALISE_ELEMENT_ARRAY(ppRenderTargetViews, NumRTVs); SERIALISE_ELEMENT(pDepthStencilView); SERIALISE_ELEMENT(UAVStartSlot); SERIALISE_ELEMENT_TYPED(D3D11UAVCount, NumUAVs); const bool KeepUAVs = (NumUAVs == D3D11_KEEP_UNORDERED_ACCESS_VIEWS); const bool ModifyUAVs = !KeepUAVs; if(!ModifyUAVs) NumUAVs = 0; SERIALISE_ELEMENT_ARRAY(ppUnorderedAccessViews, NumUAVs); SERIALISE_ELEMENT_ARRAY(pUAVInitialCounts, NumUAVs); RDCASSERT(ModifyRTVs || ModifyUAVs); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { // any bind of RTVs or UAVs implicitly NULLs out the remaining slots, so we don't want to just // change the bindings we were passed, we want to always change ALL bindings, and just set the // subset that we were passed ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumRTVs && ModifyRTVs; i++) RTs[i] = ppRenderTargetViews[i]; for(UINT i = 0; i < NumUAVs && ModifyUAVs; i++) UAVs[i] = ppUnorderedAccessViews[i]; if(ModifyRTVs) { ID3D11UnorderedAccessView *const *srcUAVs = ppUnorderedAccessViews; UINT srcUAVcount = NumUAVs; if(!ModifyUAVs) { srcUAVs = m_CurrentPipelineState->OM.UAVs; srcUAVcount = D3D11_1_UAV_SLOT_COUNT; // if we're not modifying the UAVs but NumRTVs > oldUAVStartSlot then we unbind any // overlapped UAVs. if(NumRTVs > m_CurrentPipelineState->OM.UAVStartSlot) { UINT diff = NumRTVs - m_CurrentPipelineState->OM.UAVStartSlot; srcUAVcount -= diff; srcUAVs += diff; } } if(m_CurrentPipelineState->ValidOutputMerger(ppRenderTargetViews, NumRTVs, pDepthStencilView, srcUAVs, srcUAVcount)) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RTs, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); if(!ModifyUAVs) { // set UAVStartSlot to NumRTVs m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, NumRTVs); if(NumRTVs > m_CurrentPipelineState->OM.UAVStartSlot) { UINT diff = NumRTVs - m_CurrentPipelineState->OM.UAVStartSlot; // release and unbind any UAVs that were unbound for(UINT i = 0; i < diff; i++) m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs[i], (ID3D11UnorderedAccessView *)NULL); // move the array down *without* changing any refs for(UINT i = 0; i < D3D11_1_UAV_SLOT_COUNT; i++) { if(i < D3D11_1_UAV_SLOT_COUNT - diff) { m_CurrentPipelineState->OM.UAVs[i] = m_CurrentPipelineState->OM.UAVs[i + diff]; } else { // NULL without ref'ing, since we just moved this down lower in the array m_CurrentPipelineState->OM.UAVs[i] = NULL; } } } } } } if(ModifyUAVs) { bool valid = false; if(ModifyRTVs) { valid = m_CurrentPipelineState->ValidOutputMerger( ppRenderTargetViews, NumRTVs, pDepthStencilView, ppUnorderedAccessViews, NumUAVs); } else { // if we're not modifying RTVs, any that are < UAVStartSlot get unbound so don't consider // for validity valid = m_CurrentPipelineState->ValidOutputMerger( m_CurrentPipelineState->OM.RenderTargets, UAVStartSlot, m_CurrentPipelineState->OM.DepthView, ppUnorderedAccessViews, NumUAVs); } if(valid) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_1_UAV_SLOT_COUNT); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, UAVStartSlot); // unbind any conflicting RTVS for(UINT i = UAVStartSlot; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++) m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets[i], (ID3D11RenderTargetView *)NULL); } } for(UINT i = 0; i < NumRTVs && ModifyRTVs; i++) RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, RTs[i]); for(UINT i = 0; i < NumUAVs && ModifyUAVs; i++) UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, UAVs[i]); if(ModifyRTVs) pDepthStencilView = UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView); else pDepthStencilView = NULL; if(IsLoading(m_State)) RecordOutputMergerStats(NumRTVs, RTs, pDepthStencilView, UAVStartSlot, NumUAVs, UAVs); m_pRealContext->OMSetRenderTargetsAndUnorderedAccessViews( ModifyRTVs ? NumRTVs : D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, RTs, pDepthStencilView, UAVStartSlot, ModifyUAVs ? NumUAVs : D3D11_KEEP_UNORDERED_ACCESS_VIEWS, UAVs, pUAVInitialCounts); VerifyState(); } return true; } void WrappedID3D11DeviceContext::OMSetRenderTargetsAndUnorderedAccessViews( UINT NumRTVs, ID3D11RenderTargetView *const *ppRenderTargetViews, ID3D11DepthStencilView *pDepthStencilView, UINT UAVStartSlot, UINT NumUAVs, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, const UINT *pUAVInitialCounts) { DrainAnnotationQueue(); m_EmptyCommandList = false; UINT StartSlot = UAVStartSlot; // D3D11 doesn't seem to complain about this case, but it messes our render state tracking so // ensure we don't blat over any RTs with 'empty' UAVs. if(NumUAVs == 0) { if(NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL) UAVStartSlot = RDCMAX(NumRTVs, UAVStartSlot); else UAVStartSlot = RDCMAX(m_CurrentPipelineState->OM.UAVStartSlot, UAVStartSlot); } ID3D11RenderTargetView *RTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT] = {0}; for(UINT i = 0; ppRenderTargetViews && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL && i < NumRTVs; i++) RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, ppRenderTargetViews[i]); for(UINT i = 0; ppUnorderedAccessViews && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS && i < NumUAVs; i++) UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, ppUnorderedAccessViews[i]); SERIALISE_TIME_CALL(m_pRealContext->OMSetRenderTargetsAndUnorderedAccessViews( NumRTVs, ppRenderTargetViews ? RTs : NULL, UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView), UAVStartSlot, NumUAVs, ppUnorderedAccessViews ? UAVs : NULL, pUAVInitialCounts)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::OMSetRenderTargetsAndUnorderedAccessViews); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_OMSetRenderTargetsAndUnorderedAccessViews(GET_SERIALISER, NumRTVs, ppRenderTargetViews, pDepthStencilView, UAVStartSlot, NumUAVs, ppUnorderedAccessViews, pUAVInitialCounts); m_ContextRecord->AddChunk(scope.Get()); } for(UINT i = 0; ppRenderTargetViews && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL && i < NumRTVs; i++) RTs[i] = ppRenderTargetViews[i]; for(UINT i = 0; ppUnorderedAccessViews && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS && i < NumUAVs; i++) UAVs[i] = ppUnorderedAccessViews[i]; const bool ModifyRTVs = NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL; const bool ModifyUAVs = NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS; if(ModifyRTVs) { ID3D11UnorderedAccessView **srcUAVs = ModifyUAVs ? UAVs : m_CurrentPipelineState->OM.UAVs; UINT srcUAVcount = ModifyUAVs ? NumUAVs : D3D11_1_UAV_SLOT_COUNT; if(m_CurrentPipelineState->ValidOutputMerger(ppRenderTargetViews, NumRTVs, pDepthStencilView, srcUAVs, srcUAVcount)) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, RTs, 0, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT); m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.DepthView, pDepthStencilView); } if(IsActiveCapturing(m_State)) { // make sure to mark resources referenced if the OM state is invalid, so they aren't // eliminated from the // log (which might make this combination valid on replay without some of the targets!) for(UINT i = 0; i < NumRTVs; i++) { if(ppRenderTargetViews && ppRenderTargetViews[i]) { MarkResourceReferenced(GetIDForResource(ppRenderTargetViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppRenderTargetViews[i]), eFrameRef_Read); } } if(pDepthStencilView) { MarkResourceReferenced(GetIDForResource(pDepthStencilView), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(pDepthStencilView), eFrameRef_Read); } } } if(ModifyUAVs) { bool valid = false; if(ModifyRTVs) valid = m_CurrentPipelineState->ValidOutputMerger(RTs, NumRTVs, pDepthStencilView, UAVs, NumUAVs); else valid = m_CurrentPipelineState->ValidOutputMerger( m_CurrentPipelineState->OM.RenderTargets, D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT, m_CurrentPipelineState->OM.DepthView, UAVs, NumUAVs); if(valid) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.UAVs, UAVs, 0, D3D11_1_UAV_SLOT_COUNT); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.UAVStartSlot, UAVStartSlot); } if(IsActiveCapturing(m_State)) { // make sure to mark resources referenced if the OM state is invalid, so they aren't // eliminated from the // log (which might make this combination valid on replay without some of the targets!) for(UINT i = 0; i < NumUAVs; i++) { if(UAVs[i]) { MarkResourceReferenced(GetIDForResource(UAVs[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(UAVs[i]), eFrameRef_Read); } } } } // invalid case where UAV/RTV overlap, UAV seems to take precedence bool UAVOverlap = (NumUAVs > 0 && NumUAVs <= D3D11_1_UAV_SLOT_COUNT && NumRTVs > 0 && NumRTVs <= D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT && StartSlot < NumRTVs); if(UAVOverlap) { ID3D11RenderTargetView *NullRTs[D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT] = {0}; // unset any RTs overlapping with the UAV range m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->OM.RenderTargets, NullRTs, StartSlot, RDCMIN(NumUAVs, D3D11_1_UAV_SLOT_COUNT - StartSlot)); } for(UINT i = 0; ppRenderTargetViews && NumRTVs != D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL && i < NumRTVs; i++) { if(ppRenderTargetViews[i] && IsCaptureMode(m_State)) { // technically this isn't dirty until the draw call, but let's be conservative // to avoid having to track "possibly" dirty resources. // Besides, it's unlikely an application will set an output then not draw to it if(IsBackgroundCapturing(m_State)) MarkDirtyResource(GetViewResourceResID(ppRenderTargetViews[i])); else if(IsActiveCapturing(m_State)) m_MissingTracks.insert(GetViewResourceResID(ppRenderTargetViews[i])); } RTs[i] = UNWRAP(WrappedID3D11RenderTargetView1, ppRenderTargetViews[i]); } for(UINT i = 0; ppUnorderedAccessViews && NumUAVs != D3D11_KEEP_UNORDERED_ACCESS_VIEWS && i < NumUAVs; i++) { if(ppUnorderedAccessViews[i] && IsCaptureMode(m_State)) { if(IsBackgroundCapturing(m_State)) MarkDirtyResource(GetViewResourceResID(ppUnorderedAccessViews[i])); else if(IsActiveCapturing(m_State)) m_MissingTracks.insert(GetViewResourceResID(ppUnorderedAccessViews[i])); } UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, ppUnorderedAccessViews[i]); } if(pDepthStencilView && IsCaptureMode(m_State)) { if(IsBackgroundCapturing(m_State)) MarkDirtyResource(GetViewResourceResID(pDepthStencilView)); else if(IsActiveCapturing(m_State)) m_MissingTracks.insert(GetViewResourceResID(pDepthStencilView)); } VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_OMSetBlendState(SerialiserType &ser, ID3D11BlendState *pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) { SERIALISE_ELEMENT(pBlendState); SERIALISE_ELEMENT_ARRAY(BlendFactor, 4); SERIALISE_ELEMENT(SampleMask); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { FLOAT DefaultBlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; const FLOAT *SafeBlendFactor = BlendFactor ? BlendFactor : DefaultBlendFactor; if(IsLoading(m_State)) RecordBlendStats(pBlendState, SafeBlendFactor, SampleMask); { m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.BlendState, pBlendState); m_pRealContext->OMSetBlendState(UNWRAP(WrappedID3D11BlendState1, pBlendState), BlendFactor, SampleMask); } m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.BlendFactor, SafeBlendFactor, 0, 4); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.SampleMask, SampleMask); VerifyState(); } return true; } void WrappedID3D11DeviceContext::OMSetBlendState(ID3D11BlendState *pBlendState, const FLOAT BlendFactor[4], UINT SampleMask) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->OMSetBlendState( (ID3D11BlendState *)UNWRAP(WrappedID3D11BlendState1, pBlendState), BlendFactor, SampleMask)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::OMSetBlendState); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_OMSetBlendState(GET_SERIALISER, pBlendState, BlendFactor, SampleMask); MarkResourceReferenced(GetIDForResource(pBlendState), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } FLOAT DefaultBlendFactor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.BlendState, pBlendState); if(BlendFactor != NULL) m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.BlendFactor, BlendFactor, 0, 4); else m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.BlendFactor, DefaultBlendFactor, 0, 4); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.SampleMask, SampleMask); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_OMSetDepthStencilState( SerialiserType &ser, ID3D11DepthStencilState *pDepthStencilState, UINT StencilRef) { SERIALISE_ELEMENT(pDepthStencilState); SERIALISE_ELEMENT(StencilRef); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordDepthStencilStats(pDepthStencilState, StencilRef); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.DepthStencilState, pDepthStencilState); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.StencRef, StencilRef & 0xff); m_pRealContext->OMSetDepthStencilState( UNWRAP(WrappedID3D11DepthStencilState, pDepthStencilState), StencilRef); VerifyState(); } return true; } void WrappedID3D11DeviceContext::OMSetDepthStencilState(ID3D11DepthStencilState *pDepthStencilState, UINT StencilRef) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->OMSetDepthStencilState( UNWRAP(WrappedID3D11DepthStencilState, pDepthStencilState), StencilRef)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::OMSetDepthStencilState); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_OMSetDepthStencilState(GET_SERIALISER, pDepthStencilState, StencilRef); MarkResourceReferenced(GetIDForResource(pDepthStencilState), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->OM.DepthStencilState, pDepthStencilState); m_CurrentPipelineState->Change(m_CurrentPipelineState->OM.StencRef, StencilRef & 0xff); VerifyState(); } #pragma endregion Output Merger #pragma region Draw template void WrappedID3D11DeviceContext::Serialise_DebugMessages(SerialiserType &ser) { std::vector DebugMessages; m_EmptyCommandList = false; // only grab debug messages for the immediate context, without serialising all // API use there's no way to find out which messages come from which context :(. if(ser.IsWriting() && IsActiveCapturing(m_State) && GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) { DebugMessages = m_pDevice->GetDebugMessages(); } SERIALISE_ELEMENT(DebugMessages); // hide empty sets of messages. if(ser.IsReading() && DebugMessages.empty()) ser.Hidden(); if(ser.IsReading() && IsLoading(m_State)) { for(DebugMessage &msg : DebugMessages) { msg.eventId = m_CurEventID; m_pDevice->AddDebugMessage(msg); } } } template bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstanced( SerialiserType &ser, UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) { SERIALISE_ELEMENT(IndexCountPerInstance); SERIALISE_ELEMENT(InstanceCount); SERIALISE_ELEMENT(StartIndexLocation); SERIALISE_ELEMENT(BaseVertexLocation); SERIALISE_ELEMENT(StartInstanceLocation); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_pRealContext->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); if(IsLoading(m_State)) { RecordDrawStats(true, false, InstanceCount); AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("DrawIndexedInstanced(%u, %u)", IndexCountPerInstance, InstanceCount); draw.numIndices = IndexCountPerInstance; draw.numInstances = InstanceCount; draw.indexOffset = StartIndexLocation; draw.baseVertex = BaseVertexLocation; draw.instanceOffset = StartInstanceLocation; draw.flags |= DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::UseIBuffer; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DrawIndexedInstanced(UINT IndexCountPerInstance, UINT InstanceCount, UINT StartIndexLocation, INT BaseVertexLocation, UINT StartInstanceLocation) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DrawIndexedInstanced(IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DrawIndexedInstanced); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DrawIndexedInstanced(GET_SERIALISER, IndexCountPerInstance, InstanceCount, StartIndexLocation, BaseVertexLocation, StartInstanceLocation); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } template bool WrappedID3D11DeviceContext::Serialise_DrawInstanced(SerialiserType &ser, UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) { SERIALISE_ELEMENT(VertexCountPerInstance); SERIALISE_ELEMENT(InstanceCount); SERIALISE_ELEMENT(StartVertexLocation); SERIALISE_ELEMENT(StartInstanceLocation); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_pRealContext->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); if(IsLoading(m_State)) { RecordDrawStats(true, false, InstanceCount); AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("DrawInstanced(%u, %u)", VertexCountPerInstance, InstanceCount); draw.numIndices = VertexCountPerInstance; draw.numInstances = InstanceCount; draw.vertexOffset = StartVertexLocation; draw.instanceOffset = StartInstanceLocation; draw.flags |= DrawFlags::Drawcall | DrawFlags::Instanced; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DrawInstanced(UINT VertexCountPerInstance, UINT InstanceCount, UINT StartVertexLocation, UINT StartInstanceLocation) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DrawInstanced(VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DrawInstanced); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DrawInstanced(GET_SERIALISER, VertexCountPerInstance, InstanceCount, StartVertexLocation, StartInstanceLocation); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } template bool WrappedID3D11DeviceContext::Serialise_DrawIndexed(SerialiserType &ser, UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) { SERIALISE_ELEMENT(IndexCount); SERIALISE_ELEMENT(StartIndexLocation); SERIALISE_ELEMENT(BaseVertexLocation); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_pRealContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation); if(IsLoading(m_State)) { RecordDrawStats(false, false, 1); AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("DrawIndexed(%u)", IndexCount); draw.numIndices = IndexCount; draw.baseVertex = BaseVertexLocation; draw.indexOffset = StartIndexLocation; draw.flags |= DrawFlags::Drawcall | DrawFlags::UseIBuffer; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DrawIndexed(UINT IndexCount, UINT StartIndexLocation, INT BaseVertexLocation) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DrawIndexed(IndexCount, StartIndexLocation, BaseVertexLocation)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DrawIndexed); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DrawIndexed(GET_SERIALISER, IndexCount, StartIndexLocation, BaseVertexLocation); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } template bool WrappedID3D11DeviceContext::Serialise_Draw(SerialiserType &ser, UINT VertexCount, UINT StartVertexLocation) { SERIALISE_ELEMENT(VertexCount); SERIALISE_ELEMENT(StartVertexLocation); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_pRealContext->Draw(VertexCount, StartVertexLocation); if(IsLoading(m_State)) { RecordDrawStats(false, false, 1); AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("Draw(%u)", VertexCount); draw.numIndices = VertexCount; draw.vertexOffset = StartVertexLocation; draw.flags |= DrawFlags::Drawcall; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::Draw(UINT VertexCount, UINT StartVertexLocation) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->Draw(VertexCount, StartVertexLocation)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Draw); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Draw(GET_SERIALISER, VertexCount, StartVertexLocation); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } template bool WrappedID3D11DeviceContext::Serialise_DrawAuto(SerialiserType &ser) { Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); uint64_t numVerts = 0; if(IsReplayingAndReading()) { // spec says that only the first vertex buffer is used if(m_CurrentPipelineState->IA.VBs[0] == NULL) { m_pDevice->AddDebugMessage(MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, "DrawAuto() with VB 0 set to NULL!"); } else { ResourceId id = GetIDForResource(m_CurrentPipelineState->IA.VBs[0]); StreamOutData &data = m_StreamOutCounters[id]; // if we have a query, the stream-out data for this DrawAuto was generated // in the captured frame, so we can do a legitimate DrawAuto() if(data.query) { // shouldn't still be bound on output RDCASSERT(!data.running); D3D11_QUERY_DATA_SO_STATISTICS numPrims; HRESULT hr = S_FALSE; do { hr = m_pRealContext->GetData(data.query, &numPrims, sizeof(D3D11_QUERY_DATA_SO_STATISTICS), 0); } while(hr == S_FALSE); if(m_CurrentPipelineState->IA.Topo == D3D11_PRIMITIVE_TOPOLOGY_POINTLIST) numVerts = numPrims.NumPrimitivesWritten; else if(m_CurrentPipelineState->IA.Topo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST) numVerts = numPrims.NumPrimitivesWritten * 2; else numVerts = numPrims.NumPrimitivesWritten * 3; m_pRealContext->DrawAuto(); } else { // otherwise use the cached value from the previous frame. if(m_CurrentPipelineState->IA.Topo == D3D11_PRIMITIVE_TOPOLOGY_POINTLIST) numVerts = data.numPrims; else if(m_CurrentPipelineState->IA.Topo == D3D11_PRIMITIVE_TOPOLOGY_LINELIST) numVerts = data.numPrims * 2; else numVerts = data.numPrims * 3; m_pRealContext->Draw((UINT)numVerts, 0); } } if(IsLoading(m_State)) { RecordDrawStats(false, false, 1); AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("DrawAuto(<%u>)", numVerts); draw.flags |= DrawFlags::Drawcall | DrawFlags::Auto; draw.numIndices = (uint32_t)numVerts; draw.vertexOffset = 0; draw.indexOffset = 0; draw.instanceOffset = 0; draw.numInstances = 1; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DrawAuto() { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DrawAuto()); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DrawAuto); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DrawAuto(GET_SERIALISER); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } template bool WrappedID3D11DeviceContext::Serialise_DrawIndexedInstancedIndirect(SerialiserType &ser, ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) { SERIALISE_ELEMENT(pBufferForArgs); SERIALISE_ELEMENT(AlignedByteOffsetForArgs); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pBufferForArgs) { m_pRealContext->DrawIndexedInstancedIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs); } if(IsLoading(m_State)) { AddEvent(); DrawcallDescription draw; std::string name = "DrawIndexedInstancedIndirect(-, -)"; if(pBufferForArgs) { struct DrawArgs { uint32_t IndexCountPerInstance; uint32_t InstanceCount; uint32_t StartIndexLocation; int32_t BaseVertexLocation; uint32_t StartInstanceLocation; }; bytebuf argarray; m_pDevice->GetDebugManager()->GetBufferData(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(DrawArgs), argarray); if(argarray.size() >= sizeof(DrawArgs)) { DrawArgs *args = (DrawArgs *)&argarray[0]; draw.numIndices = args->IndexCountPerInstance; draw.numInstances = args->InstanceCount; draw.indexOffset = args->StartIndexLocation; draw.baseVertex = args->BaseVertexLocation; draw.instanceOffset = args->StartInstanceLocation; RecordDrawStats(true, true, draw.numInstances); name = StringFormat::Fmt("DrawIndexedInstancedIndirect(<%u, %u>)", draw.numIndices, draw.numInstances); } else { name = "DrawIndexedInstancedIndirect()"; D3D11_BUFFER_DESC bufDesc; pBufferForArgs->GetDesc(&bufDesc); if(AlignedByteOffsetForArgs >= bufDesc.ByteWidth) { m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, StringFormat::Fmt("Call to DrawIndexedInstancedIndirect with buffer of %u " "bytes, but byte offset specified is %u bytes.", bufDesc.ByteWidth, AlignedByteOffsetForArgs)); } else if(AlignedByteOffsetForArgs + sizeof(DrawArgs) >= bufDesc.ByteWidth) { m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, StringFormat::Fmt("Call to DrawIndexedInstancedIndirect with buffer of %u " "bytes at offset of %u bytes, which leaves less than %u bytes " "for the arguments.", bufDesc.ByteWidth, AlignedByteOffsetForArgs, sizeof(DrawArgs))); } } m_ResourceUses[GetIDForResource(pBufferForArgs)].push_back( EventUsage(m_CurEventID, ResourceUsage::Indirect)); } draw.name = name; draw.flags |= DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::UseIBuffer | DrawFlags::Indirect; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DrawIndexedInstancedIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DrawIndexedInstancedIndirect( UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DrawIndexedInstancedIndirect); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DrawIndexedInstancedIndirect(GET_SERIALISER, pBufferForArgs, AlignedByteOffsetForArgs); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } if(pBufferForArgs && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(pBufferForArgs), eFrameRef_Read); } template bool WrappedID3D11DeviceContext::Serialise_DrawInstancedIndirect(SerialiserType &ser, ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) { SERIALISE_ELEMENT(pBufferForArgs); SERIALISE_ELEMENT(AlignedByteOffsetForArgs); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pBufferForArgs) { m_pRealContext->DrawInstancedIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs); } if(IsLoading(m_State)) { AddEvent(); DrawcallDescription draw; std::string name = "DrawInstancedIndirect(-, -)"; if(pBufferForArgs) { struct DrawArgs { uint32_t VertexCountPerInstance; uint32_t InstanceCount; uint32_t StartVertexLocation; uint32_t StartInstanceLocation; }; bytebuf argarray; m_pDevice->GetDebugManager()->GetBufferData(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(DrawArgs), argarray); if(argarray.size() >= sizeof(DrawArgs)) { DrawArgs *args = (DrawArgs *)&argarray[0]; draw.numIndices = args->VertexCountPerInstance; draw.numInstances = args->InstanceCount; draw.vertexOffset = args->StartVertexLocation; draw.instanceOffset = args->StartInstanceLocation; RecordDrawStats(true, true, draw.numInstances); name = StringFormat::Fmt("DrawInstancedIndirect(<%u, %u>)", draw.numIndices, draw.numInstances); } else { name = "DrawInstancedIndirect()"; D3D11_BUFFER_DESC bufDesc; pBufferForArgs->GetDesc(&bufDesc); if(AlignedByteOffsetForArgs >= bufDesc.ByteWidth) { m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, StringFormat::Fmt("Call to DrawIndexedInstancedIndirect with buffer of %u " "bytes, but byte offset specified is %u bytes.", bufDesc.ByteWidth, AlignedByteOffsetForArgs)); } else if(AlignedByteOffsetForArgs + sizeof(DrawArgs) >= bufDesc.ByteWidth) { m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, StringFormat::Fmt("Call to DrawIndexedInstancedIndirect with buffer of %u " "bytes at offset of %u bytes, which leaves less than %u bytes " "for the arguments.", bufDesc.ByteWidth, AlignedByteOffsetForArgs, sizeof(DrawArgs))); } } m_ResourceUses[GetIDForResource(pBufferForArgs)].push_back( EventUsage(m_CurEventID, ResourceUsage::Indirect)); } draw.name = name; draw.flags |= DrawFlags::Drawcall | DrawFlags::Instanced | DrawFlags::Indirect; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DrawInstancedIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DrawInstancedIndirect( UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DrawInstancedIndirect); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DrawInstancedIndirect(GET_SERIALISER, pBufferForArgs, AlignedByteOffsetForArgs); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } if(pBufferForArgs && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(pBufferForArgs), eFrameRef_Read); } #pragma endregion Draw #pragma region Compute Shader void WrappedID3D11DeviceContext::CSGetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer **ppConstantBuffers) { if(ppConstantBuffers) { ID3D11Buffer *real[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; m_pRealContext->CSGetConstantBuffers(StartSlot, NumBuffers, real); for(UINT i = 0; i < NumBuffers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppConstantBuffers[i] = (ID3D11Buffer *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppConstantBuffers[i]); RDCASSERT(ppConstantBuffers[i] == m_CurrentPipelineState->CS.ConstantBuffers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::CSGetShaderResources(UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView **ppShaderResourceViews) { if(ppShaderResourceViews) { ID3D11ShaderResourceView *real[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT] = {0}; m_pRealContext->CSGetShaderResources(StartSlot, NumViews, real); for(UINT i = 0; i < NumViews; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppShaderResourceViews[i] = (ID3D11ShaderResourceView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppShaderResourceViews[i]); RDCASSERT(ppShaderResourceViews[i] == m_CurrentPipelineState->CS.SRVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::CSGetUnorderedAccessViews( UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView **ppUnorderedAccessViews) { if(ppUnorderedAccessViews) { ID3D11UnorderedAccessView *real[D3D11_1_UAV_SLOT_COUNT] = {0}; m_pRealContext->CSGetUnorderedAccessViews(StartSlot, NumUAVs, real); for(UINT i = 0; i < NumUAVs; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppUnorderedAccessViews[i] = (ID3D11UnorderedAccessView *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppUnorderedAccessViews[i]); RDCASSERT(ppUnorderedAccessViews[i] == m_CurrentPipelineState->CSUAVs[i + StartSlot]); } } } void WrappedID3D11DeviceContext::CSGetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState **ppSamplers) { if(ppSamplers) { ID3D11SamplerState *real[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT] = {0}; m_pRealContext->CSGetSamplers(StartSlot, NumSamplers, real); for(UINT i = 0; i < NumSamplers; i++) { SAFE_RELEASE_NOCLEAR(real[i]); ppSamplers[i] = (ID3D11SamplerState *)m_pDevice->GetResourceManager()->GetWrapper(real[i]); SAFE_ADDREF(ppSamplers[i]); RDCASSERT(ppSamplers[i] == m_CurrentPipelineState->CS.Samplers[i + StartSlot]); } } } void WrappedID3D11DeviceContext::CSGetShader(ID3D11ComputeShader **ppComputeShader, ID3D11ClassInstance **ppClassInstances, UINT *pNumClassInstances) { if(ppComputeShader == NULL && ppClassInstances == NULL && pNumClassInstances == NULL) return; ID3D11ClassInstance *realInsts[D3D11_SHADER_MAX_INTERFACES] = {0}; UINT numInsts = 0; ID3D11ComputeShader *realShader = NULL; m_pRealContext->CSGetShader(&realShader, realInsts, &numInsts); SAFE_RELEASE_NOCLEAR(realShader); for(UINT i = 0; i < numInsts; i++) SAFE_RELEASE_NOCLEAR(realInsts[i]); if(ppComputeShader) { *ppComputeShader = (ID3D11ComputeShader *)m_pDevice->GetResourceManager()->GetWrapper(realShader); SAFE_ADDREF(*ppComputeShader); RDCASSERT(*ppComputeShader == m_CurrentPipelineState->CS.Object); } if(ppClassInstances) { for(UINT i = 0; i < numInsts; i++) { ppClassInstances[i] = (ID3D11ClassInstance *)m_pDevice->GetResourceManager()->GetWrapper(realInsts[i]); SAFE_ADDREF(ppClassInstances[i]); RDCASSERT(ppClassInstances[i] == m_CurrentPipelineState->CS.Instances[i]); } } if(pNumClassInstances) { *pNumClassInstances = numInsts; } } template bool WrappedID3D11DeviceContext::Serialise_CSSetConstantBuffers(SerialiserType &ser, UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumBuffers); SERIALISE_ELEMENT_ARRAY(ppConstantBuffers, NumBuffers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordConstantStats(ShaderStage::Compute, NumBuffers, ppConstantBuffers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBCounts, NullCBCounts, StartSlot, NumBuffers); ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT] = {0}; for(UINT i = 0; i < NumBuffers; i++) bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); m_pRealContext->CSSetConstantBuffers(StartSlot, NumBuffers, bufs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::CSSetConstantBuffers(UINT StartSlot, UINT NumBuffers, ID3D11Buffer *const *ppConstantBuffers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11Buffer *bufs[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT]; for(UINT i = 0; i < NumBuffers; i++) { if(ppConstantBuffers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppConstantBuffers[i]), eFrameRef_Read); bufs[i] = UNWRAP(WrappedID3D11Buffer, ppConstantBuffers[i]); } SERIALISE_TIME_CALL(m_pRealContext->CSSetConstantBuffers(StartSlot, NumBuffers, bufs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CSSetConstantBuffers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CSSetConstantBuffers(GET_SERIALISER, StartSlot, NumBuffers, ppConstantBuffers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.ConstantBuffers, ppConstantBuffers, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBOffsets, NullCBOffsets, StartSlot, NumBuffers); m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.CBCounts, NullCBCounts, StartSlot, NumBuffers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_CSSetShaderResources( SerialiserType &ser, UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumViews); SERIALISE_ELEMENT_ARRAY(ppShaderResourceViews, NumViews); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordResourceStats(ShaderStage::Compute, NumViews, ppShaderResourceViews); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.SRVs, ppShaderResourceViews, StartSlot, NumViews); ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); m_pRealContext->CSSetShaderResources(StartSlot, NumViews, SRVs); VerifyState(); } return true; } void WrappedID3D11DeviceContext::CSSetShaderResources( UINT StartSlot, UINT NumViews, ID3D11ShaderResourceView *const *ppShaderResourceViews) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ShaderResourceView *SRVs[D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT]; for(UINT i = 0; i < NumViews; i++) { if(ppShaderResourceViews[i] && IsActiveCapturing(m_State)) { MarkResourceReferenced(GetIDForResource(ppShaderResourceViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppShaderResourceViews[i]), eFrameRef_Read); } SRVs[i] = UNWRAP(WrappedID3D11ShaderResourceView1, ppShaderResourceViews[i]); } SERIALISE_TIME_CALL(m_pRealContext->CSSetShaderResources(StartSlot, NumViews, SRVs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CSSetShaderResources); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CSSetShaderResources(GET_SERIALISER, StartSlot, NumViews, ppShaderResourceViews); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.SRVs, ppShaderResourceViews, StartSlot, NumViews); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_CSSetUnorderedAccessViews( SerialiserType &ser, UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, const UINT *pUAVInitialCounts) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumUAVs); SERIALISE_ELEMENT_ARRAY(ppUnorderedAccessViews, NumUAVs); SERIALISE_ELEMENT_ARRAY(pUAVInitialCounts, NumUAVs); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->CSUAVs, ppUnorderedAccessViews, StartSlot, NumUAVs); ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT]; for(UINT i = 0; i < NumUAVs; i++) UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, ppUnorderedAccessViews[i]); // #mivance this isn't strictly correct... if(IsLoading(m_State)) RecordOutputMergerStats(0, NULL, NULL, StartSlot, NumUAVs, UAVs); m_pRealContext->CSSetUnorderedAccessViews(StartSlot, NumUAVs, UAVs, pUAVInitialCounts); VerifyState(); } return true; } void WrappedID3D11DeviceContext::CSSetUnorderedAccessViews( UINT StartSlot, UINT NumUAVs, ID3D11UnorderedAccessView *const *ppUnorderedAccessViews, const UINT *pUAVInitialCounts) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11UnorderedAccessView *UAVs[D3D11_1_UAV_SLOT_COUNT]; for(UINT i = 0; i < NumUAVs; i++) { if(ppUnorderedAccessViews[i] && IsCaptureMode(m_State)) { if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetViewResourceResID(ppUnorderedAccessViews[i])); } else if(IsActiveCapturing(m_State)) { m_MissingTracks.insert(GetViewResourceResID(ppUnorderedAccessViews[i])); MarkResourceReferenced(GetIDForResource(ppUnorderedAccessViews[i]), eFrameRef_Read); MarkResourceReferenced(GetViewResourceResID(ppUnorderedAccessViews[i]), eFrameRef_Read); } } UAVs[i] = UNWRAP(WrappedID3D11UnorderedAccessView1, ppUnorderedAccessViews[i]); } SERIALISE_TIME_CALL( m_pRealContext->CSSetUnorderedAccessViews(StartSlot, NumUAVs, UAVs, pUAVInitialCounts)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CSSetUnorderedAccessViews); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CSSetUnorderedAccessViews(GET_SERIALISER, StartSlot, NumUAVs, ppUnorderedAccessViews, pUAVInitialCounts); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefWrite(m_CurrentPipelineState->CSUAVs, ppUnorderedAccessViews, StartSlot, NumUAVs); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_CSSetSamplers(SerialiserType &ser, UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { SERIALISE_ELEMENT(StartSlot); SERIALISE_ELEMENT(NumSamplers); SERIALISE_ELEMENT_ARRAY(ppSamplers, NumSamplers); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordSamplerStats(ShaderStage::Compute, NumSamplers, ppSamplers); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Samplers, ppSamplers, StartSlot, NumSamplers); ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); m_pRealContext->CSSetSamplers(StartSlot, NumSamplers, samps); VerifyState(); } return true; } void WrappedID3D11DeviceContext::CSSetSamplers(UINT StartSlot, UINT NumSamplers, ID3D11SamplerState *const *ppSamplers) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11SamplerState *samps[D3D11_COMMONSHADER_SAMPLER_SLOT_COUNT]; for(UINT i = 0; i < NumSamplers; i++) { if(ppSamplers[i] && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(ppSamplers[i]), eFrameRef_Read); samps[i] = UNWRAP(WrappedID3D11SamplerState, ppSamplers[i]); } SERIALISE_TIME_CALL(m_pRealContext->CSSetSamplers(StartSlot, NumSamplers, samps)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CSSetSamplers); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CSSetSamplers(GET_SERIALISER, StartSlot, NumSamplers, ppSamplers); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Samplers, ppSamplers, StartSlot, NumSamplers); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_CSSetShader(SerialiserType &ser, ID3D11ComputeShader *pShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { SERIALISE_ELEMENT(pShader); SERIALISE_ELEMENT_ARRAY(ppClassInstances, NumClassInstances); SERIALISE_ELEMENT(NumClassInstances); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(IsLoading(m_State)) RecordShaderStats(ShaderStage::Compute, m_CurrentPipelineState->CS.Object, pShader); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Instances, ppClassInstances, 0, NumClassInstances); m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Object, (ID3D11DeviceChild *)pShader); ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); m_pRealContext->CSSetShader(UNWRAP(WrappedID3D11Shader, pShader), insts, NumClassInstances); VerifyState(); } return true; } void WrappedID3D11DeviceContext::CSSetShader(ID3D11ComputeShader *pComputeShader, ID3D11ClassInstance *const *ppClassInstances, UINT NumClassInstances) { DrainAnnotationQueue(); m_EmptyCommandList = false; ID3D11ClassInstance *insts[D3D11_SHADER_MAX_INTERFACES] = {0}; if(ppClassInstances && NumClassInstances > 0) for(UINT i = 0; i < NumClassInstances; i++) insts[i] = UNWRAP(WrappedID3D11ClassInstance, ppClassInstances[i]); SERIALISE_TIME_CALL(m_pRealContext->CSSetShader( UNWRAP(WrappedID3D11Shader, pComputeShader), insts, NumClassInstances)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CSSetShader); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CSSetShader(GET_SERIALISER, pComputeShader, ppClassInstances, NumClassInstances); MarkResourceReferenced(GetIDForResource(pComputeShader), eFrameRef_Read); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Object, (ID3D11DeviceChild *)pComputeShader); m_CurrentPipelineState->Change(m_CurrentPipelineState->CS.NumInstances, NumClassInstances); m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->CS.Instances, ppClassInstances, 0, NumClassInstances); VerifyState(); } #pragma endregion Compute Shader #pragma region Dispatch template bool WrappedID3D11DeviceContext::Serialise_Dispatch(SerialiserType &ser, UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) { SERIALISE_ELEMENT(ThreadGroupCountX); SERIALISE_ELEMENT(ThreadGroupCountY); SERIALISE_ELEMENT(ThreadGroupCountZ); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { m_pRealContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); if(IsLoading(m_State)) { RecordDispatchStats(false); AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("Dispatch(%u, %u, %u)", ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); draw.flags |= DrawFlags::Dispatch; draw.dispatchDimension[0] = ThreadGroupCountX; draw.dispatchDimension[1] = ThreadGroupCountY; draw.dispatchDimension[2] = ThreadGroupCountZ; if(ThreadGroupCountX == 0) m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::Medium, MessageSource::IncorrectAPIUse, "Dispatch call has ThreadGroup count X=0. This will do nothing, " "which is unusual for a non-indirect Dispatch. Did you mean X=1?"); if(ThreadGroupCountY == 0) m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::Medium, MessageSource::IncorrectAPIUse, "Dispatch call has ThreadGroup count Y=0. This will do nothing, " "which is unusual for a non-indirect Dispatch. Did you mean Y=1?"); if(ThreadGroupCountZ == 0) m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::Medium, MessageSource::IncorrectAPIUse, "Dispatch call has ThreadGroup count Z=0. This will do nothing, " "which is unusual for a non-indirect Dispatch. Did you mean Z=1?"); AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::Dispatch(UINT ThreadGroupCountX, UINT ThreadGroupCountY, UINT ThreadGroupCountZ) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL( m_pRealContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Dispatch); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Dispatch(GET_SERIALISER, ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } template bool WrappedID3D11DeviceContext::Serialise_DispatchIndirect(SerialiserType &ser, ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) { SERIALISE_ELEMENT(pBufferForArgs); SERIALISE_ELEMENT(AlignedByteOffsetForArgs); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pBufferForArgs) { m_pRealContext->DispatchIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs); } if(IsLoading(m_State)) { RecordDispatchStats(true); AddEvent(); DrawcallDescription draw; std::string name = "DispatchIndirect(-, -, -)"; if(pBufferForArgs) { struct DispatchArgs { UINT ThreadGroupCountX; UINT ThreadGroupCountY; UINT ThreadGroupCountZ; }; bytebuf argarray; m_pDevice->GetDebugManager()->GetBufferData(pBufferForArgs, AlignedByteOffsetForArgs, sizeof(DispatchArgs), argarray); if(argarray.size() >= sizeof(DispatchArgs)) { DispatchArgs *args = (DispatchArgs *)&argarray[0]; draw.dispatchDimension[0] = args->ThreadGroupCountX; draw.dispatchDimension[1] = args->ThreadGroupCountY; draw.dispatchDimension[2] = args->ThreadGroupCountZ; name = StringFormat::Fmt("DispatchIndirect(<%u, %u, %u>)", args->ThreadGroupCountX, args->ThreadGroupCountY, args->ThreadGroupCountZ); } else { name = "DispatchIndirect()"; D3D11_BUFFER_DESC bufDesc; pBufferForArgs->GetDesc(&bufDesc); if(AlignedByteOffsetForArgs >= bufDesc.ByteWidth) { m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, StringFormat::Fmt("Call to DispatchIndirect with buffer of %u " "bytes, but byte offset specified is %u bytes.", bufDesc.ByteWidth, AlignedByteOffsetForArgs)); } else if(AlignedByteOffsetForArgs + sizeof(DispatchArgs) >= bufDesc.ByteWidth) { m_pDevice->AddDebugMessage( MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, StringFormat::Fmt("Call to DispatchIndirect with buffer of %u " "bytes at offset of %u bytes, which leaves less than %u bytes " "for the arguments.", bufDesc.ByteWidth, AlignedByteOffsetForArgs, sizeof(DispatchArgs))); } } m_ResourceUses[GetIDForResource(pBufferForArgs)].push_back( EventUsage(m_CurEventID, ResourceUsage::Indirect)); } draw.name = name; draw.flags |= DrawFlags::Dispatch | DrawFlags::Indirect; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::DispatchIndirect(ID3D11Buffer *pBufferForArgs, UINT AlignedByteOffsetForArgs) { DrainAnnotationQueue(); MarkAPIActive(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->DispatchIndirect(UNWRAP(WrappedID3D11Buffer, pBufferForArgs), AlignedByteOffsetForArgs)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::DispatchIndirect); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_DispatchIndirect(GET_SERIALISER, pBufferForArgs, AlignedByteOffsetForArgs); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } if(pBufferForArgs && IsActiveCapturing(m_State)) MarkResourceReferenced(GetIDForResource(pBufferForArgs), eFrameRef_Read); } #pragma endregion Dispatch #pragma region Execute template bool WrappedID3D11DeviceContext::Serialise_ExecuteCommandList(SerialiserType &ser, ID3D11CommandList *pCommandList, BOOL RestoreContextState_) { SERIALISE_ELEMENT_LOCAL(CommandList, GetIDForResource(pCommandList)) .TypedAs("ID3D11CommandList *"); SERIALISE_ELEMENT_LOCAL(RestoreContextState, bool(RestoreContextState_ == TRUE)); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { // The serialise of exec happens at the start of the inserted linearised commands from the // deferred command list. So if we're going to restore context state afterwards, save off our // current state. This will be restored in the Serialise_PostExecuteCommandList chunk. if(RestoreContextState) { SAFE_DELETE(m_DeferredSavedState); m_DeferredSavedState = new D3D11RenderState(this); } // From the Docs: // "Immediate context state is cleared before and after a command list is executed. A command // list has no concept of inheritance." ClearState(); if(IsLoading(m_State)) { DrawcallDescription draw; draw.name = StringFormat::Fmt("ExecuteCommandList(List %s)", ToStr(CommandList).c_str()); draw.flags |= DrawFlags::CmdList; AddDrawcall(draw, true); } } return true; } template bool WrappedID3D11DeviceContext::Serialise_PostExecuteCommandList(SerialiserType &ser, ID3D11CommandList *pCommandList, BOOL RestoreContextState_) { SERIALISE_ELEMENT_LOCAL(CommandList, GetIDForResource(pCommandList)) .TypedAs("ID3D11CommandList *"); SERIALISE_ELEMENT_LOCAL(RestoreContextState, bool(RestoreContextState_ == TRUE)); // this is a 'fake' call we insert after executing, to give us a chance to restore the state. if(IsReplayingAndReading()) { if(RestoreContextState) { if(m_DeferredSavedState) { m_DeferredSavedState->ApplyState(this); SAFE_DELETE(m_DeferredSavedState); } else { RDCERR("Expected to have saved state from before execute saved, but didn't find one."); } } else { // if we don't restore the state, then it's cleared. There's no inheritance down from the // deferred context's state to the immediate context. ClearState(); } } return true; } void WrappedID3D11DeviceContext::ExecuteCommandList(ID3D11CommandList *pCommandList, BOOL RestoreContextState) { DrainAnnotationQueue(); m_EmptyCommandList = false; RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE); SERIALISE_TIME_CALL(m_pRealContext->ExecuteCommandList( UNWRAP(WrappedID3D11CommandList, pCommandList), RestoreContextState)); if(IsActiveCapturing(m_State)) { { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ExecuteCommandList); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ExecuteCommandList(GET_SERIALISER, pCommandList, RestoreContextState); m_ContextRecord->AddChunk(scope.Get()); } WrappedID3D11CommandList *wrapped = (WrappedID3D11CommandList *)pCommandList; if(!wrapped->IsCaptured()) { // we don't have this command list captured. This frame is no longer successful RDCWARN("Don't have command list %llu captured! This frame is unsuccessful.", wrapped->GetResourceID()); m_SuccessfulCapture = false; m_FailureReason = CaptureFailed_UncappedCmdlist; } else { RDCDEBUG("Executed successful command list %llu", wrapped->GetResourceID()); ResourceId contextId = wrapped->GetResourceID(); D3D11ResourceRecord *cmdListRecord = m_pDevice->GetResourceManager()->GetResourceRecord(contextId); RDCASSERT(cmdListRecord); // insert all the deferred chunks immediately following the execute chunk. m_ContextRecord->AppendFrom(cmdListRecord); cmdListRecord->AddResourceReferences(m_pDevice->GetResourceManager()); } // still update dirty resources for subsequent captures wrapped->MarkDirtyResources(m_MissingTracks); { // insert a chunk to let us know on replay that we finished the command list's // chunks and we can restore the state USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PostExecuteCommandList); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PostExecuteCommandList(GET_SERIALISER, pCommandList, RestoreContextState); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->MarkReferenced(this, false); } else if(IsBackgroundCapturing(m_State)) { WrappedID3D11CommandList *wrapped = (WrappedID3D11CommandList *)pCommandList; wrapped->MarkDirtyResources(m_pDevice->GetResourceManager()); } if(!RestoreContextState) m_CurrentPipelineState->Clear(); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_FinishCommandList(SerialiserType &ser, BOOL RestoreDeferredContextState_, ID3D11CommandList **ppCommandList) { SERIALISE_ELEMENT_LOCAL(RestoreDeferredContextState, bool(RestoreDeferredContextState_ == TRUE)); SERIALISE_ELEMENT_LOCAL(pCommandList, GetIDForResource(*ppCommandList)) .TypedAs("ID3D11CommandList *"); Serialise_DebugMessages(GET_SERIALISER); if(IsReplayingAndReading() && IsLoading(m_State)) { AddEvent(); DrawcallDescription draw; draw.name = StringFormat::Fmt("FinishCommandList(List %s)", ToStr(pCommandList).c_str()); draw.flags |= DrawFlags::CmdList; AddDrawcall(draw, true); m_pDevice->AddResource(pCommandList, ResourceType::CommandBuffer, "Command List"); // add the current deferred context ID as a parent m_pDevice->GetReplay()->GetResourceDesc(m_CurContextId).derivedResources.push_back(pCommandList); m_pDevice->GetReplay()->GetResourceDesc(pCommandList).parentResources.push_back(m_CurContextId); // don't include this as an 'initialisation chunk' m_pDevice->GetReplay()->GetResourceDesc(pCommandList).initialisationChunks.clear(); } return true; } template bool WrappedID3D11DeviceContext::Serialise_PostFinishCommandListSet(SerialiserType &ser, ID3D11CommandList *pCommandList) { SERIALISE_ELEMENT_LOCAL(CommandList, GetIDForResource(pCommandList)) .TypedAs("ID3D11CommandList *"); D3D11RenderState RenderState(*m_CurrentPipelineState); SERIALISE_ELEMENT(RenderState).Named("Initial Pipeline State"); SERIALISE_CHECK_READ_ERRORS(); // this is a 'fake' call we insert after finishing in a fresh deferred context, to allow us to // preserve the state after a previous finish stole all the serialised chunks. if(IsReplayingAndReading()) { RenderState.ApplyState(this); } return true; } HRESULT WrappedID3D11DeviceContext::FinishCommandList(BOOL RestoreDeferredContextState, ID3D11CommandList **ppCommandList) { if(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) { m_pDevice->AddDebugMessage(MessageCategory::Execution, MessageSeverity::High, MessageSource::IncorrectAPIUse, "It is invalid to call FinishCommandList on an immediate context. " "The call has been dropped from the capture."); return DXGI_ERROR_INVALID_CALL; } DrainAnnotationQueue(); ID3D11CommandList *real = NULL; HRESULT hr; SERIALISE_TIME_CALL(hr = m_pRealContext->FinishCommandList(RestoreDeferredContextState, &real)); RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED); bool cmdListSuccessful = m_SuccessfulCapture; if(!IsActiveCapturing(m_State) && !m_EmptyCommandList) cmdListSuccessful = false; WrappedID3D11CommandList *wrapped = new WrappedID3D11CommandList(real, m_pDevice, this, cmdListSuccessful); if(IsCaptureMode(m_State)) { RDCASSERT(m_pDevice->GetResourceManager()->GetResourceRecord(wrapped->GetResourceID()) == NULL); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->AddResourceRecord(wrapped->GetResourceID()); record->Length = 0; record->ignoreSerialise = true; if(IsActiveCapturing(m_State)) { // if we got here and m_SuccessfulCapture is on, we have captured everything in this command // list if(m_SuccessfulCapture) { RDCDEBUG("Deferred Context %llu Finish()'d successfully! Got successful command list %llu", GetResourceID(), wrapped->GetResourceID()); RDCASSERT(wrapped->IsCaptured()); ID3D11CommandList *w = wrapped; // serialise the finish marker { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::FinishCommandList); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_FinishCommandList(GET_SERIALISER, RestoreDeferredContextState, &w); m_ContextRecord->AddChunk(scope.Get()); } D3D11ResourceRecord *r = m_pDevice->GetResourceManager()->GetResourceRecord(wrapped->GetResourceID()); RDCASSERT(r); // swap our chunks, references, and dirty resources with the 'baked' command list. m_ContextRecord->SwapChunks(r); wrapped->SwapReferences(m_DeferredReferences); wrapped->SwapDirtyResources(m_DeferredDirty); } else // !m_SuccessfulCapture { RDCDEBUG( "Deferred Context %llu wasn't successful, but now we've Finish()'d so it is! Produced " "unsuccessful command list %llu.", GetResourceID(), wrapped->GetResourceID()); RDCASSERT(!wrapped->IsCaptured()); // need to clear out anything we had serialised before m_ContextRecord->LockChunks(); while(m_ContextRecord->HasChunks()) { Chunk *chunk = m_ContextRecord->GetLastChunk(); SAFE_DELETE(chunk); m_ContextRecord->PopChunk(); } m_ContextRecord->UnlockChunks(); // clear the references, and delete the resource records so they aren't kept around forever for(ResourceId id : m_DeferredReferences) { D3D11ResourceRecord *deferredRecord = m_pDevice->GetResourceManager()->GetResourceRecord(id); if(deferredRecord) deferredRecord->Delete(m_pDevice->GetResourceManager()); } m_DeferredReferences.clear(); // clear the dirty marks m_DeferredDirty.clear(); // It's now 'successful' again, being empty m_SuccessfulCapture = true; } // if we're supposed to restore, save the state to restore to now. This is because the next // recording to this deferred context is expected to have the same state, but we don't have // that state serialised right now. So we blat out the whole serialisation if(RestoreDeferredContextState) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::PostFinishCommandListSet); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_PostFinishCommandListSet(GET_SERIALISER, wrapped); m_ContextRecord->AddChunk(scope.Get()); } } else // IsIdleCapturing(m_State) { // mark that this command list is empty so that if we immediately try and capture // we pick up on that. m_EmptyCommandList = true; // still need to propagate up dirty resources to the immediate context wrapped->SwapDirtyResources(m_DeferredDirty); // clear the references and decref the resource records for(ResourceId id : m_DeferredReferences) { D3D11ResourceRecord *deferredRecord = m_pDevice->GetResourceManager()->GetResourceRecord(id); if(deferredRecord) deferredRecord->Delete(m_pDevice->GetResourceManager()); } m_DeferredReferences.clear(); RDCDEBUG( "Deferred Context %llu not capturing at the moment, Produced unsuccessful command list " "%llu.", GetResourceID(), wrapped->GetResourceID()); } } if(!RestoreDeferredContextState) m_CurrentPipelineState->Clear(); VerifyState(); if(ppCommandList) *ppCommandList = wrapped; return hr; } template bool WrappedID3D11DeviceContext::Serialise_Flush(SerialiserType &ser) { if(IsReplayingAndReading()) { m_pRealContext->Flush(); } return true; } void WrappedID3D11DeviceContext::Flush() { m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->Flush()); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Flush); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Flush(GET_SERIALISER); m_ContextRecord->AddChunk(scope.Get()); m_CurrentPipelineState->MarkReferenced(this, false); } } #pragma endregion Execute #pragma region Copy template bool WrappedID3D11DeviceContext::Serialise_CopySubresourceRegion( SerialiserType &ser, ID3D11Resource *pDstResource, UINT DstSubresource, UINT DstX, UINT DstY, UINT DstZ, ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox) { SERIALISE_ELEMENT(pDstResource); SERIALISE_ELEMENT(DstSubresource); SERIALISE_ELEMENT(DstX); SERIALISE_ELEMENT(DstY); SERIALISE_ELEMENT(DstZ); SERIALISE_ELEMENT(pSrcResource); SERIALISE_ELEMENT(SrcSubresource); SERIALISE_ELEMENT_OPT(pSrcBox); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pDstResource && pSrcResource) { m_pRealContext->CopySubresourceRegion( GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, DstX, DstY, DstZ, GetResourceManager()->UnwrapResource(pSrcResource), SrcSubresource, pSrcBox); } if(IsLoading(m_State)) { ResourceId dstLiveID = GetIDForResource(pDstResource); ResourceId srcLiveID = GetIDForResource(pSrcResource); ResourceId dstOrigID = GetResourceManager()->GetOriginalID(dstLiveID); ResourceId srcOrigID = GetResourceManager()->GetOriginalID(srcLiveID); AddEvent(); DrawcallDescription draw; draw.name = "CopySubresourceRegion(" + ToStr(dstOrigID) + ", " + ToStr(srcOrigID) + ")"; draw.flags |= DrawFlags::Copy; if(pDstResource && pSrcResource) { draw.copySource = srcOrigID; draw.copyDestination = dstOrigID; if(m_CurEventID) { if(dstLiveID == srcLiveID) { m_ResourceUses[dstLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::Copy)); } else { m_ResourceUses[dstLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::CopyDst)); m_ResourceUses[srcLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::CopySrc)); } } } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::CopySubresourceRegion(ID3D11Resource *pDstResource, UINT DstSubresource, UINT DstX, UINT DstY, UINT DstZ, ID3D11Resource *pSrcResource, UINT SrcSubresource, const D3D11_BOX *pSrcBox) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->CopySubresourceRegion( m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, DstX, DstY, DstZ, m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource), SrcSubresource, pSrcBox)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CopySubresourceRegion); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CopySubresourceRegion(GET_SERIALISER, pDstResource, DstSubresource, DstX, DstY, DstZ, pSrcResource, SrcSubresource, pSrcBox); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); RDCASSERT(record); D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); RDCASSERT(srcRecord); record->AddParent(srcRecord); m_ContextRecord->AddChunk(scope.Get()); m_MissingTracks.insert(GetIDForResource(pDstResource)); // assume partial update MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Read); MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pSrcResource), eFrameRef_Read); } else if(IsBackgroundCapturing(m_State)) { D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); RDCASSERT(record); D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); RDCASSERT(srcRecord); if(m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pSrcResource))) { MarkDirtyResource(GetIDForResource(pDstResource)); } else if(WrappedID3D11Buffer::IsAlloc(pDstResource) && WrappedID3D11Buffer::IsAlloc(pSrcResource)) { // perform copy manually (since we have buffer contents locally) RDCASSERT(record->DataInSerialiser); RDCASSERT(srcRecord->DataInSerialiser); byte *from = srcRecord->GetDataPtr(); byte *to = record->GetDataPtr(); to += DstX; size_t length = (size_t)srcRecord->Length; if(pSrcBox) { from += pSrcBox->left; length = pSrcBox->right - pSrcBox->left; } if(length > 0) { memcpy(to, from, length); } } else { // GPU dirty. Just let initial state handle this. MarkDirtyResource(GetIDForResource(pDstResource)); } } } template bool WrappedID3D11DeviceContext::Serialise_CopyResource(SerialiserType &ser, ID3D11Resource *pDstResource, ID3D11Resource *pSrcResource) { SERIALISE_ELEMENT(pDstResource); SERIALISE_ELEMENT(pSrcResource); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pDstResource && pSrcResource) { m_pRealContext->CopyResource(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource)); } if(IsLoading(m_State)) { ResourceId dstLiveID = GetIDForResource(pDstResource); ResourceId srcLiveID = GetIDForResource(pSrcResource); ResourceId dstOrigID = GetResourceManager()->GetOriginalID(dstLiveID); ResourceId srcOrigID = GetResourceManager()->GetOriginalID(srcLiveID); AddEvent(); DrawcallDescription draw; draw.name = "CopyResource(" + ToStr(dstOrigID) + ", " + ToStr(srcOrigID) + ")"; draw.flags |= DrawFlags::Copy; if(pDstResource && pSrcResource) { draw.copySource = srcOrigID; draw.copyDestination = dstOrigID; if(m_CurEventID) { if(dstLiveID == srcLiveID) { m_ResourceUses[dstLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::Copy)); } else { m_ResourceUses[dstLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::CopyDst)); m_ResourceUses[srcLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::CopySrc)); } } } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::CopyResource(ID3D11Resource *pDstResource, ID3D11Resource *pSrcResource) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL( m_pRealContext->CopyResource(m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource))); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CopyResource); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CopyResource(GET_SERIALISER, pDstResource, pSrcResource); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); RDCASSERT(record); D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); RDCASSERT(srcRecord); record->AddParent(srcRecord); m_ContextRecord->AddChunk(scope.Get()); m_MissingTracks.insert(GetIDForResource(pDstResource)); MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pSrcResource), eFrameRef_Read); } else if(IsBackgroundCapturing(m_State)) { D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstResource)); RDCASSERT(record); D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcResource)); RDCASSERT(srcRecord); record->UpdateCount++; if(record->UpdateCount > 5 || m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pSrcResource))) { MarkDirtyResource(GetIDForResource(pDstResource)); } else if(WrappedID3D11Buffer::IsAlloc(pDstResource) && WrappedID3D11Buffer::IsAlloc(pSrcResource)) { // perform copy manually (since we have buffer contents locally) RDCASSERT(record->DataInSerialiser); RDCASSERT(srcRecord->DataInSerialiser); byte *from = srcRecord->GetDataPtr(); byte *to = record->GetDataPtr(); memcpy(to, from, (size_t)record->Length); } else if((WrappedID3D11Texture1D::IsAlloc(pDstResource) && WrappedID3D11Texture1D::IsAlloc(pSrcResource)) || (WrappedID3D11Texture2D1::IsAlloc(pDstResource) && WrappedID3D11Texture2D1::IsAlloc(pSrcResource)) || (WrappedID3D11Texture3D1::IsAlloc(pDstResource) && WrappedID3D11Texture3D1::IsAlloc(pSrcResource))) { if(record->DataInSerialiser && srcRecord->DataInSerialiser) { RDCASSERT(record->NumSubResources == srcRecord->NumSubResources); for(int i = 0; i < record->NumSubResources; i++) { byte *from = srcRecord->SubResources[i]->GetDataPtr(); byte *to = record->SubResources[i]->GetDataPtr(); memcpy(to, from, (size_t)record->SubResources[i]->Length); } } else { // can't copy without data allocated USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CopyResource); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CopyResource(GET_SERIALISER, pDstResource, pSrcResource); record->AddChunk(scope.Get()); record->AddParent(srcRecord); } } else { RDCERR("Unexpected resource type"); } } } template bool WrappedID3D11DeviceContext::Serialise_UpdateSubresource( SerialiserType &ser, ID3D11Resource *pDstResource, UINT DstSubresource, const D3D11_BOX *pDstBox, 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(ser, pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch, ~0U); } void WrappedID3D11DeviceContext::UpdateSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, const D3D11_BOX *pDstBox, const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->UpdateSubresource( m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch)); 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(WrappedID3D11Texture2D1::IsAlloc(pDstResource)) { D3D11_TEXTURE2D_DESC desc; ((WrappedID3D11Texture2D1 *)pDstResource)->GetDesc(&desc); fmt = desc.Format; } else if(WrappedID3D11Texture3D1::IsAlloc(pDstResource)) { D3D11_TEXTURE3D_DESC desc; ((WrappedID3D11Texture3D1 *)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(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::UpdateSubresource); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_UpdateSubresource(GET_SERIALISER, pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); m_MissingTracks.insert(GetIDForResource(pDstResource)); m_ContextRecord->AddChunk(scope.Get()); } else if(IsBackgroundCapturing(m_State)) { ResourceId idx = GetIDForResource(pDstResource); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(idx); RDCASSERT(record); // buffers MUST update the whole resource, and don't have any subresources, // so this effectively becomes just a map/unmap pair. if(WrappedID3D11Buffer::IsAlloc(pDstResource)) { RDCASSERT(record->NumSubResources == 0); size_t offs = 0; size_t length = (size_t)record->Length; if(pDstBox) { offs += pDstBox->left; length = RDCMIN((uint32_t)length, pDstBox->right - pDstBox->left); } RDCASSERT(record->DataInSerialiser); void *ptr = record->GetDataPtr() + offs; memcpy(ptr, pSrcData, length); } else if(WrappedID3D11Texture1D::IsAlloc(pDstResource) || WrappedID3D11Texture2D1::IsAlloc(pDstResource) || WrappedID3D11Texture3D1::IsAlloc(pDstResource)) { RDCASSERT(record->Length == 1 && record->NumSubResources > 0); if(DstSubresource >= (UINT)record->NumSubResources) { RDCERR("DstSubresource %u >= %u (num subresources)", DstSubresource, record->NumSubResources); return; } // this record isn't in the log already, write out a chunk that we can update after. if(!record->SubResources[DstSubresource]->DataInSerialiser) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::UpdateSubresource); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_UpdateSubresource(GET_SERIALISER, pDstResource, DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch); Chunk *chunk = scope.Get(); record->AddChunk(chunk); record->SubResources[DstSubresource]->SetDataPtr(chunk->GetData()); record->SubResources[DstSubresource]->DataInSerialiser = true; } { RDCASSERT(record->SubResources[DstSubresource]->DataInSerialiser); void *ptr = record->SubResources[DstSubresource]->GetDataPtr(); // if the box is empty, we don't have to do anything! hooray! if(pDstBox && (pDstBox->back == pDstBox->front || pDstBox->left == pDstBox->right || pDstBox->top == pDstBox->bottom)) { // empty, do nothing. } else { WrappedID3D11Texture1D *tex1 = WrappedID3D11Texture1D::IsAlloc(pDstResource) ? (WrappedID3D11Texture1D *)pDstResource : NULL; WrappedID3D11Texture2D1 *tex2 = WrappedID3D11Texture2D1::IsAlloc(pDstResource) ? (WrappedID3D11Texture2D1 *)pDstResource : NULL; WrappedID3D11Texture3D1 *tex3 = WrappedID3D11Texture3D1::IsAlloc(pDstResource) ? (WrappedID3D11Texture3D1 *)pDstResource : NULL; RDCASSERT(tex1 || tex2 || tex3); DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN; UINT subWidth = 1; UINT subHeight = 1; UINT subDepth = 1; UINT mipLevel = GetMipForSubresource(pDstResource, DstSubresource); if(tex1) { D3D11_TEXTURE1D_DESC desc = {0}; tex1->GetDesc(&desc); fmt = desc.Format; subWidth = RDCMAX(1U, desc.Width >> mipLevel); } else if(tex2) { D3D11_TEXTURE2D_DESC desc = {0}; tex2->GetDesc(&desc); fmt = desc.Format; subWidth = RDCMAX(1U, desc.Width >> mipLevel); subHeight = RDCMAX(1U, desc.Height >> mipLevel); } else if(tex3) { D3D11_TEXTURE3D_DESC desc = {0}; tex3->GetDesc(&desc); fmt = desc.Format; subWidth = RDCMAX(1U, desc.Width >> mipLevel); subHeight = RDCMAX(1U, desc.Height >> mipLevel); subDepth = RDCMAX(1U, desc.Depth >> mipLevel); } UINT boxWidth = pDstBox ? pDstBox->right - pDstBox->left : subWidth; UINT boxHeight = pDstBox ? pDstBox->bottom - pDstBox->top : subHeight; UINT boxDepth = pDstBox ? pDstBox->back - pDstBox->front : subDepth; UINT boxTop = pDstBox ? pDstBox->top : 0; UINT DstRowPitch = GetByteSize(subWidth, 1, 1, fmt, 0); UINT DstBoxRowPitch = GetByteSize(boxWidth, 1, 1, fmt, 0); UINT DstSlicePitch = GetByteSize(subWidth, subHeight, 1, fmt, 0); // for block formats, rows are in blocks (so height is squished essentially) if(IsBlockFormat(fmt)) { subWidth = AlignUp4(subWidth); subHeight = AlignUp4(RDCMAX(1U, subHeight / 4)); boxHeight = RDCMAX(1U, boxHeight / 4); boxTop = RDCMAX(0U, boxTop / 4); } RDCASSERT(boxWidth <= subWidth && boxHeight <= subHeight && boxDepth <= subDepth); bool totalUpdate = false; // if there is no box, it's a totalUpdate (boxwidth/height are equal by inspection from // the initialisation above) // if the box describes the whole subresource, it's a totalUpdate if(boxWidth == subWidth && boxHeight == subHeight && boxDepth == subDepth) totalUpdate = true; // fast path for a total update from a source of the same size if(totalUpdate && ((tex1 && (UINT)record->SubResources[DstSubresource]->Length == SrcRowPitch) || (tex2 && (UINT)record->SubResources[DstSubresource]->Length == SrcRowPitch * subHeight) || (tex3 && (UINT)record->SubResources[DstSubresource]->Length == SrcDepthPitch * subDepth))) { memcpy(ptr, pSrcData, (size_t)record->SubResources[DstSubresource]->Length); } else { // need to fall back to copying row by row from the source byte *dstBuf = (byte *)ptr; byte *src = (byte *)pSrcData; // if we have a box, skip to the front of it if(pDstBox) dstBuf += DstSlicePitch * pDstBox->front; for(UINT slice = 0; slice < boxDepth; slice++) { byte *slicedst = dstBuf; byte *slicesrc = src; // if we have a box, skip to the top of it if(pDstBox) slicedst += DstRowPitch * boxTop; for(UINT row = 0; row < boxHeight; row++) { byte *rowdst = slicedst; // if we have a box, skip to the left of it if(pDstBox && pDstBox->left > 0) rowdst += GetByteSize(pDstBox->left, 1, 1, fmt, 0); memcpy(rowdst, slicesrc, DstBoxRowPitch); slicedst += DstRowPitch; slicesrc += SrcRowPitch; } dstBuf += DstSlicePitch; src += SrcDepthPitch; } } } } } } } template bool WrappedID3D11DeviceContext::Serialise_CopyStructureCount(SerialiserType &ser, ID3D11Buffer *pDstBuffer, UINT DstAlignedByteOffset, ID3D11UnorderedAccessView *pSrcView) { SERIALISE_ELEMENT(pDstBuffer); SERIALISE_ELEMENT(DstAlignedByteOffset); SERIALISE_ELEMENT(pSrcView); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading() && pDstBuffer && pSrcView) { m_pRealContext->CopyStructureCount(UNWRAP(WrappedID3D11Buffer, pDstBuffer), DstAlignedByteOffset, UNWRAP(WrappedID3D11UnorderedAccessView1, pSrcView)); } return true; } void WrappedID3D11DeviceContext::CopyStructureCount(ID3D11Buffer *pDstBuffer, UINT DstAlignedByteOffset, ID3D11UnorderedAccessView *pSrcView) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->CopyStructureCount( UNWRAP(WrappedID3D11Buffer, pDstBuffer), DstAlignedByteOffset, UNWRAP(WrappedID3D11UnorderedAccessView1, pSrcView))); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::CopyStructureCount); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_CopyStructureCount(GET_SERIALISER, pDstBuffer, DstAlignedByteOffset, pSrcView); m_ContextRecord->AddChunk(scope.Get()); m_MissingTracks.insert(GetIDForResource(pDstBuffer)); MarkResourceReferenced(GetIDForResource(pDstBuffer), eFrameRef_Read); MarkResourceReferenced(GetIDForResource(pDstBuffer), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pSrcView), eFrameRef_Read); } else if(IsBackgroundCapturing(m_State)) { // needs to go into device serialiser D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pDstBuffer)); RDCASSERT(record); D3D11ResourceRecord *srcRecord = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pSrcView)); RDCASSERT(srcRecord); record->AddParent(srcRecord); MarkDirtyResource(GetViewResourceResID(pSrcView)); } } template bool WrappedID3D11DeviceContext::Serialise_ResolveSubresource(SerialiserType &ser, ID3D11Resource *pDstResource, UINT DstSubresource, ID3D11Resource *pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) { SERIALISE_ELEMENT(pDstResource); SERIALISE_ELEMENT(DstSubresource); SERIALISE_ELEMENT(pSrcResource); SERIALISE_ELEMENT(SrcSubresource); SERIALISE_ELEMENT(Format); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pDstResource && pSrcResource) { m_pRealContext->ResolveSubresource( m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource), SrcSubresource, Format); } if(IsLoading(m_State)) { ResourceId dstLiveID = GetIDForResource(pDstResource); ResourceId srcLiveID = GetIDForResource(pSrcResource); ResourceId dstOrigID = GetResourceManager()->GetOriginalID(dstLiveID); ResourceId srcOrigID = GetResourceManager()->GetOriginalID(srcLiveID); AddEvent(); DrawcallDescription draw; draw.name = "ResolveSubresource(" + ToStr(dstOrigID) + ", " + ToStr(srcOrigID) + ")"; draw.flags |= DrawFlags::Resolve; if(pDstResource && pSrcResource) { draw.copySource = srcOrigID; draw.copyDestination = dstOrigID; if(m_CurEventID) { if(dstLiveID == srcLiveID) { m_ResourceUses[dstLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::Resolve)); } else { m_ResourceUses[dstLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::ResolveDst)); m_ResourceUses[srcLiveID].push_back(EventUsage(m_CurEventID, ResourceUsage::ResolveSrc)); } } } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::ResolveSubresource(ID3D11Resource *pDstResource, UINT DstSubresource, ID3D11Resource *pSrcResource, UINT SrcSubresource, DXGI_FORMAT Format) { DrainAnnotationQueue(); m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->ResolveSubresource( m_pDevice->GetResourceManager()->UnwrapResource(pDstResource), DstSubresource, m_pDevice->GetResourceManager()->UnwrapResource(pSrcResource), SrcSubresource, Format)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ResolveSubresource); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ResolveSubresource(GET_SERIALISER, pDstResource, DstSubresource, pSrcResource, SrcSubresource, Format); m_ContextRecord->AddChunk(scope.Get()); m_MissingTracks.insert(GetIDForResource(pDstResource)); MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Read); MarkResourceReferenced(GetIDForResource(pDstResource), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pSrcResource), eFrameRef_Read); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetIDForResource(pDstResource)); } } template bool WrappedID3D11DeviceContext::Serialise_GenerateMips(SerialiserType &ser, ID3D11ShaderResourceView *pShaderResourceView) { SERIALISE_ELEMENT(pShaderResourceView); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pShaderResourceView) { m_pRealContext->GenerateMips(UNWRAP(WrappedID3D11ShaderResourceView1, pShaderResourceView)); } if(IsLoading(m_State)) { WrappedID3D11ShaderResourceView1 *view = (WrappedID3D11ShaderResourceView1 *)pShaderResourceView; if(view) { m_ResourceUses[view->GetResourceResID()].push_back( EventUsage(m_CurEventID, ResourceUsage::GenMips, view->GetResourceID())); } AddEvent(); DrawcallDescription draw; draw.name = "GenerateMips(" + ToStr(GetResourceManager()->GetOriginalID(GetIDForResource(pShaderResourceView))) + ")"; draw.flags |= DrawFlags::GenMips; AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::GenerateMips(ID3D11ShaderResourceView *pShaderResourceView) { DrainAnnotationQueue(); m_EmptyCommandList = false; if(!pShaderResourceView) return; SERIALISE_TIME_CALL( m_pRealContext->GenerateMips(UNWRAP(WrappedID3D11ShaderResourceView1, pShaderResourceView))); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::GenerateMips); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_GenerateMips(GET_SERIALISER, pShaderResourceView); m_ContextRecord->AddChunk(scope.Get()); ResourceId id = GetViewResourceResID(pShaderResourceView); m_MissingTracks.insert(id); MarkResourceReferenced(id, eFrameRef_Read); MarkResourceReferenced(id, eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pShaderResourceView), eFrameRef_Read); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetViewResourceResID(pShaderResourceView)); } } #pragma endregion Copy #pragma region Clear template bool WrappedID3D11DeviceContext::Serialise_ClearState(SerialiserType &ser) { if(IsReplayingAndReading()) { m_CurrentPipelineState->Clear(); m_pRealContext->ClearState(); VerifyState(); } return true; } void WrappedID3D11DeviceContext::ClearState() { m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->ClearState()); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ClearState); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ClearState(GET_SERIALISER); m_ContextRecord->AddChunk(scope.Get()); } m_CurrentPipelineState->Clear(); VerifyState(); } template bool WrappedID3D11DeviceContext::Serialise_ClearRenderTargetView( SerialiserType &ser, ID3D11RenderTargetView *pRenderTargetView, const FLOAT ColorRGBA[4]) { SERIALISE_ELEMENT(pRenderTargetView); SERIALISE_ELEMENT_ARRAY(ColorRGBA, 4); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pRenderTargetView) { m_pRealContext->ClearRenderTargetView( UNWRAP(WrappedID3D11RenderTargetView1, pRenderTargetView), ColorRGBA); } if(IsLoading(m_State)) { AddEvent(); WrappedID3D11RenderTargetView1 *view = (WrappedID3D11RenderTargetView1 *)pRenderTargetView; DrawcallDescription draw; draw.name = StringFormat::Fmt("ClearRenderTargetView(%f, %f, %f, %f)", ColorRGBA[0], ColorRGBA[1], ColorRGBA[2], ColorRGBA[3]); draw.flags |= DrawFlags::Clear | DrawFlags::ClearColor; if(view) { m_ResourceUses[view->GetResourceResID()].push_back( EventUsage(m_CurEventID, ResourceUsage::Clear, view->GetResourceID())); draw.copyDestination = m_pDevice->GetResourceManager()->GetOriginalID(view->GetResourceResID()); } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::ClearRenderTargetView(ID3D11RenderTargetView *pRenderTargetView, const FLOAT ColorRGBA[4]) { DrainAnnotationQueue(); if(pRenderTargetView == NULL) return; m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->ClearRenderTargetView( UNWRAP(WrappedID3D11RenderTargetView1, pRenderTargetView), ColorRGBA)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ClearRenderTargetView); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ClearRenderTargetView(GET_SERIALISER, pRenderTargetView, ColorRGBA); if(pRenderTargetView) { MarkResourceReferenced(GetViewResourceResID(pRenderTargetView), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pRenderTargetView), eFrameRef_Read); } m_MissingTracks.insert(GetViewResourceResID(pRenderTargetView)); m_ContextRecord->AddChunk(scope.Get()); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetViewResourceResID(pRenderTargetView)); } } template bool WrappedID3D11DeviceContext::Serialise_ClearUnorderedAccessViewUint( SerialiserType &ser, ID3D11UnorderedAccessView *pUnorderedAccessView, const UINT Values[4]) { SERIALISE_ELEMENT(pUnorderedAccessView); SERIALISE_ELEMENT_ARRAY(Values, 4); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pUnorderedAccessView) { m_pRealContext->ClearUnorderedAccessViewUint( UNWRAP(WrappedID3D11UnorderedAccessView1, pUnorderedAccessView), Values); } if(IsLoading(m_State)) { AddEvent(); WrappedID3D11UnorderedAccessView1 *view = (WrappedID3D11UnorderedAccessView1 *)pUnorderedAccessView; DrawcallDescription draw; draw.name = StringFormat::Fmt("ClearUnorderedAccessViewUint(%u, %u, %u, %u)", Values[0], Values[1], Values[2], Values[3]); draw.flags |= DrawFlags::Clear; if(view) { m_ResourceUses[view->GetResourceResID()].push_back( EventUsage(m_CurEventID, ResourceUsage::Clear, view->GetResourceID())); draw.copyDestination = m_pDevice->GetResourceManager()->GetOriginalID(view->GetResourceResID()); } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::ClearUnorderedAccessViewUint( ID3D11UnorderedAccessView *pUnorderedAccessView, const UINT Values[4]) { m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->ClearUnorderedAccessViewUint( UNWRAP(WrappedID3D11UnorderedAccessView1, pUnorderedAccessView), Values)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ClearUnorderedAccessViewUint); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ClearUnorderedAccessViewUint(GET_SERIALISER, pUnorderedAccessView, Values); if(pUnorderedAccessView) { MarkResourceReferenced(GetViewResourceResID(pUnorderedAccessView), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pUnorderedAccessView), eFrameRef_Read); } m_MissingTracks.insert(GetViewResourceResID(pUnorderedAccessView)); m_ContextRecord->AddChunk(scope.Get()); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetViewResourceResID(pUnorderedAccessView)); } } template bool WrappedID3D11DeviceContext::Serialise_ClearUnorderedAccessViewFloat( SerialiserType &ser, ID3D11UnorderedAccessView *pUnorderedAccessView, const FLOAT Values[4]) { SERIALISE_ELEMENT(pUnorderedAccessView); SERIALISE_ELEMENT_ARRAY(Values, 4); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pUnorderedAccessView) { m_pRealContext->ClearUnorderedAccessViewFloat( UNWRAP(WrappedID3D11UnorderedAccessView1, pUnorderedAccessView), Values); } if(IsLoading(m_State)) { AddEvent(); WrappedID3D11UnorderedAccessView1 *view = (WrappedID3D11UnorderedAccessView1 *)pUnorderedAccessView; DrawcallDescription draw; draw.name = StringFormat::Fmt("ClearUnorderedAccessViewFloat(%f, %f, %f, %f)", Values[0], Values[1], Values[2], Values[3]); draw.flags |= DrawFlags::Clear; if(view) { m_ResourceUses[view->GetResourceResID()].push_back( EventUsage(m_CurEventID, ResourceUsage::Clear, view->GetResourceID())); draw.copyDestination = m_pDevice->GetResourceManager()->GetOriginalID(view->GetResourceResID()); } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::ClearUnorderedAccessViewFloat( ID3D11UnorderedAccessView *pUnorderedAccessView, const FLOAT Values[4]) { m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->ClearUnorderedAccessViewFloat( UNWRAP(WrappedID3D11UnorderedAccessView1, pUnorderedAccessView), Values)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ClearUnorderedAccessViewFloat); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ClearUnorderedAccessViewFloat(GET_SERIALISER, pUnorderedAccessView, Values); if(pUnorderedAccessView) { MarkResourceReferenced(GetViewResourceResID(pUnorderedAccessView), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pUnorderedAccessView), eFrameRef_Read); } m_MissingTracks.insert(GetViewResourceResID(pUnorderedAccessView)); m_ContextRecord->AddChunk(scope.Get()); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetViewResourceResID(pUnorderedAccessView)); } } template bool WrappedID3D11DeviceContext::Serialise_ClearDepthStencilView( SerialiserType &ser, ID3D11DepthStencilView *pDepthStencilView, UINT ClearFlags, FLOAT Depth, UINT8 Stencil) { SERIALISE_ELEMENT(pDepthStencilView); SERIALISE_ELEMENT_TYPED(D3D11_CLEAR_FLAG, ClearFlags); SERIALISE_ELEMENT(Depth); SERIALISE_ELEMENT(Stencil); Serialise_DebugMessages(GET_SERIALISER); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pDepthStencilView) { m_pRealContext->ClearDepthStencilView( UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView), ClearFlags, Depth, Stencil); } if(IsLoading(m_State)) { AddEvent(); WrappedID3D11DepthStencilView *view = (WrappedID3D11DepthStencilView *)pDepthStencilView; DrawcallDescription draw; if(ClearFlags == (D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL)) draw.name = StringFormat::Fmt("ClearDepthStencilView(D=%f, S=%02hhx)", Depth, Stencil); else if(ClearFlags == D3D11_CLEAR_DEPTH) draw.name = StringFormat::Fmt("ClearDepthStencilView(D=%f)", Depth); else if(ClearFlags == D3D11_CLEAR_STENCIL) draw.name = StringFormat::Fmt("ClearDepthStencilView(S=%02hhx)", Stencil); else draw.name = "ClearDepthStencilView(None)"; draw.flags |= DrawFlags::Clear | DrawFlags::ClearDepthStencil; if(view) { m_ResourceUses[view->GetResourceResID()].push_back( EventUsage(m_CurEventID, ResourceUsage::Clear, view->GetResourceID())); draw.copyDestination = m_pDevice->GetResourceManager()->GetOriginalID(view->GetResourceResID()); } AddDrawcall(draw, true); } } return true; } void WrappedID3D11DeviceContext::ClearDepthStencilView(ID3D11DepthStencilView *pDepthStencilView, UINT ClearFlags, FLOAT Depth, UINT8 Stencil) { DrainAnnotationQueue(); if(pDepthStencilView == NULL) return; m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->ClearDepthStencilView( UNWRAP(WrappedID3D11DepthStencilView, pDepthStencilView), ClearFlags, Depth, Stencil)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); GET_SERIALISER.SetDrawChunk(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::ClearDepthStencilView); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_ClearDepthStencilView(GET_SERIALISER, pDepthStencilView, ClearFlags, Depth, Stencil); if(pDepthStencilView) { MarkResourceReferenced(GetViewResourceResID(pDepthStencilView), eFrameRef_Write); MarkResourceReferenced(GetIDForResource(pDepthStencilView), eFrameRef_Read); } m_MissingTracks.insert(GetViewResourceResID(pDepthStencilView)); m_ContextRecord->AddChunk(scope.Get()); } else if(IsBackgroundCapturing(m_State)) { MarkDirtyResource(GetViewResourceResID(pDepthStencilView)); } } #pragma endregion Clear #pragma region Misc template bool WrappedID3D11DeviceContext::Serialise_Begin(SerialiserType &ser, ID3D11Asynchronous *pAsync) { SERIALISE_ELEMENT(pAsync); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading() && pAsync) { ID3D11Asynchronous *unwrapped = NULL; // only replay predicates which can affect rendering, don't re-submit queries or counters (that // might even interfere with queries we want to run) if(WrappedID3D11Predicate::IsAlloc(pAsync)) unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); // if you change this to replay other types, check with Serialise_CreateCounter which creates // dummy queries to ensure it always succeeds. if(unwrapped) m_pRealContext->Begin(unwrapped); } return true; } void WrappedID3D11DeviceContext::Begin(ID3D11Asynchronous *pAsync) { ID3D11Asynchronous *unwrapped = NULL; ResourceId id; if(WrappedID3D11Query1::IsAlloc(pAsync)) { unwrapped = UNWRAP(WrappedID3D11Query1, pAsync); id = ((WrappedID3D11Query1 *)pAsync)->GetResourceID(); } else if(WrappedID3D11Predicate::IsAlloc(pAsync)) { unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); id = ((WrappedID3D11Predicate *)pAsync)->GetResourceID(); } else if(WrappedID3D11Counter::IsAlloc(pAsync)) { unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); id = ((WrappedID3D11Counter *)pAsync)->GetResourceID(); } else { RDCERR("Unexpected ID3D11Asynchronous"); } SERIALISE_TIME_CALL(m_pRealContext->Begin(unwrapped)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Begin); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Begin(GET_SERIALISER, pAsync); m_ContextRecord->AddChunk(scope.Get()); MarkResourceReferenced(id, eFrameRef_Read); } } template bool WrappedID3D11DeviceContext::Serialise_End(SerialiserType &ser, ID3D11Asynchronous *pAsync) { SERIALISE_ELEMENT(pAsync); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading() && pAsync) { ID3D11Asynchronous *unwrapped = NULL; // only replay predicates which can affect rendering, don't re-submit queries or counters (that // might even interfere with queries we want to run) if(WrappedID3D11Predicate::IsAlloc(pAsync)) unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); // if you change this to replay other types, check with Serialise_CreateCounter which creates // dummy queries to ensure it always succeeds. if(unwrapped) m_pRealContext->End(unwrapped); } return true; } void WrappedID3D11DeviceContext::End(ID3D11Asynchronous *pAsync) { ID3D11Asynchronous *unwrapped = NULL; ResourceId id; if(WrappedID3D11Query1::IsAlloc(pAsync)) { unwrapped = UNWRAP(WrappedID3D11Query1, pAsync); id = ((WrappedID3D11Query1 *)pAsync)->GetResourceID(); } else if(WrappedID3D11Predicate::IsAlloc(pAsync)) { unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); id = ((WrappedID3D11Predicate *)pAsync)->GetResourceID(); } else if(WrappedID3D11Counter::IsAlloc(pAsync)) { unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); id = ((WrappedID3D11Counter *)pAsync)->GetResourceID(); } else { RDCERR("Unexpected ID3D11Asynchronous"); } SERIALISE_TIME_CALL(m_pRealContext->End(unwrapped)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::End); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_End(GET_SERIALISER, pAsync); m_ContextRecord->AddChunk(scope.Get()); MarkResourceReferenced(id, eFrameRef_Read); } } HRESULT WrappedID3D11DeviceContext::GetData(ID3D11Asynchronous *pAsync, void *pData, UINT DataSize, UINT GetDataFlags) { ID3D11Asynchronous *unwrapped = NULL; if(WrappedID3D11Query1::IsAlloc(pAsync)) unwrapped = UNWRAP(WrappedID3D11Query1, pAsync); else if(WrappedID3D11Predicate::IsAlloc(pAsync)) unwrapped = UNWRAP(WrappedID3D11Predicate, pAsync); else if(WrappedID3D11Counter::IsAlloc(pAsync)) unwrapped = UNWRAP(WrappedID3D11Counter, pAsync); else RDCERR("Unexpected ID3D11Asynchronous"); return m_pRealContext->GetData(unwrapped, pData, DataSize, GetDataFlags); } template bool WrappedID3D11DeviceContext::Serialise_SetPredication(SerialiserType &ser, ID3D11Predicate *pPredicate, BOOL PredicateValue_) { SERIALISE_ELEMENT(pPredicate); SERIALISE_ELEMENT_LOCAL(PredicateValue, PredicateValue_ == TRUE); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { // we don't replay predication as it can be confusing and inconsistent. We just store the state // so that we can manually check whether it *would* have passed or failed. m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->Predicate, pPredicate); m_CurrentPipelineState->Change(m_CurrentPipelineState->PredicateValue, PredicateValue ? TRUE : FALSE); /* m_pRealContext->SetPredication(UNWRAP(WrappedID3D11Predicate, pPredicate), PredicateValue ? TRUE : FALSE); */ } return true; } void WrappedID3D11DeviceContext::SetPredication(ID3D11Predicate *pPredicate, BOOL PredicateValue) { m_EmptyCommandList = false; m_CurrentPipelineState->ChangeRefRead(m_CurrentPipelineState->Predicate, pPredicate); m_CurrentPipelineState->Change(m_CurrentPipelineState->PredicateValue, PredicateValue); // on replay don't actually apply any predication. Just update the state and bail if(IsReplayMode(m_State)) return; SERIALISE_TIME_CALL( m_pRealContext->SetPredication(UNWRAP(WrappedID3D11Predicate, pPredicate), PredicateValue)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetPredication); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_SetPredication(GET_SERIALISER, pPredicate, PredicateValue); m_ContextRecord->AddChunk(scope.Get()); if(pPredicate) { ResourceId id = ((WrappedID3D11Predicate *)pPredicate)->GetResourceID(); MarkResourceReferenced(id, eFrameRef_Read); } } } FLOAT WrappedID3D11DeviceContext::GetResourceMinLOD(ID3D11Resource *pResource) { return m_pRealContext->GetResourceMinLOD(m_pDevice->GetResourceManager()->UnwrapResource(pResource)); } template bool WrappedID3D11DeviceContext::Serialise_SetResourceMinLOD(SerialiserType &ser, ID3D11Resource *pResource, FLOAT MinLOD) { SERIALISE_ELEMENT(pResource); SERIALISE_ELEMENT(MinLOD); SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading()) { if(pResource) m_pRealContext->SetResourceMinLOD(pResource, MinLOD); } return true; } void WrappedID3D11DeviceContext::SetResourceMinLOD(ID3D11Resource *pResource, FLOAT MinLOD) { m_EmptyCommandList = false; SERIALISE_TIME_CALL(m_pRealContext->SetResourceMinLOD( m_pDevice->GetResourceManager()->UnwrapResource(pResource), MinLOD)); if(IsActiveCapturing(m_State)) { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::SetResourceMinLOD); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_SetResourceMinLOD(GET_SERIALISER, pResource, MinLOD); m_ContextRecord->AddChunk(scope.Get()); } } void WrappedID3D11DeviceContext::GetPredication(ID3D11Predicate **ppPredicate, BOOL *pPredicateValue) { ID3D11Predicate *real = NULL; m_pRealContext->GetPredication(&real, pPredicateValue); SAFE_RELEASE_NOCLEAR(real); if(ppPredicate) { if(real) *ppPredicate = UNWRAP(WrappedID3D11Predicate, real); else *ppPredicate = NULL; } } D3D11_DEVICE_CONTEXT_TYPE WrappedID3D11DeviceContext::GetType() { return m_pRealContext->GetType(); } UINT WrappedID3D11DeviceContext::GetContextFlags() { return m_pRealContext->GetContextFlags(); } #pragma endregion Misc #pragma region Map void MapIntercept::SetAppMemory(void *appMemory) { app.pData = appMemory; } void MapIntercept::SetD3D(D3D11_SUBRESOURCE_DATA d3dData) { D3D11_MAPPED_SUBRESOURCE d3dMap; d3dMap.pData = (void *)d3dData.pSysMem; d3dMap.RowPitch = d3dData.SysMemPitch; d3dMap.DepthPitch = d3dData.SysMemSlicePitch; d3d = d3dMap; RDCASSERT(d3d.pData); } void MapIntercept::SetD3D(D3D11_MAPPED_SUBRESOURCE d3dMap) { d3d = d3dMap; RDCASSERT(d3d.pData); } void MapIntercept::InitWrappedResource(ID3D11Resource *res, UINT sub, void *appMemory) { if(WrappedID3D11Buffer::IsAlloc(res)) Init((ID3D11Buffer *)res, appMemory); else if(WrappedID3D11Texture1D::IsAlloc(res)) Init((ID3D11Texture1D *)res, sub, appMemory); else if(WrappedID3D11Texture2D1::IsAlloc(res)) Init((ID3D11Texture2D *)res, sub, appMemory); else if(WrappedID3D11Texture3D1::IsAlloc(res)) Init((ID3D11Texture3D *)res, sub, appMemory); else RDCERR("Unexpected resource type"); } void MapIntercept::Init(ID3D11Buffer *buf, void *appMemory) { app.pData = appMemory; if(buf == NULL) return; D3D11_BUFFER_DESC desc; buf->GetDesc(&desc); app.RowPitch = app.DepthPitch = desc.ByteWidth; if(d3d.RowPitch == 0) d3d.RowPitch = desc.ByteWidth; if(d3d.DepthPitch == 0) d3d.DepthPitch = desc.ByteWidth; } void MapIntercept::Init(ID3D11Texture1D *tex, UINT sub, void *appMemory) { app.pData = appMemory; if(tex == NULL) return; D3D11_TEXTURE1D_DESC desc; tex->GetDesc(&desc); int width = desc.Width; int height = 1; DXGI_FORMAT fmt = desc.Format; int mip = GetMipForSubresource(tex, sub); // a row in block formats is a row of 4x4 blocks. if(IsBlockFormat(fmt)) numRows /= 4; numRows = RDCMAX(1, numRows >> mip); numSlices = RDCMAX(1, numSlices >> mip); app.RowPitch = GetByteSize(width, 1, 1, fmt, mip); app.DepthPitch = GetByteSize(width, height, 1, fmt, mip); if(d3d.DepthPitch == 0) d3d.DepthPitch = app.RowPitch; if(d3d.DepthPitch == 0) d3d.DepthPitch = app.DepthPitch; } void MapIntercept::Init(ID3D11Texture2D *tex, UINT sub, void *appMemory) { app.pData = appMemory; if(tex == NULL) return; D3D11_TEXTURE2D_DESC desc; tex->GetDesc(&desc); int width = desc.Width; int height = numRows = desc.Height; DXGI_FORMAT fmt = desc.Format; int mip = GetMipForSubresource(tex, sub); // a row in block formats is a row of 4x4 blocks. if(IsBlockFormat(fmt)) numRows /= 4; numRows = RDCMAX(1, numRows >> mip); numSlices = RDCMAX(1, numSlices >> mip); app.RowPitch = GetByteSize(width, 1, 1, fmt, mip); app.DepthPitch = GetByteSize(width, height, 1, fmt, mip); if(d3d.DepthPitch == 0) d3d.DepthPitch = app.DepthPitch; } void MapIntercept::Init(ID3D11Texture3D *tex, UINT sub, void *appMemory) { app.pData = appMemory; if(tex == NULL) return; D3D11_TEXTURE3D_DESC desc; tex->GetDesc(&desc); int width = desc.Width; int height = numRows = desc.Height; numSlices = desc.Depth; DXGI_FORMAT fmt = desc.Format; int mip = GetMipForSubresource(tex, sub); // a row in block formats is a row of 4x4 blocks. if(IsBlockFormat(fmt)) numRows /= 4; numRows = RDCMAX(1, numRows >> mip); numSlices = RDCMAX(1, numSlices >> mip); app.RowPitch = GetByteSize(width, 1, 1, fmt, mip); app.DepthPitch = GetByteSize(width, height, 1, fmt, mip); } void MapIntercept::CopyFromD3D() { byte *sliceSrc = (byte *)d3d.pData; byte *sliceDst = (byte *)app.pData; RDCASSERT(numSlices > 0 && numRows > 0 && (numRows == 1 || (app.RowPitch > 0 && d3d.RowPitch > 0)) && (numSlices == 1 || (app.DepthPitch > 0 && d3d.DepthPitch > 0))); for(int slice = 0; slice < numSlices; slice++) { byte *rowSrc = sliceSrc; byte *rowDst = sliceDst; for(int row = 0; row < numRows; row++) { memcpy(rowDst, rowSrc, app.RowPitch); rowSrc += d3d.RowPitch; rowDst += app.RowPitch; } sliceSrc += d3d.DepthPitch; sliceDst += app.DepthPitch; } } void MapIntercept::CopyToD3D(size_t RangeStart, size_t RangeEnd) { byte *sliceSrc = (byte *)app.pData; byte *sliceDst = (byte *)d3d.pData + RangeStart; RDCASSERT(numSlices > 0 && numRows > 0 && app.RowPitch > 0 && d3d.RowPitch > 0 && app.DepthPitch > 0 && d3d.DepthPitch > 0); for(int slice = 0; slice < numSlices; slice++) { byte *rowSrc = sliceSrc; byte *rowDst = sliceDst; for(int row = 0; row < numRows; row++) { size_t len = app.RowPitch; if(RangeEnd > 0) { if(rowSrc + len > (byte *)app.pData + (RangeEnd - RangeStart)) len = (byte *)app.pData + (RangeEnd - RangeStart) - rowSrc; } memcpy(rowDst, rowSrc, len); rowSrc += app.RowPitch; rowDst += d3d.RowPitch; if(RangeEnd > 0 && rowSrc > (byte *)app.pData + (RangeEnd - RangeStart)) return; } sliceSrc += app.DepthPitch; sliceDst += d3d.DepthPitch; } } template bool WrappedID3D11DeviceContext::Serialise_Map(SerialiserType &ser, ID3D11Resource *pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE *pMappedResource) { // unused - just for the user's benefit SERIALISE_ELEMENT(pResource); SERIALISE_ELEMENT(Subresource); SERIALISE_ELEMENT(MapType); SERIALISE_ELEMENT_TYPED(D3D11_MAP_FLAG, MapFlags); SERIALISE_CHECK_READ_ERRORS(); // nothing to do on replay, all the work happens in Unmap. if(ser.IsReading()) return true; D3D11_MAPPED_SUBRESOURCE mappedResource = D3D11_MAPPED_SUBRESOURCE(); if(pMappedResource) mappedResource = *pMappedResource; D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); RDCASSERT(record); if(record->NumSubResources > (int)Subresource) record = (D3D11ResourceRecord *)record->SubResources[Subresource]; MapIntercept intercept; size_t mapLength = (size_t)record->Length; if(IsActiveCapturing(m_State) || !record->DataInSerialiser) { ResourceId Resource = GetIDForResource(pResource); RDCASSERT(m_OpenMaps.find(MappedResource(Resource, Subresource)) == m_OpenMaps.end()); ID3D11Resource *resMap = pResource; RDCASSERT(resMap); int ctxMapID = 0; if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) { if(m_MapResourceRecordAllocs[Resource] == 0) m_MapResourceRecordAllocs[Resource] = record->GetContextID(); ctxMapID = m_MapResourceRecordAllocs[Resource]; RDCASSERT(ctxMapID != 0); } void *appMem = record->GetShadowPtr(ctxMapID, 0); if(appMem == NULL) { record->AllocShadowStorage(ctxMapID, mapLength); appMem = record->GetShadowPtr(ctxMapID, 0); if(MapType != D3D11_MAP_WRITE_DISCARD) { if(m_pDevice->GetResourceManager()->IsResourceDirty(Resource)) { ID3D11DeviceChild *initial = m_pDevice->GetResourceManager()->GetInitialContents(Resource).resource; if(WrappedID3D11Buffer::IsAlloc(pResource)) { RDCASSERT(initial); ID3D11Buffer *stage = (ID3D11Buffer *)initial; D3D11_MAPPED_SUBRESOURCE mapped; HRESULT hr = m_pRealContext->Map(stage, 0, D3D11_MAP_READ, 0, &mapped); if(FAILED(hr)) { RDCERR("Failed to map while getting initial states HRESULT: %s", ToStr(hr).c_str()); } else { intercept = MapIntercept(); intercept.SetD3D(mapped); intercept.Init((ID3D11Buffer *)pResource, record->GetDataPtr()); intercept.CopyFromD3D(); RDCASSERT(mapLength == (size_t)record->Length); memcpy(appMem, record->GetDataPtr(), mapLength); m_pRealContext->Unmap(stage, 0); } } else { // need to get initial contents out RDCUNIMPLEMENTED("Not getting initial contents for non-buffer GPU dirty map"); RDCERR( "CORRUPTION - Invalid/inaccurate initial data for Map() - non-buffer GPU dirty " "data mapped"); } } else if(record->DataInSerialiser) { RDCASSERT(mapLength == (size_t)record->Length); memcpy(appMem, record->GetDataPtr(), mapLength); } else { memset(appMem, 0, mapLength); } } memcpy(record->GetShadowPtr(ctxMapID, 1), appMem, mapLength); } if(MapType == D3D11_MAP_WRITE_DISCARD) { memset(appMem, 0xcc, mapLength); memcpy(record->GetShadowPtr(ctxMapID, 1), appMem, mapLength); } intercept = MapIntercept(); intercept.verifyWrite = (RenderDoc::Inst().GetCaptureOptions().verifyMapWrites != 0); intercept.SetD3D(mappedResource); intercept.InitWrappedResource(resMap, Subresource, appMem); intercept.MapType = MapType; intercept.MapFlags = MapFlags; RDCASSERT(pMappedResource); *pMappedResource = intercept.app; m_OpenMaps[MappedResource(Resource, Subresource)] = intercept; } else if(IsBackgroundCapturing(m_State)) { RDCASSERT(record->DataInSerialiser); mapLength = (size_t)record->Length; intercept = MapIntercept(); intercept.verifyWrite = (RenderDoc::Inst().GetCaptureOptions().verifyMapWrites != 0); intercept.SetD3D(mappedResource); intercept.MapType = MapType; intercept.MapFlags = MapFlags; if(intercept.verifyWrite) { int ctxMapID = 0; ResourceId Resource = GetIDForResource(pResource); if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) { if(m_MapResourceRecordAllocs[Resource] == 0) m_MapResourceRecordAllocs[Resource] = record->GetContextID(); ctxMapID = m_MapResourceRecordAllocs[Resource]; RDCASSERT(ctxMapID != 0); } byte *appMem = record->GetShadowPtr(ctxMapID, 0); if(appMem == NULL) { record->AllocShadowStorage(ctxMapID, mapLength); appMem = record->GetShadowPtr(ctxMapID, 0); } memcpy(appMem, record->GetDataPtr(), mapLength); intercept.InitWrappedResource(pResource, Subresource, appMem); } else { intercept.InitWrappedResource(pResource, Subresource, record->GetDataPtr()); } *pMappedResource = intercept.app; m_OpenMaps[MappedResource(GetIDForResource(pResource), Subresource)] = intercept; } else { RDCERR("Unexpected and unhandled case"); RDCEraseEl(intercept); } // for read write fill out the buffer with what's on the mapped resource already if(MapType == D3D11_MAP_READ_WRITE || MapType == D3D11_MAP_READ) { intercept.CopyFromD3D(); } else if(MapType == D3D11_MAP_WRITE_DISCARD) { // the easy case! } else if(MapType == D3D11_MAP_WRITE || MapType == D3D11_MAP_WRITE_NO_OVERWRITE) { // For now we'll just assume that the buffer contents are perfectly accurate // (which they are if no gpu writes to the buffer happens). // could take the performance hit and just copy anyway, spec doesn't see if the // data will be invalid but it will certainly be slow. } return true; } HRESULT WrappedID3D11DeviceContext::Map(ID3D11Resource *pResource, UINT Subresource, D3D11_MAP MapType, UINT MapFlags, D3D11_MAPPED_SUBRESOURCE *pMappedResource) { DrainAnnotationQueue(); m_EmptyCommandList = false; ResourceId id = GetIDForResource(pResource); bool directMap = false; if(m_HighTrafficResources.find(id) != m_HighTrafficResources.end() && !IsActiveCapturing(m_State)) directMap = true; if(m_pDevice->GetResourceManager()->IsResourceDirty(GetIDForResource(pResource)) && !IsActiveCapturing(m_State)) directMap = true; if((!directMap && MapType == D3D11_MAP_WRITE_NO_OVERWRITE && !IsActiveCapturing(m_State)) || m_pRealContext->GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) { directMap = true; m_HighTrafficResources.insert(id); if(!IsActiveCapturing(m_State)) MarkDirtyResource(id); } if(directMap && IsBackgroundCapturing(m_State)) { return m_pRealContext->Map(m_pDevice->GetResourceManager()->UnwrapResource(pResource), Subresource, MapType, MapFlags, pMappedResource); } // can't promise no-overwrite as we're going to blat the whole buffer! HRESULT ret; SERIALISE_TIME_CALL(ret = m_pRealContext->Map( m_pDevice->GetResourceManager()->UnwrapResource(pResource), Subresource, MapType == D3D11_MAP_WRITE_NO_OVERWRITE ? D3D11_MAP_WRITE_DISCARD : MapType, MapFlags, pMappedResource)); if(SUCCEEDED(ret) && IsCaptureMode(m_State)) { if(IsActiveCapturing(m_State)) { if(MapType == D3D11_MAP_READ) { MapIntercept intercept; intercept.MapType = MapType; intercept.MapFlags = MapFlags; m_OpenMaps[MappedResource(GetIDForResource(pResource), Subresource)] = intercept; } else { m_MissingTracks.insert(GetIDForResource(pResource)); // create a chunk purely for the user's benefit USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Map); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Map(GET_SERIALISER, pResource, Subresource, MapType, MapFlags, pMappedResource); m_ContextRecord->AddChunk(scope.Get()); } } else // IsIdleCapturing(m_State) { RDCASSERT(WrappedID3D11Buffer::IsAlloc(pResource) || WrappedID3D11Texture1D::IsAlloc(pResource) || WrappedID3D11Texture2D1::IsAlloc(pResource) || WrappedID3D11Texture3D1::IsAlloc(pResource)); ResourceId Id = GetIDForResource(pResource); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(Id); RDCASSERT(record); if(record->NumSubResources > (int)Subresource) record = (D3D11ResourceRecord *)record->SubResources[Subresource]; record->UpdateCount++; if(record->UpdateCount > 60 && RenderDoc::Inst().GetCaptureOptions().verifyMapWrites == 0) { m_HighTrafficResources.insert(Id); MarkDirtyResource(Id); return ret; } // don't need to create a chunk but we do need to prepare the map. Serialise_Map(m_ScratchSerialiser, pResource, Subresource, MapType, MapFlags, pMappedResource); // throw away any serialised data m_ScratchSerialiser.GetWriter()->Rewind(); } } return ret; } template bool WrappedID3D11DeviceContext::Serialise_Unmap(SerialiserType &ser, ID3D11Resource *pResource, UINT Subresource) { SERIALISE_ELEMENT(pResource); SERIALISE_ELEMENT(Subresource); MappedResource mapIdx(GetIDForResource(pResource), Subresource); MapIntercept intercept; int ctxMapID = 0; D3D11ResourceRecord *record = NULL; size_t len = 0; uint32_t diffStart = 0; uint32_t diffEnd = 0; byte *MapWrittenData = NULL; // handle book-keeping during capture mode if(ser.IsWriting()) { record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); RDCASSERT(record); if((int)Subresource < record->NumSubResources) record = (D3D11ResourceRecord *)record->SubResources[Subresource]; len = (size_t)record->Length; diffEnd = (uint32_t)len; // locate the intercept data and remove it from the open maps list auto it = m_OpenMaps.find(mapIdx); if(it != m_OpenMaps.end()) { intercept = it->second; m_OpenMaps.erase(it); } else { RDCERR("Couldn't find map for %llu/%u in open maps list", mapIdx.resource, mapIdx.subresource); } MapWrittenData = (byte *)intercept.app.pData; // store the context ID we used for this map's shadow pointers if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED && (IsActiveCapturing(m_State) || intercept.verifyWrite)) { ctxMapID = m_MapResourceRecordAllocs[mapIdx.resource]; RDCASSERT(ctxMapID != 0); } // if we were verifying this map, then make sure the shadow storage is still safe if(intercept.verifyWrite) { if(!record->VerifyShadowStorage(ctxMapID)) { std::string msg = StringFormat::Fmt( "Overwrite of %llu byte Map()'d buffer detected\n" "Breakpoint now to see callstack,\nor click 'Yes' to debugbreak.", record->Length); int res = tinyfd_messageBox("Map() overwrite detected!", msg.c_str(), "yesno", "error", 1); if(res == 1) { OS_DEBUG_BREAK(); } } if(IsBackgroundCapturing(m_State)) { // if there was already backing store then normally the user wrote directly into it so we // don't even have to update anything, except in the case where we were verifying map // writes. Then we need to copy from the verification shadow buffer into the backing store. memcpy(record->GetDataPtr(), intercept.app.pData, len); } } // copy from the intercept buffer that the user wrote into, into D3D's real pointer intercept.CopyToD3D(); // while actively capturing, on large buffers being updated, try to locate the range of data // being // updated and update the diffStart/diffEnd/len variables if(IsActiveCapturing(m_State) && len > 512 && intercept.MapType != D3D11_MAP_WRITE_DISCARD) { size_t s = diffStart; size_t e = diffEnd; bool found = FindDiffRange(MapWrittenData, record->GetShadowPtr(ctxMapID, 1), len, s, e); diffStart = (uint32_t)s; diffEnd = (uint32_t)e; if(found) { #if ENABLED(RDOC_DEVEL) static size_t saved = 0; saved += len - (diffEnd - diffStart); RDCDEBUG("Mapped resource size %u, difference: %u -> %u. Total bytes saved so far: %u", (uint32_t)len, (uint32_t)diffStart, (uint32_t)diffEnd, (uint32_t)saved); #endif len = diffEnd - diffStart; } else { diffStart = 0; diffEnd = 0; len = 0; } // update the data pointer to be rebased to the start of the diff data. MapWrittenData += diffStart; } // update shadow stores for future diff'ing if(IsActiveCapturing(m_State) && record->GetShadowPtr(ctxMapID, 1)) { memcpy(record->GetShadowPtr(ctxMapID, 1) + diffStart, MapWrittenData, diffEnd - diffStart); } } // if(ser.IsWriting()) // if we're not actively capturing a frame, we'll skip serialising all this data for nothing as we // aren't going to save the chunk anywhere. The exception is if there's no backing store for this // resource - then we need to serialise into the chunk to allocate it bool SerialiseMap = ser.IsReading() || (ser.IsWriting() && IsActiveCapturing(m_State)) || (ser.IsWriting() && !record->DataInSerialiser); if(SerialiseMap) { SERIALISE_ELEMENT(intercept.MapType).Named("MapType"); SERIALISE_ELEMENT_TYPED(D3D11_MAP_FLAG, intercept.MapFlags).Named("MapFlags"); SERIALISE_ELEMENT(diffStart).Named("Byte offset to start of written data"); SERIALISE_ELEMENT(diffEnd).Named("Byte offset to end of written data"); SERIALISE_ELEMENT_ARRAY(MapWrittenData, len); if(ser.IsWriting() && IsBackgroundCapturing(m_State) && !record->DataInSerialiser) { record->DataInSerialiser = true; record->SetDataOffset(ser.GetWriter()->GetOffset() - (uint64_t)len); } else if(IsReplayingAndReading() && pResource) { // steal the allocated buffer, and manually release intercept.app.pData = MapWrittenData; MapWrittenData = NULL; } } if(IsReplayingAndReading() && ser.IsErrored()) { FreeAlignedBuffer(MapWrittenData); } SERIALISE_CHECK_READ_ERRORS(); if(IsReplayingAndReading() && pResource) { MapWrittenData = (byte *)intercept.app.pData; if(IsLoading(m_State) && m_CurEventID > 0 && (diffStart < diffEnd)) RecordUpdateStats(pResource, diffEnd - diffStart, false); if(diffStart >= diffEnd) { // do nothing } else if(intercept.MapType == D3D11_MAP_WRITE_NO_OVERWRITE) { RDCASSERT(WrappedID3D11Buffer::IsAlloc(pResource)); ID3D11Buffer *mapContents = NULL; D3D11_BUFFER_DESC bdesc; bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bdesc.ByteWidth = diffEnd - diffStart; bdesc.CPUAccessFlags = 0; bdesc.MiscFlags = 0; bdesc.StructureByteStride = 0; bdesc.Usage = D3D11_USAGE_IMMUTABLE; D3D11_SUBRESOURCE_DATA data; data.pSysMem = MapWrittenData; data.SysMemPitch = bdesc.ByteWidth; data.SysMemSlicePitch = bdesc.ByteWidth; HRESULT hr = m_pDevice->GetReal()->CreateBuffer(&bdesc, &data, &mapContents); if(FAILED(hr)) { RDCERR("Failed to create temp Unmap() buffer HRESULT: %s", ToStr(hr).c_str()); } else { m_pRealContext->CopySubresourceRegion(GetResourceManager()->UnwrapResource(pResource), mapIdx.subresource, diffStart, 0, 0, mapContents, 0, NULL); SAFE_RELEASE(mapContents); } } else { D3D11_MAPPED_SUBRESOURCE mappedResource; UINT flags = intercept.MapFlags & ~D3D11_MAP_FLAG_DO_NOT_WAIT; HRESULT hr = m_pRealContext->Map(GetResourceManager()->UnwrapResource(pResource), mapIdx.subresource, intercept.MapType, flags, &mappedResource); RDCASSERT(mappedResource.pData); if(FAILED(hr)) { RDCERR("Failed to map resource, HRESULT: %s", ToStr(hr).c_str()); } else { intercept.SetD3D(mappedResource); intercept.InitWrappedResource(pResource, mapIdx.subresource, MapWrittenData); intercept.CopyToD3D(diffStart, diffEnd); m_pRealContext->Unmap(m_pDevice->GetResourceManager()->UnwrapResource(pResource), mapIdx.subresource); } } FreeAlignedBuffer(MapWrittenData); } return true; } void WrappedID3D11DeviceContext::Unmap(ID3D11Resource *pResource, UINT Subresource) { DrainAnnotationQueue(); m_EmptyCommandList = false; ResourceId id = GetIDForResource(pResource); auto it = m_OpenMaps.find(MappedResource(id, Subresource)); if(IsBackgroundCapturing(m_State) && m_HighTrafficResources.find(id) != m_HighTrafficResources.end()) { // we intercepted this, even though we now don't need to serialise it. Time to finish what we // started! if(it != m_OpenMaps.end() && it->second.MapType != D3D11_MAP_READ) { it->second.CopyToD3D(); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(it->first.resource); if(record) record->FreeShadowStorage(); m_OpenMaps.erase(it); } else if(it != m_OpenMaps.end()) { m_OpenMaps.erase(it); } } else if(IsCaptureMode(m_State)) { if(it == m_OpenMaps.end() && IsActiveCapturing(m_State)) { RDCWARN( "Saw an Unmap that we didn't capture the corresponding Map for - this frame is " "unsuccessful"); m_SuccessfulCapture = false; m_FailureReason = CaptureFailed_UncappedUnmap; } if(it != m_OpenMaps.end()) { if(it->second.MapType == D3D11_MAP_READ) { m_OpenMaps.erase(it); } else if(IsActiveCapturing(m_State)) { MarkResourceReferenced(it->first.resource, eFrameRef_Read); MarkResourceReferenced(it->first.resource, eFrameRef_Write); USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Unmap); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Unmap(GET_SERIALISER, pResource, Subresource); m_ContextRecord->AddChunk(scope.Get()); } else // IsIdleCapturing(m_State) { RDCASSERT(WrappedID3D11Buffer::IsAlloc(pResource) || WrappedID3D11Texture1D::IsAlloc(pResource) || WrappedID3D11Texture2D1::IsAlloc(pResource) || WrappedID3D11Texture3D1::IsAlloc(pResource)); D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(GetIDForResource(pResource)); RDCASSERT(record); D3D11ResourceRecord *baserecord = record; if(record->NumSubResources > (int)Subresource) record = (D3D11ResourceRecord *)record->SubResources[Subresource]; if(record->DataInSerialiser) { Serialise_Unmap(m_ScratchSerialiser, pResource, Subresource); // throw away any serialised data m_ScratchSerialiser.GetWriter()->Rewind(); } else { USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(D3D11Chunk::Unmap); SERIALISE_ELEMENT(m_ResourceID).Named("Context").TypedAs("ID3D11DeviceContext *"); Serialise_Unmap(GET_SERIALISER, pResource, Subresource); Chunk *chunk = scope.Get(); baserecord->AddChunk(chunk); record->SetDataPtr(chunk->GetData()); record->DataInSerialiser = true; } record->FreeShadowStorage(); } } } m_pRealContext->Unmap(m_pDevice->GetResourceManager()->UnwrapResource(pResource), Subresource); } #pragma endregion Map #undef IMPLEMENT_FUNCTION_SERIALISED #define IMPLEMENT_FUNCTION_SERIALISED(ret, func, ...) \ template bool WrappedID3D11DeviceContext::CONCAT(Serialise_, \ func(ReadSerialiser &ser, __VA_ARGS__)); \ template bool WrappedID3D11DeviceContext::CONCAT(Serialise_, \ func(WriteSerialiser &ser, __VA_ARGS__)); SERIALISED_ID3D11CONTEXT_FUNCTIONS(); SERIALISED_ID3D11CONTEXT_MARKER_FUNCTIONS();