diff --git a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp index ada248a1e..ebbef2d9e 100644 --- a/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_list_wrap.cpp @@ -55,7 +55,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Close() { ID3D12GraphicsCommandList *list = m_Cmd->RerecordCmdList(CommandList); #ifdef VERBOSE_PARTIAL_REPLAY - RDCDEBUG("Ending partial command buffer for %llu baked to %llu", CommandList, bakeId); + RDCDEBUG("Ending partial command list for %llu baked to %llu", CommandList, bakeId); #endif list->Close(); @@ -151,7 +151,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p bool partial = false; int partialType = D3D12CommandData::ePartialNum; - // check for partial execution of this command buffer + // check for partial execution of this command list for(int p = 0; p < D3D12CommandData::ePartialNum; p++) { const vector &baseEvents = m_Cmd->m_Partial[p].cmdListExecs[bakeId]; @@ -161,8 +161,8 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p if(*it <= m_Cmd->m_LastEventID && m_Cmd->m_LastEventID < (*it + length)) { #ifdef VERBOSE_PARTIAL_REPLAY - RDCDEBUG("vkBegin - partial detected %u < %u < %u, %llu -> %llu", *it, - m_Cmd->m_LastEventID, *it + length, CommandList, bakeId); + RDCDEBUG("Reset - partial detected %u < %u < %u, %llu -> %llu", *it, m_Cmd->m_LastEventID, + *it + length, CommandList, bakeId); #endif m_Cmd->m_Partial[p].partialParent = CommandList; @@ -206,9 +206,9 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p // can be found in the subsequent serialised commands that ref the // non-baked ID. The baked ID is referenced by the submit itself. // - // In vkEndCommandBuffer we erase the non-baked reference, and since - // we know you can only be recording a command buffer once at a time - // (even if it's baked to several command buffers in the frame) + // In Close() we erase the non-baked reference, and since + // we know you can only be recording a command list once at a time + // (even if it's baked to several command listsin the frame) // there's no issue with clashes here. m_Cmd->m_RerecordCmds[bakeId] = list; m_Cmd->m_RerecordCmds[CommandList] = list; @@ -230,7 +230,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_Reset(ID3D12CommandAllocator *p GetResourceManager()->AddLiveResource(bakeId, list); - // whenever a vkCmd command-building chunk asks for the command buffer, it + // whenever a command-building chunk asks for the command list, it // will get our baked version. GetResourceManager()->ReplaceResource(CommandList, bakeId); } @@ -539,7 +539,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetPrimitiveTopology( { Unwrap(m_Cmd->RerecordCmdList(CommandList))->IASetPrimitiveTopology(topo); - // m_RenderState.topo = topo; + m_Cmd->m_RenderState.topo = topo; } } else if(m_State == READING) @@ -581,12 +581,11 @@ bool WrappedID3D12GraphicsCommandList::Serialise_RSSetViewports(UINT NumViewport { Unwrap(m_Cmd->RerecordCmdList(CommandList))->RSSetViewports(num, views); - /* - if(m_RenderState.views.size() < first + count) - m_RenderState.views.resize(first + count); + if(m_Cmd->m_RenderState.views.size() < num) + m_Cmd->m_RenderState.views.resize(num); - for(uint32_t i = 0; i < count; i++) - m_RenderState.views[first + i] = views[i];*/ + for(UINT i = 0; i < num; i++) + m_Cmd->m_RenderState.views[i] = views[i]; } } else if(m_State == READING) @@ -629,12 +628,11 @@ bool WrappedID3D12GraphicsCommandList::Serialise_RSSetScissorRects(UINT NumRects { Unwrap(m_Cmd->RerecordCmdList(CommandList))->RSSetScissorRects(num, rects); - /* - if(m_RenderState.scissors.size() < first + count) - m_RenderState.scissors.resize(first + count); + if(m_Cmd->m_RenderState.scissors.size() < num) + m_Cmd->m_RenderState.scissors.resize(num); - for(uint32_t i = 0; i < count; i++) - m_RenderState.scissors[first + i] = scissors[i];*/ + for(UINT i = 0; i < num; i++) + m_Cmd->m_RenderState.scissors[i] = rects[i]; } } else if(m_State == READING) @@ -685,7 +683,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetPipelineState(ID3D12Pipeline pPipelineState = GetResourceManager()->GetLiveAs(pipe); Unwrap(m_Cmd->RerecordCmdList(CommandList))->SetPipelineState(Unwrap(pPipelineState)); - // m_RenderState.pipe = ; + m_Cmd->m_RenderState.pipe = GetResID(pPipelineState); } } else if(m_State == READING) @@ -878,6 +876,8 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetGraphicsRootSignature( { pRootSignature = GetResourceManager()->GetLiveAs(sig); Unwrap(m_Cmd->RerecordCmdList(CommandList))->SetGraphicsRootSignature(Unwrap(pRootSignature)); + + m_Cmd->m_RenderState.graphics.rootsig = GetResID(pRootSignature); } } else if(m_State == READING) @@ -979,6 +979,12 @@ bool WrappedID3D12GraphicsCommandList::Serialise_SetGraphicsRootConstantBufferVi Unwrap(m_Cmd->RerecordCmdList(CommandList)) ->SetGraphicsRootConstantBufferView(idx, pRes->GetGPUVirtualAddress() + byteOffset); + + if(m_Cmd->m_RenderState.graphics.sigelems.size() < idx + 1) + m_Cmd->m_RenderState.graphics.sigelems.resize(idx + 1); + + m_Cmd->m_RenderState.graphics.sigelems[idx] = + D3D12RenderState::SignatureElement(eRootCBV, GetResID(pRes), byteOffset); } } else if(m_State == READING) @@ -1054,17 +1060,18 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetIndexBuffer(const D3D12_IN { Unwrap(list)->IASetIndexBuffer(&view); - // WrappedID3D12Resource::GetResIDFromAddr(view.BufferLocation, m_RenderState.ibuffer.buf, - // m_RenderState.ibuffer.offs); - // m_RenderState.ibuffer.bytewidth = (view.Format == DXGI_FORMAT_R32_UINT ? 4 : 2); + WrappedID3D12Resource::GetResIDFromAddr( + view.BufferLocation, m_Cmd->m_RenderState.ibuffer.buf, m_Cmd->m_RenderState.ibuffer.offs); + m_Cmd->m_RenderState.ibuffer.bytewidth = (view.Format == DXGI_FORMAT_R32_UINT ? 4 : 2); + m_Cmd->m_RenderState.ibuffer.size = view.SizeInBytes; } else { Unwrap(list)->IASetIndexBuffer(NULL); - // m_RenderState.ibuffer.buf = ResourceId(); - // m_RenderState.ibuffer.offs = 0; - // m_RenderState.ibuffer.bytewidth = 2; + m_Cmd->m_RenderState.ibuffer.buf = ResourceId(); + m_Cmd->m_RenderState.ibuffer.offs = 0; + m_Cmd->m_RenderState.ibuffer.bytewidth = 2; } } } @@ -1076,9 +1083,6 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetIndexBuffer(const D3D12_IN { list->IASetIndexBuffer(&view); - UINT64 dummy = 0; - WrappedID3D12Resource::GetResIDFromAddr( - view.BufferLocation, m_Cmd->m_BakedCmdListInfo[CommandList].state.ibuffer, dummy); m_Cmd->m_BakedCmdListInfo[CommandList].state.idxWidth = (view.Format == DXGI_FORMAT_R32_UINT ? 4 : 2); } @@ -1086,7 +1090,6 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetIndexBuffer(const D3D12_IN { list->IASetIndexBuffer(NULL); - m_Cmd->m_BakedCmdListInfo[CommandList].state.ibuffer = ResourceId(); m_Cmd->m_BakedCmdListInfo[CommandList].state.idxWidth = 2; } } @@ -1132,7 +1135,18 @@ bool WrappedID3D12GraphicsCommandList::Serialise_IASetVertexBuffers( { Unwrap(m_Cmd->RerecordCmdList(CommandList))->IASetVertexBuffers(start, num, views); - // m_RenderState.vbuffers = ; + if(m_Cmd->m_RenderState.vbuffers.size() < start + num) + m_Cmd->m_RenderState.vbuffers.resize(start + num); + + for(UINT i = 0; i < num; i++) + { + WrappedID3D12Resource::GetResIDFromAddr(views[i].BufferLocation, + m_Cmd->m_RenderState.vbuffers[start + i].buf, + m_Cmd->m_RenderState.vbuffers[start + i].offs); + + m_Cmd->m_RenderState.vbuffers[start + i].stride = views[i].StrideInBytes; + m_Cmd->m_RenderState.vbuffers[start + i].size = views[i].SizeInBytes; + } } } else if(m_State == READING) @@ -1218,6 +1232,15 @@ bool WrappedID3D12GraphicsCommandList::Serialise_OMSetRenderTargets( ->OMSetRenderTargets(num, rtHandles, singlehandle ? TRUE : FALSE, dsv.heap != ResourceId() ? &dsvHandle : NULL); + m_Cmd->m_RenderState.rts.resize(num); + + for(UINT i = 0; i < numHandles; i++) + m_Cmd->m_RenderState.rts[i] = rts[i]; + + m_Cmd->m_RenderState.rtSingle = singlehandle; + + m_Cmd->m_RenderState.dsv = dsv; + SAFE_DELETE_ARRAY(rtHandles); } } @@ -1234,6 +1257,48 @@ bool WrappedID3D12GraphicsCommandList::Serialise_OMSetRenderTargets( ->OMSetRenderTargets(num, rtHandles, singlehandle ? TRUE : FALSE, dsv.heap != ResourceId() ? &dsvHandle : NULL); + RDCEraseEl(m_Cmd->m_BakedCmdListInfo[CommandList].state.dsv); + RDCEraseEl(m_Cmd->m_BakedCmdListInfo[CommandList].state.rts); + + if(singlehandle) + { + WrappedID3D12DescriptorHeap *heap = + GetResourceManager()->GetLiveAs(rts[0].heap); + + const D3D12Descriptor *descs = heap->GetDescriptors() + rts[0].index; + + for(UINT i = 0; i < num; i++) + { + RDCASSERT(descs[i].GetType() == D3D12Descriptor::TypeRTV); + m_Cmd->m_BakedCmdListInfo[CommandList].state.rts[i] = GetResID(descs[i].nonsamp.resource); + } + } + else + { + for(UINT i = 0; i < num; i++) + { + WrappedID3D12DescriptorHeap *heap = + GetResourceManager()->GetLiveAs(rts[0].heap); + + const D3D12Descriptor &desc = heap->GetDescriptors()[rts[i].index]; + + RDCASSERT(desc.GetType() == D3D12Descriptor::TypeRTV); + m_Cmd->m_BakedCmdListInfo[CommandList].state.rts[i] = GetResID(desc.nonsamp.resource); + } + } + + if(dsv.heap != ResourceId()) + { + WrappedID3D12DescriptorHeap *heap = + GetResourceManager()->GetLiveAs(dsv.heap); + + const D3D12Descriptor &desc = heap->GetDescriptors()[dsv.index]; + + RDCASSERT(desc.GetType() == D3D12Descriptor::TypeDSV); + + m_Cmd->m_BakedCmdListInfo[CommandList].state.dsv = GetResID(desc.nonsamp.resource); + } + SAFE_DELETE_ARRAY(rtHandles); } diff --git a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp index 16631b863..e64bf4a23 100644 --- a/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_command_queue_wrap.cpp @@ -114,7 +114,7 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLis BakedCmdListInfo &cmdBufInfo = m_Cmd.m_BakedCmdListInfo[cmdIds[c]]; - // insert the baked command buffer in-line into this list of notes, assigning new event and + // insert the baked command list in-line into this list of notes, assigning new event and // drawIDs m_Cmd.InsertDrawsAndRefreshIDs(cmdBufInfo.draw->children); @@ -136,7 +136,7 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLis } */ - // only primary command buffers can be submitted + // only primary command lists can be submitted m_Cmd.m_Partial[D3D12CommandData::Primary].cmdListExecs[cmdIds[c]].push_back( m_Cmd.m_RootEventID); @@ -165,7 +165,7 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLis // advance m_CurEventID to match the events added when reading for(uint32_t c = 0; c < numCmds; c++) { - // 2 extra for the virtual labels around the command buffer + // 2 extra for the virtual labels around the command list m_Cmd.m_RootEventID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount; m_Cmd.m_RootDrawcallID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].drawCount; } @@ -222,7 +222,7 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLis for(uint32_t c = 0; c < numCmds; c++) { - // account for the virtual vkBeginCommandBuffer label at the start of the events here + // account for the virtual label at the start of the events here // so it matches up to baseEvent eid++; @@ -254,7 +254,7 @@ bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLis #endif } - // 1 extra to account for the virtual end command buffer label (begin is accounted for + // 1 extra to account for the virtual end command list label (begin is accounted for // above) eid += 1 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount; } @@ -340,11 +340,11 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists( if(capframe) { - // pull in frame refs from this baked command buffer + // pull in frame refs from this baked command list record->bakedCommands->AddResourceReferences(GetResourceManager()); record->bakedCommands->AddReferencedIDs(refdIDs); - // ref the parent command buffer by itself, this will pull in the cmd buffer pool + // 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 diff --git a/renderdoc/driver/d3d12/d3d12_commands.cpp b/renderdoc/driver/d3d12/d3d12_commands.cpp index df78a4194..526785022 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.cpp +++ b/renderdoc/driver/d3d12/d3d12_commands.cpp @@ -23,6 +23,7 @@ ******************************************************************************/ #include +#include "driver/dxgi/dxgi_common.h" #include "d3d12_command_list.h" #include "d3d12_command_queue.h" @@ -357,8 +358,13 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent m_pDevice->Serialise_BeginCaptureFrame(!partial); - m_pDevice->ExecuteLists(); - m_pDevice->FlushLists(); + if(readType == READING) + { + GetResourceManager()->ApplyInitialContents(); + + m_pDevice->ExecuteLists(); + m_pDevice->FlushLists(); + } m_pSerialiser->PopContext(header); @@ -370,7 +376,7 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent m_Cmd.m_RootEventID = ev.eventID; // if not partial, we need to be sure to replay - // past the command buffer records, so can't + // past the command list records, so can't // skip to the file offset of the first event if(partial) m_pSerialiser->SetOffset(ev.fileOffset); @@ -391,7 +397,7 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent if(m_State == EXECUTING && m_Cmd.m_RootEventID > endEventID) { // we can just break out if we've done all the events desired. - // note that the command buffer events aren't 'real' and we just blaze through them + // note that the command list events aren't 'real' and we just blaze through them break; } @@ -417,7 +423,7 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent // increment root event ID either if we didn't just replay a cmd // buffer event, OR if we are doing a frame sub-section replay, // in which case it's up to the calling code to make sure we only - // replay inside a command buffer (if we crossed command buffer + // replay inside a command list (if we crossed command list // boundaries, the event IDs would no longer match up). if(m_Cmd.m_LastCmdListID == ResourceId() || startEventID > 1) { @@ -432,9 +438,6 @@ void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEvent } } - m_pDevice->ExecuteLists(); - m_pDevice->FlushLists(true); - if(m_State == READING) { struct SortEID @@ -708,6 +711,12 @@ void D3D12CommandData::AddDrawcall(const FetchDrawcall &d, bool hasEvents) if(m_LastCmdListID != ResourceId()) { // TODO fill from m_BakedCmdListInfo[m_LastCmdListID].state + + draw.topology = MakePrimitiveTopology(m_BakedCmdListInfo[m_LastCmdListID].state.topo); + draw.indexByteWidth = m_BakedCmdListInfo[m_LastCmdListID].state.idxWidth; + + memcpy(draw.outputs, m_BakedCmdListInfo[m_LastCmdListID].state.rts, sizeof(draw.outputs)); + draw.depthOut = m_BakedCmdListInfo[m_LastCmdListID].state.dsv; } if(m_LastCmdListID != ResourceId()) diff --git a/renderdoc/driver/d3d12/d3d12_commands.h b/renderdoc/driver/d3d12/d3d12_commands.h index 2e4bf5f31..46f89f665 100644 --- a/renderdoc/driver/d3d12/d3d12_commands.h +++ b/renderdoc/driver/d3d12/d3d12_commands.h @@ -24,9 +24,10 @@ #pragma once -#include "common/common.h" #include "api/replay/renderdoc_replay.h" +#include "common/common.h" #include "d3d12_common.h" +#include "d3d12_state.h" struct D3D12DrawcallTreeNode { @@ -110,13 +111,9 @@ struct BakedCmdListInfo struct CmdListState { - ResourceId pipeline; - D3D12_PRIMITIVE_TOPOLOGY topo; uint32_t idxWidth; - ResourceId ibuffer; - vector vbuffers; ResourceId rts[8]; ResourceId dsv; @@ -140,6 +137,8 @@ struct D3D12CommandData map m_BakedCmdListInfo; + D3D12RenderState m_RenderState; + enum PartialReplayIndex { Primary, diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index bac2ab8a0..736fa6d39 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -90,6 +90,17 @@ string ToStrHelper::Get(const D3D12ComponentMappin : Unwrap(rm->GetLiveAs(id)); \ } +#define SerialiseWrappedObject(type, name, obj) \ + { \ + D3D12ResourceManager *rm = (D3D12ResourceManager *)GetUserData(); \ + ResourceId id; \ + if(m_Mode >= WRITING) \ + id = GetResID(obj); \ + Serialise(name, id); \ + if(m_Mode < WRITING) \ + obj = (id == ResourceId() || !rm->HasLiveResource(id)) ? NULL : rm->GetLiveAs(id); \ + } + template <> void Serialiser::Serialise(const char *name, D3D12Descriptor &el) { @@ -131,32 +142,31 @@ void Serialiser::Serialise(const char *name, D3D12Descriptor &el) } case D3D12Descriptor::TypeCBV: { - SerialiseObject(ID3D12Resource, "Resource", el.nonsamp.resource); Serialise("Descriptor", el.nonsamp.cbv); break; } case D3D12Descriptor::TypeSRV: { - SerialiseObject(ID3D12Resource, "Resource", el.nonsamp.resource); + SerialiseWrappedObject(ID3D12Resource, "Resource", el.nonsamp.resource); Serialise("Descriptor", el.nonsamp.srv); break; } case D3D12Descriptor::TypeRTV: { - SerialiseObject(ID3D12Resource, "Resource", el.nonsamp.resource); + SerialiseWrappedObject(ID3D12Resource, "Resource", el.nonsamp.resource); Serialise("Descriptor", el.nonsamp.rtv); break; } case D3D12Descriptor::TypeDSV: { - SerialiseObject(ID3D12Resource, "Resource", el.nonsamp.resource); + SerialiseWrappedObject(ID3D12Resource, "Resource", el.nonsamp.resource); Serialise("Descriptor", el.nonsamp.dsv); break; } case D3D12Descriptor::TypeUAV: { - SerialiseObject(ID3D12Resource, "Resource", el.nonsamp.resource); - SerialiseObject(ID3D12Resource, "CounterResource", el.nonsamp.uav.counterResource); + SerialiseWrappedObject(ID3D12Resource, "Resource", el.nonsamp.resource); + SerialiseWrappedObject(ID3D12Resource, "CounterResource", el.nonsamp.uav.counterResource); // special case because of extra resource and squeezed descriptor D3D12_UNORDERED_ACCESS_VIEW_DESC desc = el.nonsamp.uav.desc.AsDesc(); diff --git a/renderdoc/driver/d3d12/d3d12_device.cpp b/renderdoc/driver/d3d12/d3d12_device.cpp index 8a13eca09..fd7181614 100644 --- a/renderdoc/driver/d3d12/d3d12_device.cpp +++ b/renderdoc/driver/d3d12/d3d12_device.cpp @@ -951,7 +951,7 @@ void WrappedID3D12Device::StartFrameCapture(void *dev, void *wnd) Serialise_BeginCaptureFrame(false); // need to hold onto this as it must come right after the capture chunk, - // before any command buffers + // before any command lists m_HeaderChunk = scope.Get(); } @@ -1082,14 +1082,13 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd) { const vector &cmdListRecords = m_Queue->GetCmdLists(); - RDCDEBUG("Flushing %u command buffer records to file serialiser", - (uint32_t)cmdListRecords.size()); + RDCDEBUG("Flushing %u command list records to file serialiser", (uint32_t)cmdListRecords.size()); for(size_t i = 0; i < cmdListRecords.size(); i++) { cmdListRecords[i]->Insert(recordlist); - RDCDEBUG("Adding %u chunks to file serialiser from command buffer %llu", + RDCDEBUG("Adding %u chunks to file serialiser from command list %llu", (uint32_t)recordlist.size(), cmdListRecords[i]->GetResourceID()); } @@ -1553,12 +1552,53 @@ void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID, m_State = EXECUTING; - if(replayType == eReplay_Full) - m_Queue->ReplayLog(EXECUTING, startEventID, endEventID, partial); - else if(replayType == eReplay_WithoutDraw) - m_Queue->ReplayLog(EXECUTING, startEventID, RDCMAX(1U, endEventID) - 1, partial); - else if(replayType == eReplay_OnlyDraw) - m_Queue->ReplayLog(EXECUTING, endEventID, endEventID, partial); - else - RDCFATAL("Unexpected replay type"); + { + D3D12CommandData &cmd = *m_Queue->GetCommandData(); + + if(!partial) + { + RDCASSERT(cmd.m_Partial[D3D12CommandData::Primary].resultPartialCmdList == NULL); + RDCASSERT(cmd.m_Partial[D3D12CommandData::Secondary].resultPartialCmdList == NULL); + cmd.m_Partial[D3D12CommandData::Primary].Reset(); + cmd.m_Partial[D3D12CommandData::Secondary].Reset(); + cmd.m_RenderState = D3D12RenderState(); + cmd.m_RenderState.m_ResourceManager = GetResourceManager(); + } + + // we'll need our own command list if we're replaying just a subsection + // of events within a single command list record - always if it's only + // one drawcall, or if start event ID is > 0 we assume the outside code + // has chosen a subsection that lies within a command list + if(partial) + { + ID3D12GraphicsCommandList *list = cmd.m_Partial[D3D12CommandData::Primary].outsideCmdList = + GetNewList(); + + cmd.m_RenderState.ApplyState(list); + } + + if(replayType == eReplay_Full) + m_Queue->ReplayLog(EXECUTING, startEventID, endEventID, partial); + else if(replayType == eReplay_WithoutDraw) + m_Queue->ReplayLog(EXECUTING, startEventID, RDCMAX(1U, endEventID) - 1, partial); + else if(replayType == eReplay_OnlyDraw) + m_Queue->ReplayLog(EXECUTING, endEventID, endEventID, partial); + else + RDCFATAL("Unexpected replay type"); + + if(cmd.m_Partial[D3D12CommandData::Primary].outsideCmdList != NULL) + { + ID3D12GraphicsCommandList *list = cmd.m_Partial[D3D12CommandData::Primary].outsideCmdList; + + list->Close(); + + ExecuteLists(); + + cmd.m_Partial[D3D12CommandData::Primary].outsideCmdList = NULL; + } + +#if defined(SINGLE_FLUSH_VALIDATE) + FlushLists(true); +#endif + } } diff --git a/renderdoc/driver/d3d12/d3d12_device.h b/renderdoc/driver/d3d12/d3d12_device.h index 2ab65a497..c24170192 100644 --- a/renderdoc/driver/d3d12/d3d12_device.h +++ b/renderdoc/driver/d3d12/d3d12_device.h @@ -303,7 +303,7 @@ public: WrappedID3D12Device(ID3D12Device *realDevice, D3D12InitParams *params); virtual ~WrappedID3D12Device(); - UINT GetDescriptorIncrement(D3D12_DESCRIPTOR_HEAP_TYPE type) + UINT GetUnwrappedDescriptorIncrement(D3D12_DESCRIPTOR_HEAP_TYPE type) { return m_DescriptorIncrements[type]; } diff --git a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp index 5e8973f3f..3c6fda41f 100644 --- a/renderdoc/driver/d3d12/d3d12_device_wrap.cpp +++ b/renderdoc/driver/d3d12/d3d12_device_wrap.cpp @@ -845,6 +845,8 @@ void WrappedID3D12Device::CopyDescriptors( NumSrcDescriptorRanges, srcStarts, pSrcDescriptorRangeSizes, DescriptorHeapsType); + RDCUNIMPLEMENTED("CopyDescriptors does not copy our internal descriptor data"); + SAFE_DELETE_ARRAY(dstStarts); SAFE_DELETE_ARRAY(srcStarts); } @@ -856,6 +858,21 @@ void WrappedID3D12Device::CopyDescriptorsSimple(UINT NumDescriptors, { m_pDevice->CopyDescriptorsSimple(NumDescriptors, Unwrap(DestDescriptorRangeStart), Unwrap(SrcDescriptorRangeStart), DescriptorHeapsType); + + D3D12Descriptor *src = GetWrapped(SrcDescriptorRangeStart); + D3D12Descriptor *dst = GetWrapped(DestDescriptorRangeStart); + + for(UINT i = 0; i < NumDescriptors; i++) + { + // save these so we can do a straight copy then restore them + WrappedID3D12DescriptorHeap *heap = dst[i].samp.heap; + uint32_t index = dst[i].samp.idx; + + dst[i] = src[i]; + + dst[i].samp.heap = heap; + dst[i].samp.idx = index; + } } HRESULT WrappedID3D12Device::OpenSharedHandle(HANDLE NTHandle, REFIID riid, void **ppvObj) diff --git a/renderdoc/driver/d3d12/d3d12_manager.cpp b/renderdoc/driver/d3d12/d3d12_manager.cpp index 6ab92453f..fd8a78be7 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.cpp +++ b/renderdoc/driver/d3d12/d3d12_manager.cpp @@ -469,8 +469,8 @@ bool D3D12ResourceManager::Serialise_InitialState(ResourceId resid, ID3D12Device desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; ID3D12DescriptorHeap *copyheap = NULL; - HRESULT hr = m_Device->GetReal()->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), - (void **)©heap); + HRESULT hr = + m_Device->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap), (void **)©heap); if(FAILED(hr)) { @@ -480,11 +480,11 @@ bool D3D12ResourceManager::Serialise_InitialState(ResourceId resid, ID3D12Device D3D12_CPU_DESCRIPTOR_HANDLE handle = copyheap->GetCPUDescriptorHandleForHeapStart(); - UINT increment = m_Device->GetDescriptorIncrement(desc.Type); + UINT increment = m_Device->GetDescriptorHandleIncrementSize(desc.Type); for(uint32_t i = 0; i < numElems; i++) { - descs[i].Create(m_Device->GetReal(), handle); + descs[i].Create(m_Device, handle); handle.ptr += increment; } @@ -599,13 +599,13 @@ void D3D12ResourceManager::Apply_InitialState(ID3D12DeviceChild *live, InitialCo if(type == Resource_DescriptorHeap) { - ID3D12DescriptorHeap *dstheap = Unwrap((ID3D12DescriptorHeap *)live); + ID3D12DescriptorHeap *dstheap = (ID3D12DescriptorHeap *)live; ID3D12DescriptorHeap *srcheap = (ID3D12DescriptorHeap *)data.resource; if(srcheap) { // copy the whole heap - m_Device->GetReal()->CopyDescriptorsSimple( + m_Device->CopyDescriptorsSimple( srcheap->GetDesc().NumDescriptors, dstheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetCPUDescriptorHandleForHeapStart(), srcheap->GetDesc().Type); } diff --git a/renderdoc/driver/d3d12/d3d12_manager.h b/renderdoc/driver/d3d12/d3d12_manager.h index 950f8ae1f..18ba5a241 100644 --- a/renderdoc/driver/d3d12/d3d12_manager.h +++ b/renderdoc/driver/d3d12/d3d12_manager.h @@ -130,7 +130,7 @@ struct D3D12Descriptor TypeUndefined, }; - DescriptorType GetType() + DescriptorType GetType() const { RDCCOMPILE_ASSERT(sizeof(D3D12Descriptor) <= 64, "D3D12Descriptor has gotten larger"); @@ -223,7 +223,7 @@ struct CmdListRecordingInfo { vector barriers; - // a list of all resources dirtied by this command buffer + // a list of all resources dirtied by this command list set dirtied; // bundles executed @@ -291,6 +291,12 @@ public: return (T *)GetLiveResource(id); } + template + T *GetCurrentAs(ResourceId id) + { + return (T *)GetCurrentResource(id); + } + void ApplyBarriers(vector &barriers, map &states); diff --git a/renderdoc/driver/d3d12/d3d12_resources.cpp b/renderdoc/driver/d3d12/d3d12_resources.cpp index 950402b83..b123c57cd 100644 --- a/renderdoc/driver/d3d12/d3d12_resources.cpp +++ b/renderdoc/driver/d3d12/d3d12_resources.cpp @@ -148,7 +148,7 @@ WrappedID3D12DescriptorHeap::WrappedID3D12DescriptorHeap(ID3D12DescriptorHeap *r realCPUBase = real->GetCPUDescriptorHandleForHeapStart(); realGPUBase = real->GetGPUDescriptorHandleForHeapStart(); - increment = device->GetDescriptorIncrement(desc.Type); + increment = device->GetUnwrappedDescriptorIncrement(desc.Type); descriptors = new D3D12Descriptor[desc.NumDescriptors]; diff --git a/renderdoc/driver/d3d12/d3d12_state.cpp b/renderdoc/driver/d3d12/d3d12_state.cpp new file mode 100644 index 000000000..5fa6c8870 --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_state.cpp @@ -0,0 +1,153 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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 "d3d12_state.h" +#include "d3d12_command_list.h" +#include "d3d12_manager.h" +#include "d3d12_resources.h" + +D3D12RenderState::D3D12RenderState() +{ + views.clear(); + scissors.clear(); + + rts.clear(); + rtSingle = false; + dsv = PortableHandle(); + + m_ResourceManager = NULL; + + pipe = graphics.rootsig = compute.rootsig = ResourceId(); + graphics.sigelems.clear(); + compute.sigelems.clear(); + + topo = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; + + RDCEraseEl(ibuffer); + vbuffers.clear(); +} + +D3D12RenderState &D3D12RenderState::operator=(const D3D12RenderState &o) +{ + views = o.views; + scissors = o.scissors; + + rts = o.rts; + rtSingle = o.rtSingle; + dsv = o.dsv; + + pipe = o.pipe; + + graphics.rootsig = o.graphics.rootsig; + graphics.sigelems = o.graphics.sigelems; + compute.rootsig = o.compute.rootsig; + compute.sigelems = o.compute.sigelems; + + topo = o.topo; + + ibuffer = o.ibuffer; + vbuffers = o.vbuffers; + + return *this; +} + +void D3D12RenderState::ApplyState(ID3D12GraphicsCommandList *cmd) +{ + if(pipe != ResourceId()) + cmd->SetPipelineState(GetResourceManager()->GetCurrentAs(pipe)); + + if(!views.empty()) + cmd->RSSetViewports((UINT)views.size(), &views[0]); + + if(!scissors.empty()) + cmd->RSSetScissorRects((UINT)scissors.size(), &scissors[0]); + + if(topo != D3D_PRIMITIVE_TOPOLOGY_UNDEFINED) + cmd->IASetPrimitiveTopology(topo); + + if(ibuffer.buf != ResourceId()) + { + D3D12_INDEX_BUFFER_VIEW ib; + + ID3D12Resource *res = GetResourceManager()->GetCurrentAs(ibuffer.buf); + if(res) + ib.BufferLocation = res->GetGPUVirtualAddress() + ibuffer.offs; + else + ib.BufferLocation = 0; + + ib.Format = (ibuffer.bytewidth == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT); + ib.SizeInBytes = ibuffer.size; + + cmd->IASetIndexBuffer(&ib); + } + + for(size_t i = 0; i < vbuffers.size(); i++) + { + D3D12_VERTEX_BUFFER_VIEW vb; + + ID3D12Resource *res = GetResourceManager()->GetCurrentAs(vbuffers[i].buf); + if(res) + vb.BufferLocation = res->GetGPUVirtualAddress() + vbuffers[i].offs; + else + vb.BufferLocation = 0; + + vb.StrideInBytes = vbuffers[i].stride; + vb.SizeInBytes = vbuffers[i].size; + + cmd->IASetVertexBuffers((UINT)i, 1, &vb); + } + + if(!rts.empty() || dsv.heap != ResourceId()) + { + D3D12_CPU_DESCRIPTOR_HANDLE rtHandles[8]; + D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = FromPortableHandle(GetResourceManager(), dsv); + + UINT numActualHandles = rtSingle ? 1 : (UINT)rts.size(); + + for(UINT i = 0; i < numActualHandles; i++) + rtHandles[i] = FromPortableHandle(GetResourceManager(), rts[i]); + + // need to unwrap here, as FromPortableHandle unwraps too. + Unwrap(cmd)->OMSetRenderTargets((UINT)rts.size(), rtHandles, rtSingle ? TRUE : FALSE, + dsv.heap != ResourceId() ? &dsvHandle : NULL); + } + + if(graphics.rootsig != ResourceId()) + { + cmd->SetGraphicsRootSignature( + GetResourceManager()->GetCurrentAs(graphics.rootsig)); + + for(size_t i = 0; i < graphics.sigelems.size(); i++) + graphics.sigelems[i].SetToCommandList(GetResourceManager(), cmd, (UINT)i); + } + + if(compute.rootsig != ResourceId()) + { + cmd->SetComputeRootSignature( + GetResourceManager()->GetCurrentAs(compute.rootsig)); + + for(size_t i = 0; i < compute.sigelems.size(); i++) + compute.sigelems[i].SetToCommandList(GetResourceManager(), cmd, (UINT)i); + } +} \ No newline at end of file diff --git a/renderdoc/driver/d3d12/d3d12_state.h b/renderdoc/driver/d3d12/d3d12_state.h new file mode 100644 index 000000000..7b7a01084 --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_state.h @@ -0,0 +1,152 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * 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. + ******************************************************************************/ + +#pragma once + +#include +#include "d3d12_common.h" +#include "d3d12_manager.h" + +class D3D12ResourceManager; + +enum SignatureElementType +{ + eRootUnknown, + eRootConst, + eRootTable, + eRootCBV, + eRootSRV, + eRootUAV, +}; + +struct D3D12RenderState +{ + D3D12RenderState(); + D3D12RenderState &operator=(const D3D12RenderState &o); + + void ApplyState(ID3D12GraphicsCommandList *list); + + vector views; + vector scissors; + + vector rts; + bool rtSingle; + PortableHandle dsv; + + struct SignatureElement + { + SignatureElement() : type(eRootUnknown), offset(0) {} + SignatureElement(SignatureElementType t, ResourceId i, UINT64 o) : type(t), id(i), offset(o) {} + SignatureElement(UINT val) : type(eRootConst), offset(0) { constants.push_back(val); } + SignatureElement(UINT numVals, const void *vals, UINT destIdx) + { + SetValues(numVals, vals, destIdx); + } + + void SetValues(UINT numVals, const void *vals, UINT destIdx) + { + type = eRootConst; + offset = 0; + + if(constants.size() < destIdx + numVals) + constants.resize(destIdx + numVals); + + memcpy(&constants[destIdx], vals, numVals * sizeof(UINT)); + } + + void SetToCommandList(D3D12ResourceManager *rm, ID3D12GraphicsCommandList *cmd, UINT slot) + { + if(type == eRootConst) + { + if(constants.size() == 1) + cmd->SetGraphicsRoot32BitConstant(slot, constants[0], 0); + else + cmd->SetGraphicsRoot32BitConstants(slot, (UINT)constants.size(), &constants[0], 0); + } + else if(type == eRootTable) + { + D3D12_GPU_DESCRIPTOR_HANDLE handle = + rm->GetCurrentAs(id)->GetGPUDescriptorHandleForHeapStart(); + handle.ptr += sizeof(D3D12Descriptor) * offset; + cmd->SetGraphicsRootDescriptorTable(slot, handle); + } + else if(type == eRootCBV) + { + ID3D12Resource *res = rm->GetCurrentAs(id); + cmd->SetGraphicsRootConstantBufferView(slot, res->GetGPUVirtualAddress() + offset); + } + else if(type == eRootSRV) + { + ID3D12Resource *res = rm->GetCurrentAs(id); + cmd->SetGraphicsRootShaderResourceView(slot, res->GetGPUVirtualAddress() + offset); + } + else if(type == eRootUAV) + { + ID3D12Resource *res = rm->GetCurrentAs(id); + cmd->SetGraphicsRootUnorderedAccessView(slot, res->GetGPUVirtualAddress() + offset); + } + else + { + RDCWARN("Unexpected root signature element of type '%u' - skipping.", type); + } + } + + SignatureElementType type; + + ResourceId id; + UINT64 offset; + vector constants; + }; + + struct Pipeline + { + ResourceId rootsig; + + vector sigelems; + } compute, graphics; + + ResourceId pipe; + + D3D12_PRIMITIVE_TOPOLOGY topo; + + struct IdxBuffer + { + ResourceId buf; + UINT64 offs; + int bytewidth; + UINT size; + } ibuffer; + + struct VertBuffer + { + ResourceId buf; + UINT64 offs; + UINT stride; + UINT size; + }; + vector vbuffers; + + D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; } + D3D12ResourceManager *m_ResourceManager; +}; diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index 21f15cbdb..3201ead71 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -195,6 +195,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index 66b7cfb55..98631ad3c 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -54,6 +54,9 @@ Core IFaces + + Util + @@ -89,5 +92,8 @@ Replay + + Util + \ No newline at end of file