diff --git a/renderdoc/driver/d3d11/d3d11_common.h b/renderdoc/driver/d3d11/d3d11_common.h index 408ff8b51..a2401920d 100644 --- a/renderdoc/driver/d3d11/d3d11_common.h +++ b/renderdoc/driver/d3d11/d3d11_common.h @@ -345,6 +345,7 @@ enum D3D11ChunkType CREATE_UAV1, SWAP_PRESENT, + RESTORE_STATE_AFTER_EXEC, NUM_D3D11_CHUNKS, }; diff --git a/renderdoc/driver/d3d11/d3d11_context.cpp b/renderdoc/driver/d3d11/d3d11_context.cpp index 6c2e4df03..96029010b 100644 --- a/renderdoc/driver/d3d11/d3d11_context.cpp +++ b/renderdoc/driver/d3d11/d3d11_context.cpp @@ -134,6 +134,8 @@ WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device *real m_State = WRITING_IDLE; } + m_OwnSerialiser = false; + // create a temporary and grab its resource ID m_ResourceID = ResourceIDGen::GetNewUniqueID(); @@ -165,6 +167,7 @@ WrappedID3D11DeviceContext::WrappedID3D11DeviceContext(WrappedID3D11Device *real m_UserAnnotation.SetContext(this); m_CurrentPipelineState = new D3D11RenderState((Serialiser *)NULL); + m_DeferredSavedState = NULL; m_DoStateVerify = m_State >= WRITING; if(context->GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE) @@ -196,7 +199,7 @@ WrappedID3D11DeviceContext::~WrappedID3D11DeviceContext() SAFE_RELEASE(it->second.query); } - if(m_State >= WRITING) + if(m_State >= WRITING || m_OwnSerialiser) { SAFE_DELETE(m_pSerialiser); } @@ -607,30 +610,11 @@ void WrappedID3D11DeviceContext::ProcessChunk(uint64_t offset, D3D11ChunkType ch { 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(chunk); - return; - } - } - - RDCASSERTMSG("Context is invalid", WrappedID3D11DeviceContext::IsAlloc(context), ctxId, context); + // ctxId is now ignored + WrappedID3D11DeviceContext *context = this; LogState state = context->m_State; @@ -759,6 +743,17 @@ void WrappedID3D11DeviceContext::ProcessChunk(uint64_t offset, D3D11ChunkType ch case DISCARD_VIEW: context->Serialise_DiscardView(NULL); break; case DISCARD_VIEW1: context->Serialise_DiscardView1(NULL, NULL, 0); break; + case RESTORE_STATE_AFTER_EXEC: + { + // apply saved state. + if(m_DeferredSavedState) + { + m_DeferredSavedState->ApplyState(this); + SAFE_DELETE(m_DeferredSavedState); + } + break; + } + case SWAP_PRESENT: { // we don't do anything with these parameters, they're just here to store @@ -958,9 +953,6 @@ void WrappedID3D11DeviceContext::AddDrawcall(const FetchDrawcall &d, bool hasEve { FetchDrawcall draw = d; - if(draw.context == ResourceId()) - draw.context = m_pDevice->GetResourceManager()->GetOriginalID(m_ResourceID); - if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) { m_pDevice->GetImmediateContext()->AddDrawcall(draw, hasEvents); @@ -969,11 +961,6 @@ void WrappedID3D11DeviceContext::AddDrawcall(const FetchDrawcall &d, bool hasEve m_AddedDrawcall = true; - WrappedID3D11DeviceContext *context = - (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(draw.context); - - RDCASSERT(context); - draw.eventID = m_CurEventID; draw.drawcallID = m_CurDrawcallID; @@ -1007,34 +994,20 @@ void WrappedID3D11DeviceContext::AddDrawcall(const FetchDrawcall &d, bool hasEve if(hasEvents) { - vector 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; + draw.events = m_CurEvents; + m_CurEvents.clear(); } AddUsage(draw); // should have at least the root drawcall here, push this drawcall // onto the back's children list. - if(!context->m_DrawcallStack.empty()) + if(!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); + m_DrawcallStack.back()->children.push_back(node); } else RDCERR("Somehow lost drawcall stack!"); @@ -1053,7 +1026,6 @@ void WrappedID3D11DeviceContext::AddEvent(D3D11ChunkType type, string descriptio FetchAPIEvent apievent; - apievent.context = ctx; apievent.fileOffset = m_CurChunkOffset; apievent.eventID = m_CurEventID; @@ -1088,23 +1060,368 @@ void WrappedID3D11DeviceContext::ReplayFakeContext(ResourceId id) m_FakeContext = id; } +static void PadToAligned(Serialiser *dst, uint64_t alignment) +{ + uint64_t offs = dst->GetOffset(); + uint64_t alignedoffs = AlignUp(offs, alignment); + + // nothing to do + if(offs == alignedoffs) + return; + + uint16_t chunkIdx = 0; + dst->Serialise("", chunkIdx); + offs += sizeof(chunkIdx); + + uint8_t controlByte = 0; // control byte 0 indicates padding + dst->Serialise("", controlByte); + offs += sizeof(controlByte); + + offs++; // we will have to write out a byte indicating how much padding exists, so add 1 + alignedoffs = AlignUp(offs, alignment); + + uint8_t padLength = (alignedoffs - offs) & 0xff; + dst->Serialise("", padLength); + + // we might have padded with the control bytes, so only write some bytes if we need to + if(padLength > 0) + { + const byte zeroes[256] = {}; + dst->RawWriteBytes(zeroes, (size_t)padLength); + } +} + +static void CopyChunk(Serialiser *src, Serialiser *dst, uint64_t offsBegin) +{ + uint64_t offsEnd = src->GetOffset(); + + // this whole function is quite an abuse of the serialiser interface :(. + // It will all go away when I can break backwards compatibility and remove + // this code and greatly tidy up the interface. + + src->SetOffset(offsBegin); + + dst->RawWriteBytes(src->RawReadBytes(size_t(offsEnd - offsBegin)), size_t(offsEnd - offsBegin)); +} + +static void CopyUnmap(Serialiser *src, Serialiser *dst, Serialiser *tmp) +{ + ResourceId Resource; + uint32_t Subresource = 0; + D3D11_MAP MapType = D3D11_MAP_WRITE_DISCARD; + uint32_t MapFlags = 0; + uint32_t DiffStart = 0; + uint32_t DiffEnd = 0; + byte *buf = NULL; + size_t len = 0; + + tmp->Rewind(); + tmp->PushContext("", "", UNMAP, false); + + // context id - ignored but needed to match expected format + tmp->Serialise("", Resource); + + src->Serialise("", Resource); + tmp->Serialise("", Resource); + + src->Serialise("", Subresource); + tmp->Serialise("", Subresource); + + src->Serialise("", MapType); + tmp->Serialise("", MapType); + + src->Serialise("", MapFlags); + tmp->Serialise("", MapFlags); + + src->Serialise("", DiffStart); + tmp->Serialise("", DiffStart); + + src->Serialise("", DiffEnd); + tmp->Serialise("", DiffEnd); + + src->SerialiseBuffer("", buf, len); + tmp->SerialiseBuffer("", buf, len); + + src->PopContext(UNMAP); + tmp->PopContext(UNMAP); + + SAFE_DELETE_ARRAY(buf); + + dst->RawWriteBytes(tmp->GetRawPtr(0), size_t(tmp->GetOffset())); +} + +static void CopyUpdateSubresource(Serialiser *src, Serialiser *dst, Serialiser *tmp) +{ + ResourceId idx; + uint32_t flags = 0; + uint32_t DestSubresource = 0; + uint8_t isUpdate = true; + + uint8_t HasDestBox = 0; + D3D11_BOX box = {}; + uint32_t SourceRowPitch = 0; + uint32_t SourceDepthPitch = 0; + + uint32_t ResourceBufLen = 0; + + byte *buf = NULL; + size_t len = 0; + + tmp->Rewind(); + tmp->PushContext("", "", UPDATE_SUBRESOURCE1, false); + + // context id - ignored but needed to match expected format + tmp->Serialise("", idx); + + src->Serialise("", idx); + tmp->Serialise("", idx); + + src->Serialise("", flags); + tmp->Serialise("", flags); + + src->Serialise("", DestSubresource); + tmp->Serialise("", DestSubresource); + + src->Serialise("", isUpdate); + tmp->Serialise("", isUpdate); + + if(isUpdate) + { + src->Serialise("", HasDestBox); + tmp->Serialise("", HasDestBox); + + if(HasDestBox) + { + src->Serialise("", box); + tmp->Serialise("", box); + } + + src->Serialise("", SourceRowPitch); + tmp->Serialise("", SourceRowPitch); + + src->Serialise("", SourceDepthPitch); + tmp->Serialise("", SourceDepthPitch); + + src->Serialise("", ResourceBufLen); + tmp->Serialise("", ResourceBufLen); + + src->SerialiseBuffer("", buf, len); + tmp->SerialiseBuffer("", buf, len); + } + else + { + // shouldn't get in here, any chunks we're looking at are context chunks + // so they should be recorded as updates + + src->Serialise("", ResourceBufLen); + tmp->Serialise("", ResourceBufLen); + + src->SerialiseBuffer("", buf, len); + tmp->SerialiseBuffer("", buf, len); + } + + src->PopContext(UPDATE_SUBRESOURCE1); + tmp->PopContext(UPDATE_SUBRESOURCE1); + + SAFE_DELETE_ARRAY(buf); + + dst->RawWriteBytes(tmp->GetRawPtr(0), size_t(tmp->GetOffset())); +} + +void WrappedID3D11DeviceContext::FlattenLog() +{ + Serialiser *src = m_pSerialiser; + Serialiser *dst = new Serialiser(NULL, Serialiser::WRITING, false); + + Serialiser *tmp = new Serialiser(NULL, Serialiser::WRITING, false); + + map deferred; + + uint64_t offsBegin = src->GetOffset(); + + D3D11ChunkType chunk = (D3D11ChunkType)src->PushContext(NULL, NULL, 1, false); + RDCASSERTEQUAL(chunk, CONTEXT_CAPTURE_HEADER); + src->SkipCurrentChunk(); + src->PopContext(chunk); + + CopyChunk(src, dst, offsBegin); + + for(;;) + { + offsBegin = src->GetOffset(); + + chunk = (D3D11ChunkType)src->PushContext(NULL, NULL, 1, false); + + ResourceId ctx; + src->Serialise("ctx", ctx); + + WrappedID3D11DeviceContext *context = + (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(ctx); + + // if it's a local chunk just copy it + if(context == this) + { + ResourceId cmdList; + uint8_t restore = 0; + + if(chunk == EXECUTE_CMD_LIST) + { + m_pSerialiser->Serialise("RestoreContextState", restore); + m_pSerialiser->Serialise("cmdList", cmdList); + } + + // these chunks need to be reserialised individually to ensure padding bytes in + // between all remain the same + if(chunk == UNMAP) + { + PadToAligned(dst, 64); + CopyUnmap(src, dst, tmp); + } + else if(chunk == UPDATE_SUBRESOURCE || chunk == UPDATE_SUBRESOURCE1) + { + PadToAligned(dst, 64); + CopyUpdateSubresource(src, dst, tmp); + } + else + { + src->SetOffset(offsBegin); + src->PushContext(NULL, NULL, 1, false); + src->SkipCurrentChunk(); + src->PopContext(chunk); + + CopyChunk(src, dst, offsBegin); + } + + if(chunk == EXECUTE_CMD_LIST) + { + Serialiser *def = deferred[cmdList]; + + if(def == NULL) + { + RDCERR("ExecuteCommandList found for command list we didn't Finish!"); + } + else + { + // when inserting, ensure the chunks stay aligned (this is harmless if they don't need + // alignment). Do this by inserting padding bytes, ugly but it works. + PadToAligned(dst, 64); + + // now insert the chunks to replay + dst->RawWriteBytes(deferred[cmdList]->GetRawPtr(0), (size_t)deferred[cmdList]->GetSize()); + + // if we have to restore the state, the above Execute.. will have + // saved it, so we just add a little chunk to let it pop it again + if(restore) + { + tmp->Rewind(); + tmp->PushContext("", "", RESTORE_STATE_AFTER_EXEC, false); + tmp->PopContext(RESTORE_STATE_AFTER_EXEC); + + dst->RawWriteBytes(tmp->GetRawPtr(0), size_t(tmp->GetOffset())); + } + + // again since we inserted chunks we need to align again + PadToAligned(dst, 64); + } + } + } + else + { + if(deferred[ctx] == NULL) + deferred[ctx] = new Serialiser(NULL, Serialiser::WRITING, false); + + ResourceId cmdList; + uint8_t restore = 0; + + if(chunk == FINISH_CMD_LIST) + { + m_pSerialiser->Serialise("RestoreDeferredContextState", restore); + m_pSerialiser->Serialise("cmdList", cmdList); + + if(restore != 0) + { + RDCWARN( + "RestoreDeferredContextState == TRUE was set for command list %llu. " + "On old captures this wasn't properly replayed and can't be fixed as-is, " + "re-capture with latest RenderDoc to solve this issue."); + } + } + + // these chunks need to be reserialised individually to ensure padding bytes in + // between all remain the same + if(chunk == UNMAP) + { + PadToAligned(deferred[ctx], 64); + CopyUnmap(src, deferred[ctx], tmp); + } + else if(chunk == UPDATE_SUBRESOURCE || chunk == UPDATE_SUBRESOURCE1) + { + PadToAligned(deferred[ctx], 64); + CopyUpdateSubresource(src, deferred[ctx], tmp); + } + else + { + src->SetOffset(offsBegin); + src->PushContext(NULL, NULL, 1, false); + src->SkipCurrentChunk(); + src->PopContext(chunk); + + CopyChunk(src, deferred[ctx], offsBegin); + } + + if(chunk == FINISH_CMD_LIST) + { + // here is where RestoreDeferredContextState is broken, this doesn't + // take into account the inherited state from previous recordings. + deferred[cmdList] = deferred[ctx]; + deferred[ctx] = new Serialiser(NULL, Serialiser::WRITING, false); + } + } + + if(chunk == CONTEXT_CAPTURE_FOOTER) + { + break; + } + } + + m_pSerialiser = new Serialiser(dst->GetSize(), dst->GetRawPtr(0), false); + m_OwnSerialiser = true; + + // tidy up the temporary serialisers + SAFE_DELETE(dst); + SAFE_DELETE(tmp); + + for(auto it = deferred.begin(); it != deferred.end(); ++it) + SAFE_DELETE(it->second); +} + void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial) { m_State = readType; + if(readType == READING && m_pDevice->GetNumDeferredContexts() && + m_pDevice->GetLogVersion() < 0x00000A) + { + // flatten the log + FlattenLog(); + } + m_DoStateVerify = true; + if(readType == EXECUTING && m_pDevice->GetNumDeferredContexts() && + m_pDevice->GetLogVersion() < 0x00000A) + { + m_pSerialiser->SetOffset(0); + } + D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false); RDCASSERTEQUAL(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); + // id is now ignored Serialise_BeginCaptureFrame(!partial); diff --git a/renderdoc/driver/d3d11/d3d11_context.h b/renderdoc/driver/d3d11/d3d11_context.h index 6a3088d3e..a8f8493b6 100644 --- a/renderdoc/driver/d3d11/d3d11_context.h +++ b/renderdoc/driver/d3d11/d3d11_context.h @@ -202,6 +202,7 @@ private: ResourceId m_ResourceID; D3D11ResourceRecord *m_ContextRecord; + bool m_OwnSerialiser; Serialiser *m_pSerialiser; LogState m_State; CaptureFailReason m_FailureReason; @@ -215,6 +216,8 @@ private: bool m_DoStateVerify; D3D11RenderState *m_CurrentPipelineState; + D3D11RenderState *m_DeferredSavedState; + vector m_CurEvents, m_Events; bool m_AddedDrawcall; @@ -243,6 +246,8 @@ private: list m_DrawcallStack; + void FlattenLog(); + const char *GetChunkName(D3D11ChunkType idx); void Serialise_DebugMessages(); diff --git a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp index c03387a30..ba9dfd06f 100644 --- a/renderdoc/driver/d3d11/d3d11_context_wrap.cpp +++ b/renderdoc/driver/d3d11/d3d11_context_wrap.cpp @@ -4787,48 +4787,22 @@ bool WrappedID3D11DeviceContext::Serialise_ExecuteCommandList(ID3D11CommandList SERIALISE_ELEMENT(uint8_t, RestoreContextState, RestoreContextState_ == TRUE); SERIALISE_ELEMENT(ResourceId, cmdList, GetIDForResource(pCommandList)); - RDCASSERT(GetType() == D3D11_DEVICE_CONTEXT_IMMEDIATE); - - if(m_State <= EXECUTING) - { - if(m_pDevice->GetResourceManager()->HasLiveResource(cmdList)) - m_pRealContext->ExecuteCommandList( - UNWRAP(WrappedID3D11CommandList, m_pDevice->GetResourceManager()->GetLiveResource(cmdList)), - RestoreContextState); - else - RDCERR("Don't have command list serialised for %llu", cmdList); - - if(!RestoreContextState) - m_CurrentPipelineState->Clear(); - - VerifyState(); - } - const string desc = m_pSerialiser->GetDebugStr(); Serialise_DebugMessages(); + if(m_State <= EXECUTING && RestoreContextState) + { + m_DeferredSavedState = new D3D11RenderState(this); + } + if(m_State == READING) { string name = "ExecuteCommandList(" + ToStr::Get(cmdList) + ")"; FetchDrawcall draw; draw.name = name; - draw.flags |= eDraw_CmdList | eDraw_PushMarker; - - AddDrawcall(draw, true); - - auto cmdDrawChildren = m_CmdLists.find(cmdList); - - if(!m_DrawcallStack.empty() && !m_DrawcallStack.back()->children.empty() && - cmdDrawChildren != m_CmdLists.end()) - { - m_DrawcallStack.back()->children.back().children = cmdDrawChildren->second.children; - - // assign new drawcall IDs so that we don't get duplicates if this commandlist is executed - // again - RefreshDrawcallIDs(cmdDrawChildren->second); - } + draw.flags |= eDraw_CmdList | eDraw_SetMarker; } return true; @@ -5063,29 +5037,6 @@ bool WrappedID3D11DeviceContext::Serialise_FinishCommandList(BOOL RestoreDeferre SERIALISE_ELEMENT(uint8_t, RestoreDeferredContextState, RestoreDeferredContextState_ == TRUE); SERIALISE_ELEMENT(ResourceId, cmdList, GetIDForResource(*ppCommandList)); - if(m_State <= EXECUTING && GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) - { - ID3D11CommandList *ret = NULL; - HRESULT hr = m_pRealContext->FinishCommandList(RestoreDeferredContextState, &ret); - - if(!RestoreDeferredContextState) - m_CurrentPipelineState->Clear(); - - VerifyState(); - - if(FAILED(hr)) - RDCERR("Failed on finishing command list, HRESULT: 0x%08x", hr); - - RDCASSERT(SUCCEEDED(hr) && ret); - - ret = new WrappedID3D11CommandList(ret, m_pDevice, this, true); - - if(ret) - { - m_pDevice->GetResourceManager()->AddLiveResource(cmdList, ret); - } - } - const string desc = m_pSerialiser->GetDebugStr(); Serialise_DebugMessages(); @@ -5097,12 +5048,9 @@ bool WrappedID3D11DeviceContext::Serialise_FinishCommandList(BOOL RestoreDeferre FetchDrawcall draw; draw.name = name; - draw.flags |= eDraw_CmdList; + draw.flags |= eDraw_CmdList | eDraw_SetMarker; AddDrawcall(draw, true); - - m_pDevice->GetImmediateContext()->m_CmdLists[cmdList] = m_ParentDrawcall; - m_ParentDrawcall.children.clear(); } return true; diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index 68a724b20..5aa94b9b3 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -193,6 +193,8 @@ const char *D3D11ChunkNames[] = { "ID3D11Device3::CreateUnorderedAccessView1", "IDXGISwapChain::Present", + + "ID3D11DeviceContext::ExecuteCommandList", }; WRAPPED_POOL_INST(WrappedID3D11Device); @@ -229,6 +231,10 @@ const uint32_t D3D11InitParams::D3D11_OLD_VERSIONS[D3D11InitParams::D3D11_NUM_SU // from 0x8 to 0x9, we added the view creation details to clear calls in the device // record so that we can still perform the clear even if the view wasn't referenced. 0x000008, + // from 0x9 to 0xA, we refactored deferred context handling - it's flattened on + // capture now. So on replay if deferred contexts are present, we go through a + // flattening stpe. + 0x000009, }; ReplayCreateStatus D3D11InitParams::Serialise() diff --git a/renderdoc/driver/d3d11/d3d11_device.h b/renderdoc/driver/d3d11/d3d11_device.h index a3248fd8b..94a8d9ed9 100644 --- a/renderdoc/driver/d3d11/d3d11_device.h +++ b/renderdoc/driver/d3d11/d3d11_device.h @@ -62,10 +62,10 @@ struct D3D11InitParams : public RDCInitParams UINT NumFeatureLevels; D3D_FEATURE_LEVEL FeatureLevels[16]; - static const uint32_t D3D11_SERIALISE_VERSION = 0x0000009; + static const uint32_t D3D11_SERIALISE_VERSION = 0x000000A; // backwards compatibility for old logs described at the declaration of this array - static const uint32_t D3D11_NUM_SUPPORTED_OLD_VERSIONS = 5; + static const uint32_t D3D11_NUM_SUPPORTED_OLD_VERSIONS = 6; static const uint32_t D3D11_OLD_VERSIONS[D3D11_NUM_SUPPORTED_OLD_VERSIONS]; // version number internal to d3d11 stream diff --git a/renderdocui/Windows/EventBrowser.cs b/renderdocui/Windows/EventBrowser.cs index 603242a81..9fbf7fb4e 100644 --- a/renderdocui/Windows/EventBrowser.cs +++ b/renderdocui/Windows/EventBrowser.cs @@ -302,22 +302,6 @@ namespace renderdocui.Windows def.eventID = eventNum; def.marker = (drawcall.flags & DrawcallFlags.SetMarker) != 0; - if (drawcall.context != m_Core.FrameInfo.immContextId) - { - def.defCtx = drawcall.context; - def.lastDefEv = drawcall.eventID; - - FetchDrawcall parent = drawcall.parent; - while(!parent.name.Contains("ExecuteCommand")) - parent = parent.parent; - - def.eventID = parent.eventID-1; - - def.firstDefEv = parent.children[0].eventID; - if(parent.children[0].events.Length > 0) - def.firstDefEv = parent.children[0].events[0].eventID; - } - drawNode.Tag = def; if (drawcall.children != null && drawcall.children.Length > 0)