mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-12 17:51:02 +00:00
* Note in some cases we still unconditionally return an object (like ID3D11InfoQueue) just for compatibility's sake if it's pretty ubiquitous and programs might expect it to always be there. This change however will stop us from reporting interfaces that might actually not be HW or OS supported.
1386 lines
37 KiB
C++
1386 lines
37 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* 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 "driver/d3d11/d3d11_device.h"
|
|
#include "driver/d3d11/d3d11_context.h"
|
|
#include "driver/d3d11/d3d11_renderstate.h"
|
|
#include "driver/d3d11/d3d11_manager.h"
|
|
#include "driver/d3d11/d3d11_resources.h"
|
|
|
|
#include "serialise/string_utils.h"
|
|
|
|
#include "replay/type_helpers.h"
|
|
|
|
WRAPPED_POOL_INST(WrappedID3D11DeviceContext);
|
|
WRAPPED_POOL_INST(WrappedID3D11CommandList);
|
|
|
|
|
|
#if defined(INCLUDE_D3D_11_1)
|
|
INT STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::BeginEvent(LPCWSTR Name)
|
|
{
|
|
if(m_Context)
|
|
return m_Context->PushEvent(0, Name);
|
|
|
|
return -1;
|
|
}
|
|
|
|
INT STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::EndEvent()
|
|
{
|
|
if(m_Context)
|
|
return m_Context->PopEvent();
|
|
|
|
return -1;
|
|
}
|
|
|
|
void STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::SetMarker(LPCWSTR Name)
|
|
{
|
|
if(m_Context)
|
|
return m_Context->SetMarker(0, Name);
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE WrappedID3DUserDefinedAnnotation::QueryInterface(REFIID riid, void **ppvObject)
|
|
{
|
|
//DEFINE_GUID(IID_ID3DUserDefinedAnnotation,0xb2daad8b,0x03d4,0x4dbf,0x95,0xeb,0x32,0xab,0x4b,0x63,0xd0,0xab);
|
|
static const GUID ID3D11UserDefinedAnnotation_uuid = { 0xb2daad8b, 0x03d4, 0x4dbf, { 0x95, 0xeb, 0x32, 0xab, 0x4b, 0x63, 0xd0, 0xab } };
|
|
|
|
if(riid == ID3D11UserDefinedAnnotation_uuid)
|
|
{
|
|
*ppvObject = (void *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
#endif
|
|
|
|
extern uint32_t NullCBOffsets[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
|
|
extern uint32_t NullCBCounts[D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT];
|
|
|
|
WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device* realDevice, ID3D11DeviceContext* context,
|
|
Serialiser *ser, Serialiser *debugser)
|
|
: RefCounter(context), m_pDevice(realDevice), m_pRealContext(context)
|
|
{
|
|
if(RenderDoc::Inst().GetCrashHandler())
|
|
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(WrappedID3D11DeviceContext));
|
|
|
|
for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
|
|
{
|
|
NullCBOffsets[i] = 0;
|
|
NullCBCounts[i] = 4096;
|
|
}
|
|
|
|
#if defined(INCLUDE_D3D_11_1)
|
|
D3D11_FEATURE_DATA_D3D11_OPTIONS features;
|
|
RDCEraseEl(features);
|
|
HRESULT hr = m_pDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &features, sizeof(features));
|
|
|
|
m_SetCBuffer1 = false;
|
|
if(SUCCEEDED(hr))
|
|
m_SetCBuffer1 = features.ConstantBufferOffsetting == TRUE;
|
|
|
|
m_pRealContext1 = NULL;
|
|
m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext1), (void **)&m_pRealContext1);
|
|
|
|
m_pRealContext2 = NULL;
|
|
m_pRealContext->QueryInterface(__uuidof(ID3D11DeviceContext2), (void **)&m_pRealContext2);
|
|
#endif
|
|
|
|
#if defined(RELEASE)
|
|
const bool debugSerialiser = false;
|
|
#else
|
|
const bool debugSerialiser = true;
|
|
#endif
|
|
|
|
if(RenderDoc::Inst().IsReplayApp())
|
|
{
|
|
m_State = READING;
|
|
m_pSerialiser = ser;
|
|
}
|
|
else
|
|
{
|
|
m_pSerialiser = new Serialiser(NULL, Serialiser::WRITING, debugSerialiser);
|
|
m_pDebugSerialiser = debugser;
|
|
m_State = WRITING_IDLE;
|
|
}
|
|
|
|
// create a temporary and grab its resource ID
|
|
m_ResourceID = TrackedResource().GetResourceID();
|
|
|
|
m_ContextRecord = NULL;
|
|
|
|
if(!RenderDoc::Inst().IsReplayApp())
|
|
{
|
|
m_ContextRecord = m_pDevice->GetResourceManager()->AddResourceRecord(m_ResourceID);
|
|
m_ContextRecord->DataInSerialiser = false;
|
|
m_ContextRecord->SpecialResource = true;
|
|
m_ContextRecord->Length = 0;
|
|
m_ContextRecord->NumSubResources = 0;
|
|
m_ContextRecord->SubResources = NULL;
|
|
m_ContextRecord->ignoreSerialise = true;
|
|
}
|
|
|
|
m_SuccessfulCapture = true;
|
|
m_FailureReason = CaptureSucceeded;
|
|
m_EmptyCommandList = true;
|
|
|
|
m_DrawcallStack.push_back(&m_ParentDrawcall);
|
|
|
|
m_CurEventID = 1;
|
|
m_CurDrawcallID = 1;
|
|
|
|
m_MarkerIndentLevel = 0;
|
|
#if defined(INCLUDE_D3D_11_1)
|
|
m_UserAnnotation.SetContext(this);
|
|
#endif
|
|
|
|
m_CurrentPipelineState = new D3D11RenderState((Serialiser *)NULL);
|
|
m_DoStateVerify = m_State >= WRITING;
|
|
|
|
if(context->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE)
|
|
{
|
|
m_CurrentPipelineState->SetImmediatePipeline(m_pDevice);
|
|
}
|
|
else
|
|
{
|
|
m_CurrentPipelineState->SetDevice(m_pDevice);
|
|
m_pDevice->SoftRef();
|
|
|
|
if(m_State >= WRITING && RenderDoc::Inst().GetCaptureOptions().CaptureAllCmdLists)
|
|
m_State = WRITING_CAPFRAME;
|
|
}
|
|
|
|
ReplayFakeContext(ResourceId());
|
|
}
|
|
|
|
WrappedID3D11DeviceContext::~WrappedID3D11DeviceContext()
|
|
{
|
|
if(m_ContextRecord)
|
|
m_ContextRecord->Delete(m_pDevice->GetResourceManager());
|
|
|
|
if(m_pRealContext->GetType() != D3D11_DEVICE_CONTEXT_IMMEDIATE)
|
|
m_pDevice->RemoveDeferredContext(this);
|
|
|
|
for(auto it = m_StreamOutCounters.begin(); it != m_StreamOutCounters.end(); ++it)
|
|
{
|
|
SAFE_RELEASE(it->second.query);
|
|
}
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
SAFE_DELETE(m_pSerialiser);
|
|
}
|
|
|
|
#if defined(INCLUDE_D3D_11_1)
|
|
SAFE_RELEASE(m_pRealContext1);
|
|
SAFE_RELEASE(m_pRealContext2);
|
|
#endif
|
|
|
|
SAFE_DELETE(m_CurrentPipelineState);
|
|
SAFE_RELEASE(m_pRealContext);
|
|
|
|
if(RenderDoc::Inst().GetCrashHandler())
|
|
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
|
|
}
|
|
|
|
const char *WrappedID3D11DeviceContext::GetChunkName(D3D11ChunkType idx)
|
|
{
|
|
return m_pDevice->GetChunkName(idx);
|
|
}
|
|
|
|
bool WrappedID3D11DeviceContext::Serialise_BeginCaptureFrame(bool applyInitialState)
|
|
{
|
|
D3D11RenderState state(m_pSerialiser);
|
|
|
|
if(m_State >= WRITING)
|
|
{
|
|
state = *m_CurrentPipelineState;
|
|
|
|
state.SetSerialiser(m_pSerialiser);
|
|
|
|
state.MarkReferenced(this, true);
|
|
}
|
|
|
|
state.Serialise(m_State, m_pDevice);
|
|
|
|
if(m_State <= EXECUTING && applyInitialState)
|
|
{
|
|
m_DoStateVerify = false;
|
|
{
|
|
*m_CurrentPipelineState = state;
|
|
m_CurrentPipelineState->SetDevice(m_pDevice);
|
|
state.ApplyState(this);
|
|
}
|
|
m_DoStateVerify = true;
|
|
VerifyState();
|
|
}
|
|
|
|
// stream-out hidden counters need to be saved, in case their results are used
|
|
// for a DrawAuto() somewhere. Each buffer used as a stream-out target has a hidden
|
|
// counter saved with it that stores the number of primitives written, which is then
|
|
// used for a DrawAuto(). If the stream-out happens in frame we don't need to worry,
|
|
// but if it references a buffer from before we need to have that counter available
|
|
// on replay to 'fake' the DrawAuto() just as a Draw() with known values
|
|
if(m_State >= WRITING)
|
|
{
|
|
// this may break API guarantees, but we need to fetch the hidden counters
|
|
// so we need to restart any queries for currently set SO targets.
|
|
// Potentially to be more correct we could defer fetching the results of queries
|
|
// that are still running until they get detached (as they must be detached
|
|
// before being used for any DrawAuto calls - if we're in CAPFRAME we could
|
|
// serialise the data then. If they're never detached, we don't need the results)
|
|
|
|
bool restart[4] = { false };
|
|
|
|
for(UINT b=0; b < 4; 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;
|
|
|
|
restart[b] = true;
|
|
}
|
|
}
|
|
|
|
D3D11_QUERY_DATA_SO_STATISTICS numPrims;
|
|
|
|
// readback all known counters
|
|
SERIALISE_ELEMENT(uint32_t, numStreamOutCounters, (uint32_t)m_StreamOutCounters.size());
|
|
for(auto it = m_StreamOutCounters.begin(); it != m_StreamOutCounters.end(); ++it)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, id, it->first);
|
|
|
|
RDCEraseEl(numPrims);
|
|
|
|
HRESULT hr = S_FALSE;
|
|
|
|
do
|
|
{
|
|
hr = m_pRealContext->GetData(it->second.query, &numPrims, sizeof(D3D11_QUERY_DATA_SO_STATISTICS), 0);
|
|
} while(hr == S_FALSE);
|
|
|
|
if(hr != S_OK)
|
|
{
|
|
numPrims.NumPrimitivesWritten = 0;
|
|
RDCERR("Couldn't retrieve hidden buffer counter for streamout on buffer %llx", id);
|
|
}
|
|
|
|
SERIALISE_ELEMENT(uint64_t, hiddenCounter, (uint64_t)numPrims.NumPrimitivesWritten);
|
|
}
|
|
|
|
// restart any counters we were forced to stop
|
|
for(UINT b=0; b < 4; b++)
|
|
{
|
|
ID3D11Buffer *buf = m_CurrentPipelineState->SO.Buffers[b];
|
|
|
|
if(buf && restart[b])
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
// version 5 added this set of data, we can assume for older logs there's just no counters
|
|
else if(m_pDevice->GetLogVersion() >= 0x000005)
|
|
{
|
|
// read in the known stream-out counters at the start of the frame.
|
|
// any stream-out that happens in the captured frame will be replayed
|
|
// and those counters will override this value when it comes to a
|
|
// DrawAuto()
|
|
SERIALISE_ELEMENT(uint32_t, numStreamOutCounters, 0);
|
|
for(uint32_t i=0; i < numStreamOutCounters; i++)
|
|
{
|
|
SERIALISE_ELEMENT(ResourceId, id, ResourceId());
|
|
SERIALISE_ELEMENT(uint64_t, hiddenCounter, 0);
|
|
|
|
m_StreamOutCounters[m_pDevice->GetResourceManager()->GetLiveID(id)].numPrims = hiddenCounter;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::MarkResourceReferenced(ResourceId id, FrameRefType refType)
|
|
{
|
|
if(m_pRealContext->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE)
|
|
{
|
|
m_pDevice->GetResourceManager()->MarkResourceFrameReferenced(id, refType);
|
|
}
|
|
else
|
|
{
|
|
m_ContextRecord->MarkResourceFrameReferenced(id, refType);
|
|
}
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::VerifyState()
|
|
{
|
|
#if 0
|
|
if(m_DoStateVerify)
|
|
{
|
|
D3D11RenderState state(this);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::BeginCaptureFrame()
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_HEADER);
|
|
m_pSerialiser->Serialise("context", m_ResourceID);
|
|
|
|
Serialise_BeginCaptureFrame(false);
|
|
|
|
{
|
|
SCOPED_LOCK(m_AnnotLock);
|
|
|
|
m_AnnotationQueue.clear();
|
|
}
|
|
|
|
m_ContextRecord->AddChunk(scope.Get(), 1);
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::AttemptCapture()
|
|
{
|
|
m_State = WRITING_CAPFRAME;
|
|
|
|
m_FailureReason = CaptureSucceeded;
|
|
|
|
// deferred contexts are initially NOT successful unless empty. That's because we don't have the serialised
|
|
// contents of whatever is in them up until now (could be anything).
|
|
// Only after they have been through a Finish() and then in CAPFRAME mode are they considered
|
|
// successful.
|
|
if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED)
|
|
{
|
|
RDCDEBUG("Deferred Context %llu Attempting capture - initially %s, %s", GetResourceID(), m_SuccessfulCapture ? "successful" : "unsuccessful", m_EmptyCommandList ? "empty" : "non-empty");
|
|
|
|
m_SuccessfulCapture |= m_EmptyCommandList;
|
|
|
|
if(m_SuccessfulCapture)
|
|
m_FailureReason = CaptureSucceeded;
|
|
else
|
|
m_FailureReason = CaptureFailed_UncappedCmdlist;
|
|
|
|
RDCDEBUG("Deferred Context %llu Attempting capture - now %s", GetResourceID(), m_SuccessfulCapture ? "successful" : "unsuccessful");
|
|
}
|
|
else
|
|
{
|
|
RDCDEBUG("Immediate Context %llu Attempting capture", GetResourceID());
|
|
|
|
m_SuccessfulCapture = true;
|
|
m_FailureReason = CaptureSucceeded;
|
|
|
|
for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it)
|
|
(*it)->Delete(m_pDevice->GetResourceManager());
|
|
m_DeferredRecords.clear();
|
|
|
|
m_ContextRecord->LockChunks();
|
|
while(m_ContextRecord->HasChunks())
|
|
{
|
|
Chunk *chunk = m_ContextRecord->GetLastChunk();
|
|
|
|
SAFE_DELETE(chunk);
|
|
m_ContextRecord->PopChunk();
|
|
}
|
|
m_ContextRecord->UnlockChunks();
|
|
|
|
m_ContextRecord->FreeParents(m_pDevice->GetResourceManager());
|
|
}
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::FinishCapture()
|
|
{
|
|
if(GetType() != D3D11_DEVICE_CONTEXT_DEFERRED || !RenderDoc::Inst().GetCaptureOptions().CaptureAllCmdLists)
|
|
{
|
|
m_State = WRITING_IDLE;
|
|
|
|
m_SuccessfulCapture = false;
|
|
m_FailureReason = CaptureSucceeded;
|
|
}
|
|
|
|
for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it)
|
|
{
|
|
m_ContextRecord->AddParent(*it);
|
|
(*it)->Delete(m_pDevice->GetResourceManager());
|
|
}
|
|
m_DeferredRecords.clear();
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::EndCaptureFrame()
|
|
{
|
|
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER);
|
|
m_pSerialiser->Serialise("context", m_ResourceID);
|
|
|
|
bool HasCallstack = RenderDoc::Inst().GetCaptureOptions().CaptureCallstacks != 0;
|
|
m_pSerialiser->Serialise("HasCallstack", HasCallstack);
|
|
|
|
if(HasCallstack)
|
|
{
|
|
Callstack::Stackwalk *call = Callstack::Collect();
|
|
|
|
RDCASSERT(call->NumLevels() < 0xff);
|
|
|
|
size_t numLevels = call->NumLevels();
|
|
uint64_t *stack = (uint64_t *)call->GetAddrs();
|
|
|
|
m_pSerialiser->Serialise("callstack", stack, numLevels);
|
|
|
|
delete call;
|
|
}
|
|
|
|
m_ContextRecord->AddChunk(scope.Get());
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::FreeCaptureData()
|
|
{
|
|
for(auto it = WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it)
|
|
{
|
|
D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(it->first);
|
|
|
|
if(record == NULL) continue;
|
|
|
|
bool inuse = false;
|
|
for(auto mapit=m_OpenMaps.begin(); mapit != m_OpenMaps.end(); ++mapit)
|
|
{
|
|
if(mapit->first.resource == it->first)
|
|
{
|
|
inuse = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(inuse) continue;
|
|
|
|
record->FreeShadowStorage();
|
|
}
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::CleanupCapture()
|
|
{
|
|
if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED)
|
|
{
|
|
m_SuccessfulCapture |= m_EmptyCommandList;
|
|
|
|
if(m_SuccessfulCapture)
|
|
m_FailureReason = CaptureSucceeded;
|
|
else
|
|
m_FailureReason = CaptureFailed_UncappedCmdlist;
|
|
|
|
for(auto it=m_MapResourceRecordAllocs.begin(); it != m_MapResourceRecordAllocs.end(); ++it)
|
|
{
|
|
D3D11ResourceRecord *record = m_pDevice->GetResourceManager()->GetResourceRecord(it->first);
|
|
if(record) record->FreeContextID(it->second);
|
|
}
|
|
|
|
if(RenderDoc::Inst().GetCaptureOptions().CaptureAllCmdLists)
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
m_SuccessfulCapture = true;
|
|
m_FailureReason = CaptureSucceeded;
|
|
}
|
|
|
|
for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it)
|
|
(*it)->Delete(m_pDevice->GetResourceManager());
|
|
m_DeferredRecords.clear();
|
|
|
|
m_ContextRecord->LockChunks();
|
|
while(m_ContextRecord->HasChunks())
|
|
{
|
|
Chunk *chunk = m_ContextRecord->GetLastChunk();
|
|
|
|
SAFE_DELETE(chunk);
|
|
m_ContextRecord->PopChunk();
|
|
}
|
|
m_ContextRecord->UnlockChunks();
|
|
|
|
m_ContextRecord->FreeParents(m_pDevice->GetResourceManager());
|
|
|
|
for(auto it=m_MissingTracks.begin(); it != m_MissingTracks.end(); ++it)
|
|
{
|
|
if(m_pDevice->GetResourceManager()->HasResourceRecord(*it))
|
|
m_pDevice->GetResourceManager()->MarkDirtyResource(*it);
|
|
}
|
|
|
|
m_MissingTracks.clear();
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::BeginFrame()
|
|
{
|
|
{
|
|
SCOPED_LOCK(m_AnnotLock);
|
|
m_AnnotationQueue.clear();
|
|
}
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::EndFrame()
|
|
{
|
|
DrainAnnotationQueue();
|
|
|
|
m_pDevice->GetResourceManager()->FlushPendingDirty();
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::ProcessChunk(uint64_t offset, D3D11ChunkType chunk, bool forceExecute)
|
|
{
|
|
if(chunk < FIRST_CONTEXT_CHUNK && !forceExecute)
|
|
{
|
|
if(m_State == READING)
|
|
{
|
|
m_pDevice->GetResourceManager()->MarkInFrame(false);
|
|
|
|
m_pDevice->ProcessChunk(offset, chunk);
|
|
m_pSerialiser->PopContext(NULL, chunk);
|
|
|
|
m_pDevice->GetResourceManager()->MarkInFrame(true);
|
|
}
|
|
else if(m_State == EXECUTING)
|
|
{
|
|
m_pSerialiser->SkipCurrentChunk();
|
|
m_pSerialiser->PopContext(NULL, chunk);
|
|
}
|
|
return;
|
|
}
|
|
|
|
m_CurChunkOffset = offset;
|
|
|
|
RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE);
|
|
|
|
uint64_t cOffs = m_pSerialiser->GetOffset();
|
|
|
|
ResourceId ctxId;
|
|
m_pSerialiser->Serialise("context", ctxId);
|
|
|
|
WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(ctxId);
|
|
|
|
if(m_FakeContext != ResourceId())
|
|
{
|
|
if(m_FakeContext == ctxId)
|
|
context = this;
|
|
else
|
|
{
|
|
m_pSerialiser->SetOffset(cOffs);
|
|
m_pSerialiser->SkipCurrentChunk();
|
|
m_pSerialiser->PopContext(NULL, chunk);
|
|
return;
|
|
}
|
|
}
|
|
|
|
RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context));
|
|
|
|
LogState state = context->m_State;
|
|
|
|
if(forceExecute)
|
|
context->m_State = EXECUTING;
|
|
else
|
|
context->m_State = m_State;
|
|
|
|
m_AddedDrawcall = false;
|
|
|
|
switch(chunk)
|
|
{
|
|
case SET_INPUT_LAYOUT:
|
|
context->Serialise_IASetInputLayout(0x0);
|
|
break;
|
|
case SET_VBUFFER:
|
|
context->Serialise_IASetVertexBuffers(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
case SET_IBUFFER:
|
|
context->Serialise_IASetIndexBuffer(0, DXGI_FORMAT_UNKNOWN, 0);
|
|
break;
|
|
case SET_TOPOLOGY:
|
|
context->Serialise_IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED);
|
|
break;
|
|
|
|
case SET_VS_CBUFFERS:
|
|
context->Serialise_VSSetConstantBuffers(0, 0, 0x0);
|
|
break;
|
|
case SET_VS_RESOURCES:
|
|
context->Serialise_VSSetShaderResources(0, 0, 0x0);
|
|
break;
|
|
case SET_VS_SAMPLERS:
|
|
context->Serialise_VSSetSamplers(0, 0, 0x0);
|
|
break;
|
|
case SET_VS:
|
|
context->Serialise_VSSetShader(0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_HS_CBUFFERS:
|
|
context->Serialise_HSSetConstantBuffers(0, 0, 0x0);
|
|
break;
|
|
case SET_HS_RESOURCES:
|
|
context->Serialise_HSSetShaderResources(0, 0, 0x0);
|
|
break;
|
|
case SET_HS_SAMPLERS:
|
|
context->Serialise_HSSetSamplers(0, 0, 0x0);
|
|
break;
|
|
case SET_HS:
|
|
context->Serialise_HSSetShader(0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_DS_CBUFFERS:
|
|
context->Serialise_DSSetConstantBuffers(0, 0, 0x0);
|
|
break;
|
|
case SET_DS_RESOURCES:
|
|
context->Serialise_DSSetShaderResources(0, 0, 0x0);
|
|
break;
|
|
case SET_DS_SAMPLERS:
|
|
context->Serialise_DSSetSamplers(0, 0, 0x0);
|
|
break;
|
|
case SET_DS:
|
|
context->Serialise_DSSetShader(0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_GS_CBUFFERS:
|
|
context->Serialise_GSSetConstantBuffers(0, 0, 0x0);
|
|
break;
|
|
case SET_GS_RESOURCES:
|
|
context->Serialise_GSSetShaderResources(0, 0, 0x0);
|
|
break;
|
|
case SET_GS_SAMPLERS:
|
|
context->Serialise_GSSetSamplers(0, 0, 0x0);
|
|
break;
|
|
case SET_GS:
|
|
context->Serialise_GSSetShader(0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_SO_TARGETS:
|
|
context->Serialise_SOSetTargets(0, 0x0, 0x0);
|
|
break;
|
|
|
|
case SET_PS_CBUFFERS:
|
|
context->Serialise_PSSetConstantBuffers(0, 0, 0x0);
|
|
break;
|
|
case SET_PS_RESOURCES:
|
|
context->Serialise_PSSetShaderResources(0, 0, 0x0);
|
|
break;
|
|
case SET_PS_SAMPLERS:
|
|
context->Serialise_PSSetSamplers(0, 0, 0x0);
|
|
break;
|
|
case SET_PS:
|
|
context->Serialise_PSSetShader(0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_CS_CBUFFERS:
|
|
context->Serialise_CSSetConstantBuffers(0, 0, 0x0);
|
|
break;
|
|
case SET_CS_RESOURCES:
|
|
context->Serialise_CSSetShaderResources(0, 0, 0x0);
|
|
break;
|
|
case SET_CS_UAVS:
|
|
context->Serialise_CSSetUnorderedAccessViews(0, 0, 0x0, 0x0);
|
|
break;
|
|
case SET_CS_SAMPLERS:
|
|
context->Serialise_CSSetSamplers(0, 0, 0x0);
|
|
break;
|
|
case SET_CS:
|
|
context->Serialise_CSSetShader(0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_VIEWPORTS:
|
|
context->Serialise_RSSetViewports(0, 0x0);
|
|
break;
|
|
case SET_SCISSORS:
|
|
context->Serialise_RSSetScissorRects(0, 0x0);
|
|
break;
|
|
case SET_RASTER:
|
|
context->Serialise_RSSetState(0x0);
|
|
break;
|
|
|
|
case SET_RTARGET:
|
|
context->Serialise_OMSetRenderTargets(0, 0x0, 0x0);
|
|
break;
|
|
case SET_RTARGET_AND_UAVS:
|
|
context->Serialise_OMSetRenderTargetsAndUnorderedAccessViews(0, 0x0, 0x0, 0, 0, 0x0, 0x0);
|
|
break;
|
|
case SET_BLEND:
|
|
context->Serialise_OMSetBlendState(0x0, (FLOAT*)0x0, 0);
|
|
break;
|
|
case SET_DEPTHSTENCIL:
|
|
context->Serialise_OMSetDepthStencilState(0x0, 0);
|
|
break;
|
|
|
|
case DRAW_INDEXED_INST:
|
|
context->Serialise_DrawIndexedInstanced(0, 0, 0, 0, 0);
|
|
break;
|
|
case DRAW_INST:
|
|
context->Serialise_DrawInstanced(0, 0, 0, 0);
|
|
break;
|
|
case DRAW_INDEXED:
|
|
context->Serialise_DrawIndexed(0, 0, 0);
|
|
break;
|
|
case DRAW:
|
|
context->Serialise_Draw(0, 0);
|
|
break;
|
|
case DRAW_AUTO:
|
|
context->Serialise_DrawAuto();
|
|
break;
|
|
case DRAW_INDEXED_INST_INDIRECT:
|
|
context->Serialise_DrawIndexedInstancedIndirect(0x0, 0);
|
|
break;
|
|
case DRAW_INST_INDIRECT:
|
|
context->Serialise_DrawInstancedIndirect(0x0, 0);
|
|
break;
|
|
|
|
case MAP:
|
|
context->Serialise_Map(0, 0, (D3D11_MAP)0, 0, 0);
|
|
break;
|
|
case UNMAP:
|
|
context->Serialise_Unmap(0, 0);
|
|
break;
|
|
|
|
case COPY_SUBRESOURCE_REGION:
|
|
context->Serialise_CopySubresourceRegion(0x0, 0, 0, 0, 0, 0x0, 0, 0x0);
|
|
break;
|
|
case COPY_RESOURCE:
|
|
context->Serialise_CopyResource(0x0, 0x0);
|
|
break;
|
|
case UPDATE_SUBRESOURCE:
|
|
context->Serialise_UpdateSubresource(0x0, 0, 0x0, 0x0, 0, 0);
|
|
break;
|
|
case COPY_STRUCTURE_COUNT:
|
|
context->Serialise_CopyStructureCount(0x0, 0, 0x0);
|
|
break;
|
|
case RESOLVE_SUBRESOURCE:
|
|
context->Serialise_ResolveSubresource(0x0, 0, 0x0, 0, DXGI_FORMAT_UNKNOWN);
|
|
break;
|
|
case GENERATE_MIPS:
|
|
context->Serialise_GenerateMips(0x0);
|
|
break;
|
|
|
|
case CLEAR_DSV:
|
|
context->Serialise_ClearDepthStencilView(0x0, 0, 0.0f, 0);
|
|
break;
|
|
case CLEAR_RTV:
|
|
context->Serialise_ClearRenderTargetView(0x0, (FLOAT*)0x0);
|
|
break;
|
|
case CLEAR_UAV_INT:
|
|
context->Serialise_ClearUnorderedAccessViewUint(0x0, (UINT*)0x0);
|
|
break;
|
|
case CLEAR_UAV_FLOAT:
|
|
context->Serialise_ClearUnorderedAccessViewFloat(0x0, (FLOAT*)0x0);
|
|
break;
|
|
case CLEAR_STATE:
|
|
context->Serialise_ClearState();
|
|
break;
|
|
|
|
case EXECUTE_CMD_LIST:
|
|
context->Serialise_ExecuteCommandList(0x0, 0);
|
|
break;
|
|
case DISPATCH:
|
|
context->Serialise_Dispatch(0, 0, 0);
|
|
break;
|
|
case DISPATCH_INDIRECT:
|
|
context->Serialise_DispatchIndirect(0x0, 0);
|
|
break;
|
|
case FINISH_CMD_LIST:
|
|
context->Serialise_FinishCommandList(0, 0x0);
|
|
break;
|
|
case FLUSH:
|
|
context->Serialise_Flush();
|
|
break;
|
|
|
|
case SET_PREDICATION:
|
|
context->Serialise_SetPredication(0x0, 0x0);
|
|
break;
|
|
case SET_RESOURCE_MINLOD:
|
|
context->Serialise_SetResourceMinLOD(0x0, 0);
|
|
break;
|
|
|
|
case BEGIN:
|
|
context->Serialise_Begin(0x0);
|
|
break;
|
|
case END:
|
|
context->Serialise_End(0x0);
|
|
break;
|
|
|
|
#if defined(INCLUDE_D3D_11_1)
|
|
case COPY_SUBRESOURCE_REGION1:
|
|
context->Serialise_CopySubresourceRegion1(0x0, 0, 0, 0, 0, 0x0, 0, 0x0, 0);
|
|
break;
|
|
case UPDATE_SUBRESOURCE1:
|
|
context->Serialise_UpdateSubresource1(0x0, 0, 0x0, 0x0, 0, 0, 0);
|
|
break;
|
|
case CLEAR_VIEW:
|
|
context->Serialise_ClearView(0x0, 0x0, 0x0, 0);
|
|
break;
|
|
|
|
case SET_VS_CBUFFERS1:
|
|
context->Serialise_VSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
case SET_HS_CBUFFERS1:
|
|
context->Serialise_HSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
case SET_DS_CBUFFERS1:
|
|
context->Serialise_DSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
case SET_GS_CBUFFERS1:
|
|
context->Serialise_GSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
case SET_PS_CBUFFERS1:
|
|
context->Serialise_PSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
case SET_CS_CBUFFERS1:
|
|
context->Serialise_CSSetConstantBuffers1(0, 0, 0x0, 0x0, 0x0);
|
|
break;
|
|
#else
|
|
case COPY_SUBRESOURCE_REGION1:
|
|
case UPDATE_SUBRESOURCE1:
|
|
case CLEAR_VIEW:
|
|
case SET_VS_CBUFFERS1:
|
|
case SET_HS_CBUFFERS1:
|
|
case SET_DS_CBUFFERS1:
|
|
case SET_GS_CBUFFERS1:
|
|
case SET_PS_CBUFFERS1:
|
|
case SET_CS_CBUFFERS1:
|
|
RDCERR("Replaying log with D3D11.1 events on a build without D3D11.1 support");
|
|
break;
|
|
#endif
|
|
|
|
case PUSH_EVENT:
|
|
context->Serialise_PushEvent(0, L"");
|
|
break;
|
|
case SET_MARKER:
|
|
context->Serialise_SetMarker(0, L"");
|
|
break;
|
|
case POP_EVENT:
|
|
context->Serialise_PopEvent();
|
|
break;
|
|
|
|
case CONTEXT_CAPTURE_FOOTER:
|
|
{
|
|
bool HasCallstack = false;
|
|
m_pSerialiser->Serialise("HasCallstack", HasCallstack);
|
|
|
|
if(HasCallstack)
|
|
{
|
|
size_t numLevels = 0;
|
|
uint64_t *stack = NULL;
|
|
|
|
m_pSerialiser->Serialise("callstack", stack, numLevels);
|
|
|
|
m_pSerialiser->SetCallstack(stack, numLevels);
|
|
|
|
SAFE_DELETE_ARRAY(stack);
|
|
}
|
|
|
|
if(m_State == READING)
|
|
{
|
|
AddEvent(CONTEXT_CAPTURE_FOOTER, "IDXGISwapChain::Present()");
|
|
|
|
FetchDrawcall draw;
|
|
draw.name = "Present()";
|
|
draw.flags |= eDraw_Present;
|
|
|
|
AddDrawcall(draw, true);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
RDCERR("Unrecognised Chunk type %d", chunk);
|
|
break;
|
|
}
|
|
|
|
m_pSerialiser->PopContext(NULL, chunk);
|
|
|
|
if(context->m_State == READING && chunk == SET_MARKER)
|
|
{
|
|
// no push/pop necessary
|
|
}
|
|
else if(context->m_State == READING && chunk == PUSH_EVENT)
|
|
{
|
|
// push down the drawcallstack to the latest drawcall
|
|
context->m_DrawcallStack.push_back(&context->m_DrawcallStack.back()->children.back());
|
|
}
|
|
else if(context->m_State == READING && chunk == POP_EVENT)
|
|
{
|
|
// refuse to pop off further than the root drawcall (mismatched begin/end events e.g.)
|
|
RDCASSERT(context->m_DrawcallStack.size() > 1);
|
|
if(context->m_DrawcallStack.size() > 1)
|
|
context->m_DrawcallStack.pop_back();
|
|
}
|
|
else if(context->m_State == READING)
|
|
{
|
|
if(!m_AddedDrawcall)
|
|
context->AddEvent(chunk, m_pSerialiser->GetDebugStr());
|
|
}
|
|
|
|
m_AddedDrawcall = false;
|
|
|
|
if(forceExecute)
|
|
context->m_State = state;
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::AddUsage(FetchDrawcall d)
|
|
{
|
|
const D3D11RenderState *pipe = m_CurrentPipelineState;
|
|
uint32_t e = d.eventID;
|
|
|
|
if((d.flags & (eDraw_Drawcall|eDraw_Dispatch|eDraw_CmdList)) == 0)
|
|
return;
|
|
|
|
//////////////////////////////
|
|
// IA
|
|
|
|
if(d.flags & eDraw_UseIBuffer && pipe->IA.IndexBuffer != NULL)
|
|
m_ResourceUses[GetIDForResource(pipe->IA.IndexBuffer)].push_back(EventUsage(e, eUsage_IA_IB));
|
|
|
|
for(int i=0; i < D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT; i++)
|
|
if(pipe->IA.Used_VB(m_pDevice, i))
|
|
m_ResourceUses[GetIDForResource(pipe->IA.VBs[i])].push_back(EventUsage(e, eUsage_IA_VB));
|
|
|
|
//////////////////////////////
|
|
// Shaders
|
|
|
|
const D3D11RenderState::shader *shArr = &pipe->VS;
|
|
for(int s=0; s < 6; s++)
|
|
{
|
|
const D3D11RenderState::shader &sh = shArr[s];
|
|
|
|
for(int i=0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_API_SLOT_COUNT; i++)
|
|
if(sh.Used_CB(i))
|
|
m_ResourceUses[GetIDForResource(sh.ConstantBuffers[i])].push_back(EventUsage(e, (ResourceUsage)(eUsage_VS_CB+s)));
|
|
|
|
for(int i=0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_SLOT_COUNT; i++)
|
|
if(sh.Used_SRV(i))
|
|
m_ResourceUses[((WrappedID3D11ShaderResourceView *)sh.SRVs[i])->GetResourceResID()].push_back(EventUsage(e, (ResourceUsage)(eUsage_VS_SRV+s)));
|
|
|
|
if(s == 5)
|
|
{
|
|
for(int i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++)
|
|
if(pipe->CS.Used_UAV(i) && pipe->CS.UAVs[i])
|
|
m_ResourceUses[((WrappedID3D11UnorderedAccessView *)pipe->CS.UAVs[i])->GetResourceResID()].push_back(EventUsage(e, eUsage_CS_UAV));
|
|
}
|
|
}
|
|
|
|
//////////////////////////////
|
|
// SO
|
|
|
|
for(int i=0; i < D3D11_SO_BUFFER_SLOT_COUNT; i++)
|
|
if(pipe->SO.Buffers[i]) // assuming for now that any SO target bound is used.
|
|
m_ResourceUses[GetIDForResource(pipe->SO.Buffers[i])].push_back(EventUsage(e, eUsage_SO));
|
|
|
|
//////////////////////////////
|
|
// OM
|
|
|
|
for(int i=0; i < D3D11_PS_CS_UAV_REGISTER_COUNT; i++)
|
|
if(pipe->PS.Used_UAV(i) && pipe->OM.UAVs[i])
|
|
m_ResourceUses[((WrappedID3D11UnorderedAccessView *)pipe->OM.UAVs[i])->GetResourceResID()].push_back(EventUsage(e, eUsage_PS_UAV));
|
|
|
|
if(pipe->OM.DepthView) // assuming for now that any DSV bound is used.
|
|
m_ResourceUses[((WrappedID3D11DepthStencilView *)pipe->OM.DepthView)->GetResourceResID()].push_back(EventUsage(e, eUsage_OM_DSV));
|
|
|
|
for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
|
|
if(pipe->OM.RenderTargets[i]) // assuming for now that any RTV bound is used.
|
|
m_ResourceUses[((WrappedID3D11RenderTargetView *)pipe->OM.RenderTargets[i])->GetResourceResID()].push_back(EventUsage(e, eUsage_OM_RTV));
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::RefreshDrawcallIDs(DrawcallTreeNode &node)
|
|
{
|
|
if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED)
|
|
{
|
|
m_pDevice->GetImmediateContext()->RefreshDrawcallIDs(node);
|
|
return;
|
|
}
|
|
|
|
// assign new drawcall IDs
|
|
for(size_t i=0; i < node.children.size(); i++)
|
|
{
|
|
m_CurEventID++;
|
|
|
|
node.children[i].draw.eventID = m_CurEventID;
|
|
node.children[i].draw.drawcallID = m_CurDrawcallID;
|
|
|
|
// markers don't increment drawcall ID
|
|
if((node.children[i].draw.flags & (eDraw_SetMarker|eDraw_PushMarker)) == 0)
|
|
m_CurDrawcallID++;
|
|
|
|
RefreshDrawcallIDs(node.children[i]);
|
|
}
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::AddDrawcall(FetchDrawcall d, bool hasEvents)
|
|
{
|
|
if(d.context == ResourceId()) d.context = m_pDevice->GetResourceManager()->GetOriginalID(m_ResourceID);
|
|
|
|
if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED)
|
|
{
|
|
m_pDevice->GetImmediateContext()->AddDrawcall(d, hasEvents);
|
|
return;
|
|
}
|
|
|
|
m_AddedDrawcall = true;
|
|
|
|
WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(d.context);
|
|
|
|
RDCASSERT(context);
|
|
|
|
FetchDrawcall draw = d;
|
|
draw.eventID = m_CurEventID;
|
|
draw.drawcallID = m_CurDrawcallID;
|
|
|
|
draw.indexByteWidth = 0;
|
|
if(m_CurrentPipelineState->IA.IndexFormat == DXGI_FORMAT_R16_UINT)
|
|
draw.indexByteWidth = 2;
|
|
if(m_CurrentPipelineState->IA.IndexFormat == DXGI_FORMAT_R32_UINT)
|
|
draw.indexByteWidth = 4;
|
|
|
|
draw.topology = MakePrimitiveTopology(m_CurrentPipelineState->IA.Topo);
|
|
|
|
for(int i=0; i < D3D11_SIMULTANEOUS_RENDER_TARGET_COUNT; i++)
|
|
{
|
|
draw.outputs[i] = ResourceId();
|
|
if(m_CurrentPipelineState->OM.RenderTargets[i])
|
|
draw.outputs[i] = ((WrappedID3D11RenderTargetView *)m_CurrentPipelineState->OM.RenderTargets[i])->GetResourceResID();
|
|
}
|
|
|
|
{
|
|
draw.depthOut = ResourceId();
|
|
if(m_CurrentPipelineState->OM.DepthView)
|
|
draw.depthOut = ((WrappedID3D11DepthStencilView *)m_CurrentPipelineState->OM.DepthView)->GetResourceResID();
|
|
}
|
|
|
|
// markers don't increment drawcall ID
|
|
if((draw.flags & (eDraw_SetMarker|eDraw_PushMarker)) == 0)
|
|
m_CurDrawcallID++;
|
|
|
|
if(hasEvents)
|
|
{
|
|
vector<FetchAPIEvent> evs;
|
|
evs.reserve(m_CurEvents.size());
|
|
for(size_t i=0; i < m_CurEvents.size(); )
|
|
{
|
|
if(m_CurEvents[i].context == draw.context)
|
|
{
|
|
evs.push_back(m_CurEvents[i]);
|
|
m_CurEvents.erase(m_CurEvents.begin()+i);
|
|
}
|
|
else
|
|
{
|
|
i++;
|
|
}
|
|
}
|
|
|
|
draw.events = evs;
|
|
}
|
|
|
|
AddUsage(draw);
|
|
|
|
// should have at least the root drawcall here, push this drawcall
|
|
// onto the back's children list.
|
|
if(!context->m_DrawcallStack.empty())
|
|
{
|
|
DrawcallTreeNode node(draw);
|
|
node.children.insert(node.children.begin(), draw.children.elems, draw.children.elems+draw.children.count);
|
|
context->m_DrawcallStack.back()->children.push_back(node);
|
|
}
|
|
else
|
|
RDCERR("Somehow lost drawcall stack!");
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::AddEvent(D3D11ChunkType type, string description, ResourceId ctx)
|
|
{
|
|
if(ctx == ResourceId()) ctx = m_pDevice->GetResourceManager()->GetOriginalID(m_ResourceID);
|
|
|
|
if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED)
|
|
{
|
|
m_pDevice->GetImmediateContext()->AddEvent(type, description, ctx);
|
|
return;
|
|
}
|
|
|
|
FetchAPIEvent apievent;
|
|
|
|
apievent.context = ctx;
|
|
apievent.fileOffset = m_CurChunkOffset;
|
|
apievent.eventID = m_CurEventID;
|
|
|
|
apievent.eventDesc = description;
|
|
|
|
Callstack::Stackwalk *stack = m_pSerialiser->GetLastCallstack();
|
|
if(stack)
|
|
{
|
|
create_array(apievent.callstack, stack->NumLevels());
|
|
memcpy(apievent.callstack.elems, stack->GetAddrs(), sizeof(uint64_t)*stack->NumLevels());
|
|
}
|
|
|
|
m_CurEvents.push_back(apievent);
|
|
|
|
if(m_State == READING)
|
|
m_Events.push_back(apievent);
|
|
}
|
|
|
|
FetchAPIEvent WrappedID3D11DeviceContext::GetEvent(uint32_t eventID)
|
|
{
|
|
for(size_t i=m_Events.size()-1; i > 0; i--)
|
|
{
|
|
if(m_Events[i].eventID <= eventID)
|
|
return m_Events[i];
|
|
}
|
|
|
|
return m_Events[0];
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::ReplayFakeContext(ResourceId id)
|
|
{
|
|
m_FakeContext = id;
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial)
|
|
{
|
|
m_State = readType;
|
|
|
|
m_DoStateVerify = true;
|
|
|
|
D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false);
|
|
RDCASSERT(header == CONTEXT_CAPTURE_HEADER);
|
|
|
|
ResourceId id;
|
|
m_pSerialiser->Serialise("context", id);
|
|
|
|
WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(id);
|
|
|
|
RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context) && context == this);
|
|
|
|
Serialise_BeginCaptureFrame(!partial);
|
|
|
|
m_pSerialiser->PopContext(NULL, header);
|
|
|
|
m_CurEvents.clear();
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
FetchAPIEvent ev = GetEvent(startEventID);
|
|
m_CurEventID = ev.eventID;
|
|
m_pSerialiser->SetOffset(ev.fileOffset);
|
|
}
|
|
else if(m_State == READING)
|
|
{
|
|
m_CurEventID = 1;
|
|
}
|
|
|
|
if(m_State == EXECUTING)
|
|
{
|
|
ClearMaps();
|
|
for(size_t i=0; i < m_pDevice->GetNumDeferredContexts(); i++)
|
|
{
|
|
WrappedID3D11DeviceContext *context = m_pDevice->GetDeferredContext(i);
|
|
context->ClearMaps();
|
|
}
|
|
}
|
|
|
|
m_pDevice->GetResourceManager()->MarkInFrame(true);
|
|
|
|
while(1)
|
|
{
|
|
if(m_State == EXECUTING && m_CurEventID > endEventID)
|
|
{
|
|
// we can just break out if we've done all the events desired.
|
|
break;
|
|
}
|
|
|
|
uint64_t offset = m_pSerialiser->GetOffset();
|
|
|
|
D3D11ChunkType context = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false);
|
|
|
|
ProcessChunk(offset, context, false);
|
|
|
|
RenderDoc::Inst().SetProgress(FileInitialRead, float(offset)/float(m_pSerialiser->GetSize()));
|
|
|
|
// for now just abort after capture scope. Really we'd need to support multiple frames
|
|
// but for now this will do.
|
|
if(context == CONTEXT_CAPTURE_FOOTER)
|
|
break;
|
|
|
|
m_CurEventID++;
|
|
}
|
|
|
|
if(m_State == READING)
|
|
{
|
|
m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake();
|
|
m_pDevice->GetFrameRecord().back().frameInfo.debugMessages = m_pDevice->GetDebugMessages();
|
|
|
|
m_ParentDrawcall.children.clear();
|
|
|
|
int initialSkips = 0;
|
|
|
|
for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it)
|
|
m_ResourceUses[it->first];
|
|
|
|
for(auto it=WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it)
|
|
m_ResourceUses[it->first];
|
|
for(auto it=WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it)
|
|
m_ResourceUses[it->first];
|
|
for(auto it=WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it)
|
|
m_ResourceUses[it->first];
|
|
|
|
for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it)
|
|
{
|
|
ResourceId id = m_pDevice->GetResourceManager()->GetOriginalID(it->first);
|
|
|
|
if(m_pDevice->GetResourceManager()->GetInitialContents(id).resource == NULL)
|
|
continue;
|
|
|
|
RDCDEBUG("Resource %llu", id);
|
|
if(it->second.empty())
|
|
{
|
|
RDCDEBUG("Never used!");
|
|
initialSkips++;
|
|
}
|
|
else
|
|
{
|
|
bool written = false;
|
|
|
|
for(auto usit = it->second.begin(); usit != it->second.end(); ++usit)
|
|
{
|
|
ResourceUsage u = usit->usage;
|
|
|
|
if(u == eUsage_SO ||
|
|
u == eUsage_CS_UAV || u == eUsage_PS_UAV ||
|
|
u == eUsage_OM_DSV || u == eUsage_OM_RTV)
|
|
{
|
|
written = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(written)
|
|
{
|
|
RDCDEBUG("Written in frame - needs initial state");
|
|
}
|
|
else
|
|
{
|
|
RDCDEBUG("Never written to in the frame");
|
|
initialSkips++;
|
|
}
|
|
}
|
|
}
|
|
|
|
RDCDEBUG("Can skip %d initial states.", initialSkips);
|
|
}
|
|
|
|
m_pDevice->GetResourceManager()->MarkInFrame(false);
|
|
|
|
m_State = READING;
|
|
|
|
m_DoStateVerify = false;
|
|
}
|
|
|
|
void WrappedID3D11DeviceContext::ClearMaps()
|
|
{
|
|
auto it = m_OpenMaps.begin();
|
|
|
|
for(; it != m_OpenMaps.end(); ++it)
|
|
{
|
|
RDCASSERT(m_pDevice->GetResourceManager()->HasLiveResource(it->first.resource));
|
|
|
|
ID3D11Resource *res = (ID3D11Resource *)m_pDevice->GetResourceManager()->GetLiveResource(it->first.resource);
|
|
|
|
m_pRealContext->Unmap(m_pDevice->GetResourceManager()->UnwrapResource(res), it->first.subresource);
|
|
}
|
|
|
|
m_OpenMaps.clear();
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE WrappedID3D11DeviceContext::QueryInterface( REFIID riid, void **ppvObject )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if(riid == __uuidof(ID3D11DeviceContext))
|
|
{
|
|
*ppvObject = (ID3D11DeviceContext *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else if(riid == __uuidof(ID3D11DeviceChild))
|
|
{
|
|
*ppvObject = (ID3D11DeviceChild *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
#if defined(INCLUDE_D3D_11_1)
|
|
else if(riid == __uuidof(ID3D11DeviceContext1))
|
|
{
|
|
if(m_pRealContext1)
|
|
{
|
|
*ppvObject = (ID3D11DeviceContext1 *)this;
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
else if(riid == __uuidof(ID3D11DeviceContext2))
|
|
{
|
|
if(m_pRealContext2)
|
|
{
|
|
*ppvObject = (ID3D11DeviceContext2 *)this;
|
|
AddRef();
|
|
RDCWARN("Trying to get ID3D11DeviceContext2. DX11.2 tiled resources are not supported at this time.");
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
return E_NOINTERFACE;
|
|
}
|
|
}
|
|
else if(riid == __uuidof(ID3DUserDefinedAnnotation))
|
|
{
|
|
*ppvObject = (ID3DUserDefinedAnnotation *)&m_UserAnnotation;
|
|
m_UserAnnotation.AddRef();
|
|
return S_OK;
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
string guid = ToStr::Get(riid);
|
|
RDCWARN("Querying ID3D11DeviceContext for interface: %s", guid.c_str());
|
|
}
|
|
|
|
return RefCounter::QueryInterface(riid, ppvObject);
|
|
}
|