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 *defcontext = m_pDevice->GetDeferredContext(i); defcontext->ClearMaps(); } } m_pDevice->GetResourceManager()->MarkInFrame(true); uint64_t startOffset = m_pSerialiser->GetOffset(); 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 chunktype = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false); ProcessChunk(offset, chunktype, false); RenderDoc::Inst().SetProgress(FrameEventsRead, float(offset - startOffset)/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(chunktype == 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(); 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]; // it's easier to remove duplicate usages here than check it as we go. // this means if textures are bound in multiple places in the same draw // we don't have duplicate uses for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it) { vector<EventUsage> &v = it->second; std::sort(v.begin(), v.end()); v.erase( std::unique(v.begin(), v.end()), v.end() ); #if 0 ResourceId resid = m_pDevice->GetResourceManager()->GetOriginalID(it->first); if(m_pDevice->GetResourceManager()->GetInitialContents(resid).resource == NULL) continue; // code disabled for now as skipping these initial states // doesn't seem to produce any measurable improvement in any case // I've checked RDCDEBUG("Resource %llu", resid); if(v.empty()) { RDCDEBUG("Never used!"); initialSkips++; } else { bool written = false; for(auto usit = v.begin(); usit != v.end(); ++usit) { ResourceUsage u = usit->usage; if(u == eUsage_SO || (u >= eUsage_VS_RWResource && u <= eUsage_CS_RWResource) || u == eUsage_DepthStencilTarget || u == eUsage_ColourTarget) { written = true; break; } } if(written) { RDCDEBUG("Written in frame - needs initial state"); } else { RDCDEBUG("Never written to in the frame"); initialSkips++; } } #endif } //RDCDEBUG("Can skip %d initial states.", initialSkips); } m_pDevice->GetResourceManager()->MarkInFrame(false); m_State = READING; m_DoStateVerify = false; }
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->SerialisePODArray("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.) 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::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_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) == 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; }