void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chunk) { m_Cmd.m_CurChunkOffset = offset; m_Cmd.m_AddedDrawcall = false; switch(chunk) { case CLOSE_LIST: m_ReplayList->Serialise_Close(); break; case RESET_LIST: m_ReplayList->Serialise_Reset(NULL, NULL); break; case RESOURCE_BARRIER: m_ReplayList->Serialise_ResourceBarrier(0, NULL); break; case BEGIN_EVENT: m_ReplayList->Serialise_BeginEvent(0, NULL, 0); break; case SET_MARKER: m_ReplayList->Serialise_SetMarker(0, NULL, 0); break; case END_EVENT: m_ReplayList->Serialise_EndEvent(); break; case DRAW_INST: m_ReplayList->Serialise_DrawInstanced(0, 0, 0, 0); break; case DRAW_INDEXED_INST: m_ReplayList->Serialise_DrawIndexedInstanced(0, 0, 0, 0, 0); break; case DISPATCH: m_ReplayList->Serialise_Dispatch(0, 0, 0); break; case EXEC_INDIRECT: m_ReplayList->Serialise_ExecuteIndirect(NULL, 0, NULL, 0, NULL, 0); break; case COPY_BUFFER: m_ReplayList->Serialise_CopyBufferRegion(NULL, 0, NULL, 0, 0); break; case COPY_TEXTURE: m_ReplayList->Serialise_CopyTextureRegion(NULL, 0, 0, 0, NULL, NULL); break; case COPY_RESOURCE: m_ReplayList->Serialise_CopyResource(NULL, NULL); break; case RESOLVE_SUBRESOURCE: m_ReplayList->Serialise_ResolveSubresource(NULL, 0, NULL, 0, DXGI_FORMAT_UNKNOWN); break; case CLEAR_RTV: m_ReplayList->Serialise_ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE(), (FLOAT *)NULL, 0, NULL); break; case CLEAR_DSV: m_ReplayList->Serialise_ClearDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE(), D3D12_CLEAR_FLAGS(0), 0.0f, 0, 0, NULL); break; case CLEAR_UAV_INT: m_ReplayList->Serialise_ClearUnorderedAccessViewUint( D3D12_GPU_DESCRIPTOR_HANDLE(), D3D12_CPU_DESCRIPTOR_HANDLE(), NULL, NULL, 0, NULL); break; case CLEAR_UAV_FLOAT: m_ReplayList->Serialise_ClearUnorderedAccessViewFloat( D3D12_GPU_DESCRIPTOR_HANDLE(), D3D12_CPU_DESCRIPTOR_HANDLE(), NULL, NULL, 0, NULL); break; case DISCARD_RESOURCE: m_ReplayList->Serialise_DiscardResource(NULL, NULL); break; case SET_TOPOLOGY: m_ReplayList->Serialise_IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_UNDEFINED); break; case SET_IBUFFER: m_ReplayList->Serialise_IASetIndexBuffer(NULL); break; case SET_VBUFFERS: m_ReplayList->Serialise_IASetVertexBuffers(0, 0, NULL); break; case SET_VIEWPORTS: m_ReplayList->Serialise_RSSetViewports(0, NULL); break; case SET_SCISSORS: m_ReplayList->Serialise_RSSetScissorRects(0, NULL); break; case SET_STENCIL: m_ReplayList->Serialise_OMSetStencilRef(0); break; case SET_BLENDFACTOR: m_ReplayList->Serialise_OMSetBlendFactor(NULL); break; case SET_PIPE: m_ReplayList->Serialise_SetPipelineState(NULL); break; case SET_RTVS: m_ReplayList->Serialise_OMSetRenderTargets(0, NULL, FALSE, NULL); break; case SET_DESC_HEAPS: m_ReplayList->Serialise_SetDescriptorHeaps(0, NULL); break; case SET_GFX_ROOT_SIG: m_ReplayList->Serialise_SetGraphicsRootSignature(NULL); break; case SET_GFX_ROOT_TABLE: m_ReplayList->Serialise_SetGraphicsRootDescriptorTable(0, D3D12_GPU_DESCRIPTOR_HANDLE()); break; case SET_GFX_ROOT_CONST: m_ReplayList->Serialise_SetGraphicsRoot32BitConstant(0, 0, 0); break; case SET_GFX_ROOT_CONSTS: m_ReplayList->Serialise_SetGraphicsRoot32BitConstants(0, 0, NULL, 0); break; case SET_GFX_ROOT_CBV: m_ReplayList->Serialise_SetGraphicsRootConstantBufferView(0, D3D12_GPU_VIRTUAL_ADDRESS()); break; case SET_GFX_ROOT_SRV: m_ReplayList->Serialise_SetGraphicsRootShaderResourceView(0, D3D12_GPU_VIRTUAL_ADDRESS()); break; case SET_GFX_ROOT_UAV: m_ReplayList->Serialise_SetGraphicsRootUnorderedAccessView(0, D3D12_GPU_VIRTUAL_ADDRESS()); break; case SET_COMP_ROOT_SIG: m_ReplayList->Serialise_SetComputeRootSignature(NULL); break; case SET_COMP_ROOT_TABLE: m_ReplayList->Serialise_SetComputeRootDescriptorTable(0, D3D12_GPU_DESCRIPTOR_HANDLE()); break; case SET_COMP_ROOT_CONST: m_ReplayList->Serialise_SetComputeRoot32BitConstant(0, 0, 0); break; case SET_COMP_ROOT_CONSTS: m_ReplayList->Serialise_SetComputeRoot32BitConstants(0, 0, NULL, 0); break; case SET_COMP_ROOT_CBV: m_ReplayList->Serialise_SetComputeRootConstantBufferView(0, D3D12_GPU_VIRTUAL_ADDRESS()); break; case SET_COMP_ROOT_SRV: m_ReplayList->Serialise_SetComputeRootShaderResourceView(0, D3D12_GPU_VIRTUAL_ADDRESS()); break; case SET_COMP_ROOT_UAV: m_ReplayList->Serialise_SetComputeRootUnorderedAccessView(0, D3D12_GPU_VIRTUAL_ADDRESS()); break; case EXECUTE_CMD_LISTS: Serialise_ExecuteCommandLists(0, NULL); break; case SIGNAL: Serialise_Signal(NULL, 0); break; case CONTEXT_CAPTURE_FOOTER: { SERIALISE_ELEMENT(ResourceId, bbid, ResourceId()); bool HasCallstack = false; m_pSerialiser->Serialise("HasCallstack", HasCallstack); m_BackbufferID = bbid; 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) { m_Cmd.AddEvent(CONTEXT_CAPTURE_FOOTER, "Present()"); FetchDrawcall draw; draw.name = "Present()"; draw.flags |= eDraw_Present; draw.copyDestination = bbid; m_Cmd.AddDrawcall(draw, true); } break; } default: // ignore system chunks if(chunk == INITIAL_CONTENTS) GetResourceManager()->Serialise_InitialState(ResourceId(), NULL); else if(chunk < FIRST_CHUNK_ID) m_pSerialiser->SkipCurrentChunk(); else RDCERR("Unexpected non-device chunk %d at offset %llu", chunk, offset); break; } m_pSerialiser->PopContext(chunk); if(m_State == READING && chunk == SET_MARKER) { // no push/pop necessary } else if(m_State == READING && (chunk == BEGIN_EVENT || chunk == END_EVENT)) { // don't add these events - they will be handled when inserted in-line into queue submit } else if(m_State == READING) { if(!m_Cmd.m_AddedDrawcall) m_Cmd.AddEvent(chunk, m_pSerialiser->GetDebugStr()); } m_Cmd.m_AddedDrawcall = false; }
void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists) { ID3D12CommandList **unwrapped = m_pDevice->GetTempArray<ID3D12CommandList *>(NumCommandLists); for(UINT i = 0; i < NumCommandLists; i++) unwrapped[i] = Unwrap(ppCommandLists[i]); m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped); if(m_State >= WRITING) { SCOPED_LOCK(m_Lock); SCOPED_LOCK(m_pDevice->GetCapTransitionLock()); bool capframe = (m_State == WRITING_CAPFRAME); set<ResourceId> refdIDs; for(UINT i = 0; i < NumCommandLists; i++) { D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]); if(record->ContainsExecuteIndirect) m_QueueRecord->ContainsExecuteIndirect = true; m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers); // need to lock the whole section of code, not just the check on // m_State, as we also need to make sure we don't check the state, // start marking dirty resources then while we're doing so the // state becomes capframe. // the next sections where we mark resources referenced and add // the submit chunk to the frame record don't have to be protected. // Only the decision of whether we're inframe or not, and marking // dirty. if(capframe) { for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) GetResourceManager()->MarkPendingDirty(*it); } else { for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) GetResourceManager()->MarkDirtyResource(*it); } if(capframe) { // any descriptor copies or writes could reference new resources not in the // bound descs list yet. So we take all of those referenced descriptors and // include them to see if we need to flush std::vector<D3D12Descriptor> dynDescRefs; m_pDevice->GetDynamicDescriptorReferences(dynDescRefs); for(size_t d = 0; d < dynDescRefs.size(); d++) { ResourceId id, id2; FrameRefType ref = eFrameRef_Read; dynDescRefs[d].GetRefIDs(id, id2, ref); if(id != ResourceId()) { refdIDs.insert(id); GetResourceManager()->MarkResourceFrameReferenced(id, ref); } if(id2 != ResourceId()) { refdIDs.insert(id2); GetResourceManager()->MarkResourceFrameReferenced(id2, ref); } } // for each bound descriptor table, mark it referenced as well as all resources currently // bound to it for(auto it = record->bakedCommands->cmdInfo->boundDescs.begin(); it != record->bakedCommands->cmdInfo->boundDescs.end(); ++it) { D3D12Descriptor *desc = *it; ResourceId id, id2; FrameRefType ref = eFrameRef_Read; desc->GetRefIDs(id, id2, ref); if(id != ResourceId()) { refdIDs.insert(id); GetResourceManager()->MarkResourceFrameReferenced(id, ref); } if(id2 != ResourceId()) { refdIDs.insert(id2); GetResourceManager()->MarkResourceFrameReferenced(id2, ref); } } // pull in frame refs from this baked command list record->bakedCommands->AddResourceReferences(GetResourceManager()); record->bakedCommands->AddReferencedIDs(refdIDs); // reference all executed bundles as well for(size_t b = 0; b < record->bakedCommands->cmdInfo->bundles.size(); b++) { record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddResourceReferences( GetResourceManager()); record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddReferencedIDs(refdIDs); GetResourceManager()->MarkResourceFrameReferenced( record->bakedCommands->cmdInfo->bundles[b]->GetResourceID(), eFrameRef_Read); record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddRef(); } { m_CmdListRecords.push_back(record->bakedCommands); for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->bundles.size(); sub++) m_CmdListRecords.push_back(record->bakedCommands->cmdInfo->bundles[sub]->bakedCommands); } record->bakedCommands->AddRef(); } record->cmdInfo->dirtied.clear(); } if(capframe) { vector<MapState> maps = m_pDevice->GetMaps(); for(auto it = maps.begin(); it != maps.end(); ++it) { WrappedID3D12Resource *res = it->res; UINT subres = it->subres; size_t size = (size_t)it->totalSize; // only need to flush memory that could affect this submitted batch of work if(refdIDs.find(res->GetResourceID()) == refdIDs.end()) { RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing", res->GetResourceID()); continue; } size_t diffStart = 0, diffEnd = 0; bool found = true; byte *ref = res->GetShadow(subres); byte *data = res->GetMap(subres); if(ref) found = FindDiffRange(data, ref, size, diffStart, diffEnd); else diffEnd = size; if(found) { RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", res->GetResourceID(), (uint64_t)diffStart, (uint64_t)diffEnd); D3D12_RANGE range = {diffStart, diffEnd}; m_pDevice->MapDataWrite(res, subres, data, range); if(ref == NULL) { res->AllocShadow(subres, size); ref = res->GetShadow(subres); } // update comparison shadow for next time memcpy(ref, res->GetMap(subres), size); GetResourceManager()->MarkPendingDirty(res->GetResourceID()); } else { RDCDEBUG("Persistent map flush not needed for %llu", res->GetResourceID()); } } for(UINT i = 0; i < NumCommandLists; i++) { SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS); Serialise_ExecuteCommandLists(1, ppCommandLists + i); m_QueueRecord->AddChunk(scope.Get()); } } } }
void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists) { ID3D12CommandList **unwrapped = new ID3D12CommandList *[NumCommandLists]; for(UINT i = 0; i < NumCommandLists; i++) unwrapped[i] = Unwrap(ppCommandLists[i]); m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped); SAFE_DELETE_ARRAY(unwrapped); if(m_State >= WRITING) { bool capframe = false; set<ResourceId> refdIDs; for(UINT i = 0; i < NumCommandLists; i++) { D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]); m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers); // need to lock the whole section of code, not just the check on // m_State, as we also need to make sure we don't check the state, // start marking dirty resources then while we're doing so the // state becomes capframe. // the next sections where we mark resources referenced and add // the submit chunk to the frame record don't have to be protected. // Only the decision of whether we're inframe or not, and marking // dirty. { SCOPED_LOCK(m_pDevice->GetCapTransitionLock()); if(m_State == WRITING_CAPFRAME) { for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) GetResourceManager()->MarkPendingDirty(*it); capframe = true; } else { for(auto it = record->bakedCommands->cmdInfo->dirtied.begin(); it != record->bakedCommands->cmdInfo->dirtied.end(); ++it) GetResourceManager()->MarkDirtyResource(*it); } } if(capframe) { // for each bound descriptor table, mark it referenced as well as all resources currently // bound to it for(auto it = record->bakedCommands->cmdInfo->boundDescs.begin(); it != record->bakedCommands->cmdInfo->boundDescs.end(); ++it) { D3D12Descriptor &desc = **it; switch(desc.GetType()) { case D3D12Descriptor::TypeUndefined: case D3D12Descriptor::TypeSampler: // nothing to do - no resource here break; case D3D12Descriptor::TypeCBV: GetResourceManager()->MarkResourceFrameReferenced( WrappedID3D12Resource::GetResIDFromAddr(desc.nonsamp.cbv.BufferLocation), eFrameRef_Read); break; case D3D12Descriptor::TypeSRV: GetResourceManager()->MarkResourceFrameReferenced(GetResID(desc.nonsamp.resource), eFrameRef_Read); break; case D3D12Descriptor::TypeUAV: GetResourceManager()->MarkResourceFrameReferenced(GetResID(desc.nonsamp.resource), eFrameRef_Write); GetResourceManager()->MarkResourceFrameReferenced( GetResID(desc.nonsamp.uav.counterResource), eFrameRef_Write); break; case D3D12Descriptor::TypeRTV: GetResourceManager()->MarkResourceFrameReferenced(GetResID(desc.nonsamp.resource), eFrameRef_Write); break; case D3D12Descriptor::TypeDSV: GetResourceManager()->MarkResourceFrameReferenced(GetResID(desc.nonsamp.resource), eFrameRef_Write); break; } } // pull in frame refs from this baked command list record->bakedCommands->AddResourceReferences(GetResourceManager()); record->bakedCommands->AddReferencedIDs(refdIDs); // ref the parent command list by itself, this will pull in the cmd buffer pool GetResourceManager()->MarkResourceFrameReferenced(record->GetResourceID(), eFrameRef_Read); // reference all executed bundles as well for(size_t b = 0; b < record->bakedCommands->cmdInfo->bundles.size(); b++) { record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddResourceReferences( GetResourceManager()); record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddReferencedIDs(refdIDs); GetResourceManager()->MarkResourceFrameReferenced( record->bakedCommands->cmdInfo->bundles[b]->GetResourceID(), eFrameRef_Read); record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddRef(); } { m_CmdListRecords.push_back(record->bakedCommands); for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->bundles.size(); sub++) m_CmdListRecords.push_back(record->bakedCommands->cmdInfo->bundles[sub]->bakedCommands); } record->bakedCommands->AddRef(); } record->cmdInfo->dirtied.clear(); } if(capframe) { // flush coherent maps for(UINT i = 0; i < NumCommandLists; i++) { SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS); Serialise_ExecuteCommandLists(1, ppCommandLists + i); m_QueueRecord->AddChunk(scope.Get()); } } } }