Add mostly stubbed D3D12 replay interface, and 2 core chunk replay loops

This commit is contained in:
baldurk
2016-07-10 18:09:44 +02:00
parent 89f40fb0df
commit 5c963fc6a6
18 changed files with 1960 additions and 97 deletions
@@ -100,6 +100,9 @@ class WrappedID3D12GraphicsCommandList : public RefCounter12<ID3D12GraphicsComma
D3D12_COMMAND_LIST_TYPE type;
} m_Init;
void AddDrawcall(const FetchDrawcall &d, bool hasEvents);
void AddEvent(D3D12ChunkType type, string description);
const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); }
D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); }
public:
@@ -162,7 +162,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT Index
if(m_State == READING)
{
// TODO - AddEvent(DRAW_INDEXED_INST, desc);
AddEvent(DRAW_INDEXED_INST, desc);
string name =
"DrawIndexedInstanced(" + ToStr::Get(idxCount) + ", " + ToStr::Get(instCount) + ")";
@@ -176,7 +176,7 @@ bool WrappedID3D12GraphicsCommandList::Serialise_DrawIndexedInstanced(UINT Index
draw.flags |= eDraw_Drawcall | eDraw_Instanced | eDraw_UseIBuffer;
// TODO - AddDrawcall(draw, true);
AddDrawcall(draw, true);
}
return true;
@@ -496,7 +496,7 @@ void WrappedID3D12GraphicsCommandList::SetGraphicsRootSignature(ID3D12RootSignat
if(m_State >= WRITING)
{
SCOPED_SERIALISE_CONTEXT(SET_ROOT_SIG);
SCOPED_SERIALISE_CONTEXT(SET_GFX_ROOT_SIG);
Serialise_SetGraphicsRootSignature(pRootSignature);
m_ListRecord->AddChunk(scope.Get());
@@ -24,6 +24,7 @@
#pragma once
#include <list>
#include "common/wrapped_pool.h"
#include "d3d12_common.h"
#include "d3d12_device.h"
@@ -66,12 +67,48 @@ struct DummyID3D12DebugCommandQueue : public ID3D12DebugCommandQueue
}
};
struct D3D12DrawcallTreeNode
{
D3D12DrawcallTreeNode() {}
explicit D3D12DrawcallTreeNode(const FetchDrawcall &d) : draw(d) {}
FetchDrawcall draw;
vector<D3D12DrawcallTreeNode> children;
vector<pair<ResourceId, EventUsage> > resourceUsage;
D3D12DrawcallTreeNode &operator=(const FetchDrawcall &d)
{
*this = D3D12DrawcallTreeNode(d);
return *this;
}
vector<FetchDrawcall> Bake()
{
vector<FetchDrawcall> ret;
if(children.empty())
return ret;
ret.resize(children.size());
for(size_t i = 0; i < children.size(); i++)
{
ret[i] = children[i].draw;
ret[i].children = children[i].Bake();
}
return ret;
}
};
class WrappedID3D12GraphicsCommandList;
class WrappedID3D12CommandQueue : public ID3D12CommandQueue,
public RefCounter12<ID3D12CommandQueue>,
public ID3DDevice
{
WrappedID3D12Device *m_pDevice;
WrappedID3D12GraphicsCommandList *m_ReplayList;
ResourceId m_ResourceID;
D3D12ResourceRecord *m_QueueRecord;
@@ -82,6 +119,136 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue,
vector<D3D12ResourceRecord *> m_CmdListRecords;
vector<FetchAPIEvent> m_RootEvents, m_Events;
bool m_AddedDrawcall;
uint64_t m_CurChunkOffset;
uint32_t m_RootEventID, m_RootDrawcallID;
uint32_t m_FirstEventID, m_LastEventID;
D3D12DrawcallTreeNode m_ParentDrawcall;
void InsertDrawsAndRefreshIDs(vector<D3D12DrawcallTreeNode> &cmdBufNodes, uint32_t baseEventID,
uint32_t baseDrawID);
struct BakedCmdListInfo
{
vector<FetchAPIEvent> curEvents;
vector<DebugMessage> debugMessages;
std::list<D3D12DrawcallTreeNode *> drawStack;
vector<pair<ResourceId, EventUsage> > resourceUsage;
struct CmdListState
{
ResourceId pipeline;
uint32_t idxWidth;
ResourceId ibuffer;
vector<ResourceId> vbuffers;
ResourceId rts[8];
ResourceId dsv;
} state;
vector<D3D12_RESOURCE_BARRIER> barriers;
D3D12DrawcallTreeNode *draw; // the root draw to copy from when submitting
uint32_t eventCount; // how many events are in this cmd list, for quick skipping
uint32_t curEventID; // current event ID while reading or executing
uint32_t drawCount; // similar to above
};
map<ResourceId, BakedCmdListInfo> m_BakedCmdListInfo;
// on replay, the current command list for the last chunk we
// handled.
ResourceId m_LastCmdListID;
int m_CmdListsInProgress;
// this is a list of uint64_t file offset -> uint32_t EIDs of where each
// drawcall is used. E.g. the drawcall at offset 873954 is EID 50. If a
// command list is executed more than once, there may be more than
// one entry here - the drawcall will be aliased among several EIDs, with
// the first one being the 'primary'
struct DrawcallUse
{
DrawcallUse(uint64_t offs, uint32_t eid) : fileOffset(offs), eventID(eid) {}
uint64_t fileOffset;
uint32_t eventID;
bool operator<(const DrawcallUse &o) const
{
if(fileOffset != o.fileOffset)
return fileOffset < o.fileOffset;
return eventID < o.eventID;
}
};
vector<DrawcallUse> m_DrawcallUses;
struct PartialReplayData
{
// if we're doing a partial replay, by definition only one command
// list will be partial at any one time. While replaying through
// the command list chunks, the partial command list will be
// created as a temporary new command list and when it comes to
// the queue that should execute it, it can execute this instead.
ID3D12CommandAllocator *resultPartialCmdAllocator;
ID3D12GraphicsCommandList *resultPartialCmdList;
// if we're replaying just a single draw or a particular command
// list subsection of command events, we don't go through the
// whole original command lists to set up the partial replay,
// so we just set this command list
ID3D12GraphicsCommandList *outsideCmdList;
// this records where in the frame a command list was executed,
// so that we know if our replay range ends in one of these ranges
// we need to construct a partial command list for future
// replaying. Note that we always have the complete command list
// around - it's the bakeID itself.
// Since we only ever record a bakeID once the key is unique - note
// that the same command list could be reset multiple times
// a frame, so the parent command list ID (the one recorded in
// CmdList chunks) is NOT unique.
// However, a single baked command list can be executed multiple
// times - so we have to have a list of base events
// Map from bakeID -> vector<baseEventID>
map<ResourceId, vector<uint32_t> > cmdListExecs;
// This is just the ResourceId of the original parent command list
// and it's baked id.
// If we are in the middle of a partial replay - allows fast checking
// in all CmdList chunks, with the iteration through the above list
// only in Reset.
// partialParent gets reset to ResourceId() in the Close so that
// other baked command lists from the same parent don't pick it up
// Also reset each overall replay
ResourceId partialParent;
// If a partial replay is detected, this records the base of the
// range. This both allows easily and uniquely identifying it in the
// executecmdlists, but also allows the recording to 'rebase' the
// last event ID by subtracting this, to know how far to record
uint32_t baseEvent;
} m_PartialReplayData;
map<ResourceId, ID3D12GraphicsCommandList *> m_RerecordCmds;
std::list<D3D12DrawcallTreeNode *> m_DrawcallStack;
std::list<D3D12DrawcallTreeNode *> &GetDrawcallStack()
{
if(m_LastCmdListID != ResourceId())
return m_BakedCmdListInfo[m_LastCmdListID].drawStack;
return m_DrawcallStack;
}
bool ShouldRerecordCmd(ResourceId cmdid);
bool InRerecordRange();
ID3D12GraphicsCommandList *RerecordCmdList(ResourceId cmdid);
void ProcessChunk(uint64_t offset, D3D12ChunkType context);
const char *GetChunkName(uint32_t idx) { return m_pDevice->GetChunkName(idx); }
D3D12ResourceManager *GetResourceManager() { return m_pDevice->GetResourceManager(); }
public:
@@ -98,8 +265,16 @@ public:
D3D12ResourceRecord *GetResourceRecord() { return m_QueueRecord; }
WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; }
const vector<D3D12ResourceRecord *> &GetCmdLists() { return m_CmdListRecords; }
D3D12DrawcallTreeNode &GetParentDrawcall() { return m_ParentDrawcall; }
FetchAPIEvent GetEvent(uint32_t eventID);
uint32_t GetMaxEID() { return m_Events.back().eventID; }
void ClearAfterCapture();
void AddDrawcall(const FetchDrawcall &d, bool hasEvents);
void AddEvent(D3D12ChunkType type, string description);
void ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial);
// interface for DXGI
virtual IUnknown *GetRealIUnknown() { return GetReal(); }
virtual IID GetBackbufferUUID() { return __uuidof(ID3D12Resource); }
@@ -90,8 +90,6 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists(
{
D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]);
// TODO apply barriers from command list to current resource state tracking
m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers);
// need to lock the whole section of code, not just the check on
+348 -1
View File
@@ -22,6 +22,7 @@
* THE SOFTWARE.
******************************************************************************/
#include <algorithm>
#include "d3d12_command_list.h"
#include "d3d12_command_queue.h"
@@ -147,6 +148,8 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real,
if(RenderDoc::Inst().IsReplayApp())
{
m_pSerialiser = serialiser;
m_ReplayList = new WrappedID3D12GraphicsCommandList(NULL, m_pDevice, m_pSerialiser, state);
}
else
{
@@ -162,6 +165,20 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real,
m_QueueRecord = NULL;
m_RootEventID = 1;
m_RootDrawcallID = 1;
m_FirstEventID = 0;
m_LastEventID = ~0U;
m_LastCmdListID = ResourceId();
m_PartialReplayData.resultPartialCmdList = NULL;
m_PartialReplayData.outsideCmdList = NULL;
m_PartialReplayData.partialParent = ResourceId();
m_PartialReplayData.baseEvent = 0;
m_DrawcallStack.push_back(&m_ParentDrawcall);
if(!RenderDoc::Inst().IsReplayApp())
{
m_QueueRecord = m_pDevice->GetResourceManager()->AddResourceRecord(m_ResourceID);
@@ -228,6 +245,325 @@ void WrappedID3D12CommandQueue::ClearAfterCapture()
m_CmdListRecords.clear();
}
FetchAPIEvent WrappedID3D12CommandQueue::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 WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chunk)
{
m_CurChunkOffset = offset;
m_AddedDrawcall = false;
switch(chunk)
{
case CLOSE_LIST: m_ReplayList->Close(); break;
case RESET_LIST: m_ReplayList->Serialise_Reset(NULL, NULL); break;
case RESOURCE_BARRIER: m_ReplayList->Serialise_ResourceBarrier(0, NULL); break;
case DRAW_INDEXED_INST: m_ReplayList->Serialise_DrawIndexedInstanced(0, 0, 0, 0, 0); break;
case COPY_BUFFER: m_ReplayList->Serialise_CopyBufferRegion(NULL, 0, NULL, 0, 0); break;
case CLEAR_RTV:
m_ReplayList->Serialise_ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE(), (FLOAT *)NULL, 0,
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_PIPE: m_ReplayList->Serialise_SetPipelineState(NULL); break;
case SET_RTVS: m_ReplayList->Serialise_OMSetRenderTargets(0, NULL, FALSE, NULL); break;
case SET_GFX_ROOT_SIG: m_ReplayList->Serialise_SetGraphicsRootSignature(NULL); break;
case SET_GFX_ROOT_CBV:
m_ReplayList->Serialise_SetGraphicsRootConstantBufferView(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);
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, "Present()");
FetchDrawcall draw;
draw.name = "Present()";
draw.flags |= eDraw_Present;
draw.copyDestination = bbid;
AddDrawcall(draw, true);
}
}
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 == PUSH_EVENT || chunk == POP_EVENT))
{
// don't add these events - they will be handled when inserted in-line into queue submit
}
else if(m_State == READING)
{
if(!m_AddedDrawcall)
AddEvent(chunk, m_pSerialiser->GetDebugStr());
}
m_AddedDrawcall = false;
}
void WrappedID3D12CommandQueue::ReplayLog(LogState readType, uint32_t startEventID,
uint32_t endEventID, bool partial)
{
m_State = readType;
D3D12ChunkType header = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
RDCASSERTEQUAL(header, CONTEXT_CAPTURE_HEADER);
m_pDevice->Serialise_BeginCaptureFrame(!partial);
m_pDevice->GPUSync();
m_pSerialiser->PopContext(header);
m_RootEvents.clear();
if(m_State == EXECUTING)
{
FetchAPIEvent ev = GetEvent(startEventID);
m_RootEventID = ev.eventID;
// if not partial, we need to be sure to replay
// past the command buffer records, so can't
// skip to the file offset of the first event
if(partial)
m_pSerialiser->SetOffset(ev.fileOffset);
m_FirstEventID = startEventID;
m_LastEventID = endEventID;
}
else if(m_State == READING)
{
m_RootEventID = 1;
m_RootDrawcallID = 1;
m_FirstEventID = 0;
m_LastEventID = ~0U;
}
for(;;)
{
if(m_State == EXECUTING && 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
break;
}
uint64_t offset = m_pSerialiser->GetOffset();
D3D12ChunkType context = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
m_LastCmdListID = ResourceId();
ProcessChunk(offset, context);
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;
// break out if we were only executing one event
if(m_State == EXECUTING && startEventID == endEventID)
break;
// 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
// boundaries, the event IDs would no longer match up).
if(m_LastCmdListID == ResourceId() || startEventID > 1)
{
m_RootEventID++;
if(startEventID > 1)
m_pSerialiser->SetOffset(GetEvent(m_RootEventID).fileOffset);
}
else
{
m_BakedCmdListInfo[m_LastCmdListID].curEventID++;
}
}
m_pDevice->GPUSync();
if(m_State == READING)
{
struct SortEID
{
bool operator()(const FetchAPIEvent &a, const FetchAPIEvent &b)
{
return a.eventID < b.eventID;
}
};
std::sort(m_Events.begin(), m_Events.end(), SortEID());
}
SAFE_RELEASE(m_PartialReplayData.resultPartialCmdList);
for(auto it = m_RerecordCmds.begin(); it != m_RerecordCmds.end(); ++it)
SAFE_RELEASE(it->second);
m_RerecordCmds.clear();
m_State = READING;
}
void WrappedID3D12CommandQueue::AddDrawcall(const FetchDrawcall &d, bool hasEvents)
{
m_AddedDrawcall = true;
FetchDrawcall draw = d;
draw.eventID = m_LastCmdListID != ResourceId() ? m_BakedCmdListInfo[m_LastCmdListID].curEventID
: m_RootEventID;
draw.drawcallID = m_LastCmdListID != ResourceId() ? m_BakedCmdListInfo[m_LastCmdListID].drawCount
: m_RootDrawcallID;
for(int i = 0; i < 8; i++)
draw.outputs[i] = ResourceId();
draw.depthOut = ResourceId();
draw.indexByteWidth = 0;
draw.topology = eTopology_Unknown;
if(m_LastCmdListID != ResourceId())
{
// TODO fill from m_BakedCmdListInfo[m_LastCmdListID].state
}
if(m_LastCmdListID != ResourceId())
m_BakedCmdListInfo[m_LastCmdListID].drawCount++;
else
m_RootDrawcallID++;
if(hasEvents)
{
vector<FetchAPIEvent> &srcEvents = m_LastCmdListID != ResourceId()
? m_BakedCmdListInfo[m_LastCmdListID].curEvents
: m_RootEvents;
draw.events = srcEvents;
srcEvents.clear();
}
// should have at least the root drawcall here, push this drawcall
// onto the back's children list.
if(!GetDrawcallStack().empty())
{
D3D12DrawcallTreeNode node(draw);
node.resourceUsage.swap(m_BakedCmdListInfo[m_LastCmdListID].resourceUsage);
// TODO add usage
node.children.insert(node.children.begin(), draw.children.elems,
draw.children.elems + draw.children.count);
GetDrawcallStack().back()->children.push_back(node);
}
else
RDCERR("Somehow lost drawcall stack!");
}
void WrappedID3D12CommandQueue::AddEvent(D3D12ChunkType type, string description)
{
FetchAPIEvent apievent;
apievent.context = ResourceId();
apievent.fileOffset = m_CurChunkOffset;
apievent.eventID = m_LastCmdListID != ResourceId() ? m_BakedCmdListInfo[m_LastCmdListID].curEventID
: m_RootEventID;
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());
}
// TODO have real m_EventMessages
vector<DebugMessage> m_EventMessages;
for(size_t i = 0; i < m_EventMessages.size(); i++)
m_EventMessages[i].eventID = apievent.eventID;
if(m_LastCmdListID != ResourceId())
{
m_BakedCmdListInfo[m_LastCmdListID].curEvents.push_back(apievent);
vector<DebugMessage> &msgs = m_BakedCmdListInfo[m_LastCmdListID].debugMessages;
msgs.insert(msgs.end(), m_EventMessages.begin(), m_EventMessages.end());
}
else
{
m_RootEvents.push_back(apievent);
m_Events.push_back(apievent);
// TODO m_DebugMessages.insert(m_DebugMessages.end(), m_EventMessages.begin(),
// m_EventMessages.end());
}
m_EventMessages.clear();
}
WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12GraphicsCommandList *real,
WrappedID3D12Device *device,
Serialiser *serialiser,
@@ -238,7 +574,8 @@ WrappedID3D12GraphicsCommandList::WrappedID3D12GraphicsCommandList(ID3D12Graphic
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(
this, sizeof(WrappedID3D12GraphicsCommandList));
m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandList), (void **)&m_DummyDebug.m_pReal);
if(m_pReal)
m_pReal->QueryInterface(__uuidof(ID3D12DebugCommandList), (void **)&m_DummyDebug.m_pReal);
if(RenderDoc::Inst().IsReplayApp())
{
@@ -326,3 +663,13 @@ HRESULT STDMETHODCALLTYPE WrappedID3D12GraphicsCommandList::QueryInterface(REFII
return RefCounter12::QueryInterface(riid, ppvObject);
}
void WrappedID3D12GraphicsCommandList::AddDrawcall(const FetchDrawcall &d, bool hasEvents)
{
m_pDevice->GetQueue()->AddDrawcall(d, hasEvents);
}
void WrappedID3D12GraphicsCommandList::AddEvent(D3D12ChunkType type, string description)
{
m_pDevice->GetQueue()->AddEvent(type, description);
}
+56 -56
View File
@@ -151,62 +151,62 @@ void Serialiser::Serialise(const char *name, D3D12Descriptor &el);
#pragma region Chunks
#define D3D12_CHUNKS \
D3D12_CHUNK_MACRO(DEVICE_INIT = FIRST_CHUNK_ID, "ID3D12Device::Initialisation") \
D3D12_CHUNK_MACRO(SET_RESOURCE_NAME, "ID3D12Object::SetName") \
D3D12_CHUNK_MACRO(RELEASE_RESOURCE, "IUnknown::Release") \
D3D12_CHUNK_MACRO(CREATE_SWAP_BUFFER, "IDXGISwapChain::GetBuffer") \
\
D3D12_CHUNK_MACRO(CAPTURE_SCOPE, "Capture") \
\
D3D12_CHUNK_MACRO(PUSH_EVENT, "BeginEvent") \
D3D12_CHUNK_MACRO(SET_MARKER, "SetMarker") \
D3D12_CHUNK_MACRO(POP_EVENT, "EndEvent") \
\
D3D12_CHUNK_MACRO(DEBUG_MESSAGES, "DebugMessageList") \
\
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_HEADER, "ContextBegin") \
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_FOOTER, "ContextEnd") \
\
D3D12_CHUNK_MACRO(SET_SHADER_DEBUG_PATH, "SetShaderDebugPath") \
\
D3D12_CHUNK_MACRO(CREATE_COMMAND_QUEUE, "ID3D12Device::CreateCommandQueue") \
D3D12_CHUNK_MACRO(CREATE_COMMAND_ALLOCATOR, "ID3D12Device::CreateCommandAllocator") \
D3D12_CHUNK_MACRO(CREATE_COMMAND_LIST, "ID3D12Device::CreateCommandList") \
\
D3D12_CHUNK_MACRO(CREATE_GRAPHICS_PIPE, "ID3D12Device::CreateGraphicsPipeline") \
D3D12_CHUNK_MACRO(CREATE_COMPUTE_PIPE, "ID3D12Device::CreateComputePipeline") \
D3D12_CHUNK_MACRO(CREATE_DESCRIPTOR_HEAP, "ID3D12Device::CreateDescriptorHeap") \
D3D12_CHUNK_MACRO(CREATE_ROOT_SIG, "ID3D12Device::CreateRootSignature") \
\
D3D12_CHUNK_MACRO(CREATE_COMMITTED_RESOURCE, "ID3D12Device::CreateCommittedResource") \
\
D3D12_CHUNK_MACRO(CREATE_FENCE, "ID3D12Device::CreateFence") \
\
D3D12_CHUNK_MACRO(CLOSE_LIST, "ID3D12GraphicsCommandList::Close") \
D3D12_CHUNK_MACRO(RESET_LIST, "ID3D12GraphicsCommandList::Reset") \
\
D3D12_CHUNK_MACRO(RESOURCE_BARRIER, "ID3D12GraphicsCommandList::ResourceBarrier") \
\
D3D12_CHUNK_MACRO(DRAW_INDEXED_INST, "ID3D12GraphicsCommandList::DrawIndexedInstanced") \
D3D12_CHUNK_MACRO(COPY_BUFFER, "ID3D12GraphicsCommandList::CopyBufferRegion") \
\
D3D12_CHUNK_MACRO(CLEAR_RTV, "ID3D12GraphicsCommandList::ClearRenderTargetView") \
\
D3D12_CHUNK_MACRO(SET_TOPOLOGY, "ID3D12GraphicsCommandList::IASetPrimitiveTopology") \
D3D12_CHUNK_MACRO(SET_IBUFFER, "ID3D12GraphicsCommandList::IASetIndexBuffer") \
D3D12_CHUNK_MACRO(SET_VBUFFERS, "ID3D12GraphicsCommandList::IASetVertexBuffers") \
D3D12_CHUNK_MACRO(SET_VIEWPORTS, "ID3D12GraphicsCommandList::RSSetViewports") \
D3D12_CHUNK_MACRO(SET_SCISSORS, "ID3D12GraphicsCommandList::RSSetScissors") \
D3D12_CHUNK_MACRO(SET_PIPE, "ID3D12GraphicsCommandList::SetPipelineState") \
D3D12_CHUNK_MACRO(SET_RTVS, "ID3D12GraphicsCommandList::OMSetRenderTargets") \
D3D12_CHUNK_MACRO(SET_ROOT_SIG, "ID3D12GraphicsCommandList::SetRootSignature") \
D3D12_CHUNK_MACRO(SET_GFX_ROOT_CBV, \
"ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView") \
\
D3D12_CHUNK_MACRO(EXECUTE_CMD_LISTS, "ID3D12GraphicsCommandQueue::ExecuteCommandLists") \
D3D12_CHUNK_MACRO(SIGNAL, "ID3D12GraphicsCommandQueue::Signal") \
\
#define D3D12_CHUNKS \
D3D12_CHUNK_MACRO(DEVICE_INIT = FIRST_CHUNK_ID, "ID3D12Device::Initialisation") \
D3D12_CHUNK_MACRO(SET_RESOURCE_NAME, "ID3D12Object::SetName") \
D3D12_CHUNK_MACRO(RELEASE_RESOURCE, "IUnknown::Release") \
D3D12_CHUNK_MACRO(CREATE_SWAP_BUFFER, "IDXGISwapChain::GetBuffer") \
\
D3D12_CHUNK_MACRO(CAPTURE_SCOPE, "Capture") \
\
D3D12_CHUNK_MACRO(PUSH_EVENT, "BeginEvent") \
D3D12_CHUNK_MACRO(SET_MARKER, "SetMarker") \
D3D12_CHUNK_MACRO(POP_EVENT, "EndEvent") \
\
D3D12_CHUNK_MACRO(DEBUG_MESSAGES, "DebugMessageList") \
\
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_HEADER, "ContextBegin") \
D3D12_CHUNK_MACRO(CONTEXT_CAPTURE_FOOTER, "ContextEnd") \
\
D3D12_CHUNK_MACRO(SET_SHADER_DEBUG_PATH, "SetShaderDebugPath") \
\
D3D12_CHUNK_MACRO(CREATE_COMMAND_QUEUE, "ID3D12Device::CreateCommandQueue") \
D3D12_CHUNK_MACRO(CREATE_COMMAND_ALLOCATOR, "ID3D12Device::CreateCommandAllocator") \
D3D12_CHUNK_MACRO(CREATE_COMMAND_LIST, "ID3D12Device::CreateCommandList") \
\
D3D12_CHUNK_MACRO(CREATE_GRAPHICS_PIPE, "ID3D12Device::CreateGraphicsPipeline") \
D3D12_CHUNK_MACRO(CREATE_COMPUTE_PIPE, "ID3D12Device::CreateComputePipeline") \
D3D12_CHUNK_MACRO(CREATE_DESCRIPTOR_HEAP, "ID3D12Device::CreateDescriptorHeap") \
D3D12_CHUNK_MACRO(CREATE_ROOT_SIG, "ID3D12Device::CreateRootSignature") \
\
D3D12_CHUNK_MACRO(CREATE_COMMITTED_RESOURCE, "ID3D12Device::CreateCommittedResource") \
\
D3D12_CHUNK_MACRO(CREATE_FENCE, "ID3D12Device::CreateFence") \
\
D3D12_CHUNK_MACRO(CLOSE_LIST, "ID3D12GraphicsCommandList::Close") \
D3D12_CHUNK_MACRO(RESET_LIST, "ID3D12GraphicsCommandList::Reset") \
\
D3D12_CHUNK_MACRO(RESOURCE_BARRIER, "ID3D12GraphicsCommandList::ResourceBarrier") \
\
D3D12_CHUNK_MACRO(DRAW_INDEXED_INST, "ID3D12GraphicsCommandList::DrawIndexedInstanced") \
D3D12_CHUNK_MACRO(COPY_BUFFER, "ID3D12GraphicsCommandList::CopyBufferRegion") \
\
D3D12_CHUNK_MACRO(CLEAR_RTV, "ID3D12GraphicsCommandList::ClearRenderTargetView") \
\
D3D12_CHUNK_MACRO(SET_TOPOLOGY, "ID3D12GraphicsCommandList::IASetPrimitiveTopology") \
D3D12_CHUNK_MACRO(SET_IBUFFER, "ID3D12GraphicsCommandList::IASetIndexBuffer") \
D3D12_CHUNK_MACRO(SET_VBUFFERS, "ID3D12GraphicsCommandList::IASetVertexBuffers") \
D3D12_CHUNK_MACRO(SET_VIEWPORTS, "ID3D12GraphicsCommandList::RSSetViewports") \
D3D12_CHUNK_MACRO(SET_SCISSORS, "ID3D12GraphicsCommandList::RSSetScissors") \
D3D12_CHUNK_MACRO(SET_PIPE, "ID3D12GraphicsCommandList::SetPipelineState") \
D3D12_CHUNK_MACRO(SET_RTVS, "ID3D12GraphicsCommandList::OMSetRenderTargets") \
D3D12_CHUNK_MACRO(SET_GFX_ROOT_SIG, "ID3D12GraphicsCommandList::SetGraphicsRootSignature") \
D3D12_CHUNK_MACRO(SET_GFX_ROOT_CBV, \
"ID3D12GraphicsCommandList::SetGraphicsRootConstantBufferView") \
\
D3D12_CHUNK_MACRO(EXECUTE_CMD_LISTS, "ID3D12GraphicsCommandQueue::ExecuteCommandLists") \
D3D12_CHUNK_MACRO(SIGNAL, "ID3D12GraphicsCommandQueue::Signal") \
\
D3D12_CHUNK_MACRO(NUM_D3D12_CHUNKS, "")
enum D3D12ChunkType
+381
View File
@@ -0,0 +1,381 @@
/******************************************************************************
* 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_debug.h"
#include "d3d12_command_queue.h"
#include "d3d12_device.h"
D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper)
{
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->RegisterMemoryRegion(this, sizeof(D3D12DebugManager));
m_Device = wrapper->GetReal();
m_ResourceManager = wrapper->GetResourceManager();
m_OutputWindowID = 1;
m_WrappedDevice = wrapper;
m_WrappedDevice->InternalRef();
RenderDoc::Inst().SetProgress(DebugManagerInit, 0.0f);
m_pFactory = NULL;
HRESULT hr = S_OK;
IDXGIDevice *pDXGIDevice;
hr = m_WrappedDevice->QueryInterface(__uuidof(IDXGIDevice), (void **)&pDXGIDevice);
if(FAILED(hr))
{
RDCERR("Couldn't get DXGI device from D3D device");
}
else
{
IDXGIAdapter *pDXGIAdapter;
hr = pDXGIDevice->GetParent(__uuidof(IDXGIAdapter), (void **)&pDXGIAdapter);
if(FAILED(hr))
{
RDCERR("Couldn't get DXGI adapter from DXGI device");
SAFE_RELEASE(pDXGIDevice);
}
else
{
hr = pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), (void **)&m_pFactory);
SAFE_RELEASE(pDXGIDevice);
SAFE_RELEASE(pDXGIAdapter);
if(FAILED(hr))
{
RDCERR("Couldn't get DXGI factory from DXGI adapter");
}
}
}
D3D12_DESCRIPTOR_HEAP_DESC desc;
desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
desc.NodeMask = 1;
desc.NumDescriptors = 1024;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
hr = m_WrappedDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap),
(void **)&rtvHeap);
if(FAILED(hr))
{
RDCERR("Couldn't create RTV descriptor heap!");
}
desc.NumDescriptors = 16;
desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_DSV;
hr = m_WrappedDevice->CreateDescriptorHeap(&desc, __uuidof(ID3D12DescriptorHeap),
(void **)&dsvHeap);
if(FAILED(hr))
{
RDCERR("Couldn't create DSV descriptor heap!");
}
RenderDoc::Inst().SetProgress(DebugManagerInit, 1.0f);
}
D3D12DebugManager::~D3D12DebugManager()
{
SAFE_RELEASE(m_pFactory);
m_WrappedDevice->InternalRelease();
if(RenderDoc::Inst().GetCrashHandler())
RenderDoc::Inst().GetCrashHandler()->UnregisterMemoryRegion(this);
}
void D3D12DebugManager::OutputWindow::MakeDSV()
{
SAFE_RELEASE(depth);
D3D12_RESOURCE_DESC texDesc = bb->GetDesc();
texDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
texDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL;
D3D12_HEAP_PROPERTIES heapProps;
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
heapProps.CreationNodeMask = 1;
heapProps.VisibleNodeMask = 1;
HRESULT hr = dev->CreateCommittedResource(
&heapProps, D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES, &texDesc,
D3D12_RESOURCE_STATE_DEPTH_WRITE | D3D12_RESOURCE_STATE_DEPTH_READ, NULL,
__uuidof(ID3D12Resource), (void **)&depth);
if(FAILED(hr))
{
RDCERR("Failed to create DSV texture for main output, HRESULT: 0x%08x", hr);
return;
}
dev->CreateDepthStencilView(depth, NULL, dsv);
if(FAILED(hr))
{
RDCERR("Failed to create DSV for main output, HRESULT: 0x%08x", hr);
SAFE_RELEASE(swap);
SAFE_RELEASE(depth);
SAFE_RELEASE(bb);
return;
}
}
uint64_t D3D12DebugManager::MakeOutputWindow(void *w, bool depth)
{
OutputWindow outw;
outw.wnd = (HWND)w;
outw.dev = m_WrappedDevice;
DXGI_SWAP_CHAIN_DESC swapDesc;
RDCEraseEl(swapDesc);
RECT rect;
GetClientRect(outw.wnd, &rect);
swapDesc.BufferCount = 2;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
outw.width = swapDesc.BufferDesc.Width = rect.right - rect.left;
outw.height = swapDesc.BufferDesc.Height = rect.bottom - rect.top;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.SampleDesc.Count = depth ? 4 : 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.OutputWindow = outw.wnd;
swapDesc.Windowed = TRUE;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Flags = 0;
HRESULT hr = S_OK;
hr = m_pFactory->CreateSwapChain(m_WrappedDevice->GetQueue()->GetReal(), &swapDesc, &outw.swap);
if(FAILED(hr))
{
RDCERR("Failed to create swap chain for HWND, HRESULT: 0x%08x", hr);
return 0;
}
outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb);
outw.rtv = rtvHeap->GetCPUDescriptorHandleForHeapStart();
outw.rtv.ptr += m_OutputWindowID *
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
outw.dsv = dsvHeap->GetCPUDescriptorHandleForHeapStart();
outw.dsv.ptr += m_OutputWindowID *
m_WrappedDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_DSV);
m_WrappedDevice->CreateRenderTargetView(outw.bb, NULL, outw.rtv);
outw.depth = NULL;
if(depth)
outw.MakeDSV();
uint64_t id = m_OutputWindowID++;
m_OutputWindows[id] = outw;
return id;
}
void D3D12DebugManager::DestroyOutputWindow(uint64_t id)
{
auto it = m_OutputWindows.find(id);
if(id == 0 || it == m_OutputWindows.end())
return;
OutputWindow &outw = it->second;
SAFE_RELEASE(outw.swap);
SAFE_RELEASE(outw.bb);
SAFE_RELEASE(outw.depth);
m_OutputWindows.erase(it);
}
bool D3D12DebugManager::CheckResizeOutputWindow(uint64_t id)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return false;
OutputWindow &outw = m_OutputWindows[id];
if(outw.wnd == NULL || outw.swap == NULL)
return false;
RECT rect;
GetClientRect(outw.wnd, &rect);
long w = rect.right - rect.left;
long h = rect.bottom - rect.top;
if(w != outw.width || h != outw.height)
{
outw.width = w;
outw.height = h;
m_WrappedDevice->GPUSync();
if(outw.width > 0 && outw.height > 0)
{
SAFE_RELEASE(outw.bb);
DXGI_SWAP_CHAIN_DESC desc;
outw.swap->GetDesc(&desc);
HRESULT hr = outw.swap->ResizeBuffers(desc.BufferCount, outw.width, outw.height,
desc.BufferDesc.Format, desc.Flags);
if(FAILED(hr))
{
RDCERR("Failed to resize swap chain, HRESULT: 0x%08x", hr);
return true;
}
outw.swap->GetBuffer(0, __uuidof(ID3D12Resource), (void **)&outw.bb);
m_WrappedDevice->CreateRenderTargetView(outw.bb, NULL, outw.rtv);
if(outw.depth)
outw.MakeDSV();
}
return true;
}
return false;
}
void D3D12DebugManager::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
w = m_OutputWindows[id].width;
h = m_OutputWindows[id].height;
}
void D3D12DebugManager::ClearOutputWindowColour(uint64_t id, float col[4])
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
m_WrappedDevice->GetList()->ClearRenderTargetView(Unwrap(m_OutputWindows[id].rtv), col, 0, NULL);
m_WrappedDevice->GetList()->Close();
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
}
void D3D12DebugManager::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
m_WrappedDevice->GetList()->ClearDepthStencilView(
Unwrap(m_OutputWindows[id].dsv), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, depth,
stencil, 0, NULL);
m_WrappedDevice->GetList()->Close();
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
}
void D3D12DebugManager::BindOutputWindow(uint64_t id, bool depth)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
OutputWindow &outw = m_OutputWindows[id];
if(outw.bb == NULL)
return;
m_width = (int32_t)outw.width;
m_height = (int32_t)outw.height;
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = Unwrap(m_OutputWindows[id].bb);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
m_WrappedDevice->GetList()->ResourceBarrier(1, &barrier);
m_WrappedDevice->GetList()->Close();
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
}
bool D3D12DebugManager::IsOutputWindowVisible(uint64_t id)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return false;
return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE);
}
void D3D12DebugManager::FlipOutputWindow(uint64_t id)
{
if(id == 0 || m_OutputWindows.find(id) == m_OutputWindows.end())
return;
if(m_OutputWindows[id].swap)
{
D3D12_RESOURCE_BARRIER barrier;
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = Unwrap(m_OutputWindows[id].bb);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
m_WrappedDevice->GetList()->Reset(m_WrappedDevice->GetAlloc(), NULL);
m_WrappedDevice->GetList()->ResourceBarrier(1, &barrier);
m_WrappedDevice->GetList()->Close();
ID3D12CommandList *list = (ID3D12CommandList *)m_WrappedDevice->GetList();
m_WrappedDevice->GetQueue()->GetReal()->ExecuteCommandLists(1, &list);
m_OutputWindows[id].swap->Present(0, 0);
}
}
+89
View File
@@ -0,0 +1,89 @@
/******************************************************************************
* 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 "api/replay/renderdoc_replay.h"
#include "core/core.h"
#include "replay/replay_driver.h"
#include "d3d12_common.h"
class WrappedID3D12Device;
class D3D12ResourceManager;
class D3D12DebugManager
{
public:
D3D12DebugManager(WrappedID3D12Device *wrapper);
~D3D12DebugManager();
uint64_t MakeOutputWindow(void *w, bool depth);
void DestroyOutputWindow(uint64_t id);
bool CheckResizeOutputWindow(uint64_t id);
void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h);
void ClearOutputWindowColour(uint64_t id, float col[4]);
void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil);
void BindOutputWindow(uint64_t id, bool depth);
bool IsOutputWindowVisible(uint64_t id);
void FlipOutputWindow(uint64_t id);
void SetOutputDimensions(int w, int h)
{
m_width = w;
m_height = h;
}
int GetWidth() { return m_width; }
int GetHeight() { return m_height; }
private:
struct OutputWindow
{
HWND wnd;
IDXGISwapChain *swap;
ID3D12Resource *bb;
ID3D12Resource *depth;
D3D12_CPU_DESCRIPTOR_HANDLE rtv;
D3D12_CPU_DESCRIPTOR_HANDLE dsv;
WrappedID3D12Device *dev;
void MakeDSV();
int width, height;
};
ID3D12DescriptorHeap *rtvHeap;
ID3D12DescriptorHeap *dsvHeap;
int m_width, m_height;
uint64_t m_OutputWindowID;
map<uint64_t, OutputWindow> m_OutputWindows;
WrappedID3D12Device *m_WrappedDevice;
ID3D12Device *m_Device;
IDXGIFactory *m_pFactory;
D3D12ResourceManager *m_ResourceManager;
};
+229 -28
View File
@@ -557,6 +557,8 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap,
return tex;
}
LazyInit();
ID3D12Resource *pRes = new WrappedID3D12Resource((ID3D12Resource *)realSurface, this);
ResourceId id = GetResID(pRes);
@@ -803,6 +805,27 @@ HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInte
return S_OK;
}
void WrappedID3D12Device::Serialise_CaptureScope(uint64_t offset)
{
uint32_t FrameNumber = m_FrameCounter;
m_pSerialiser->Serialise("FrameNumber", FrameNumber);
if(m_State >= WRITING)
{
GetResourceManager()->Serialise_InitialContentsNeeded();
}
else
{
m_FrameRecord.frameInfo.fileOffset = offset;
m_FrameRecord.frameInfo.firstEvent = 1;
m_FrameRecord.frameInfo.frameNumber = FrameNumber;
m_FrameRecord.frameInfo.immContextId = ResourceId();
RDCEraseEl(m_FrameRecord.frameInfo.stats);
GetResourceManager()->CreateInitialContents();
}
}
bool WrappedID3D12Device::Serialise_BeginCaptureFrame(bool applyInitialState)
{
if(m_State < WRITING && !applyInitialState)
@@ -828,27 +851,6 @@ bool WrappedID3D12Device::Serialise_BeginCaptureFrame(bool applyInitialState)
return true;
}
void WrappedID3D12Device::Serialise_CaptureScope(uint64_t offset)
{
uint32_t FrameNumber = m_FrameCounter;
m_pSerialiser->Serialise("FrameNumber", FrameNumber);
if(m_State >= WRITING)
{
GetResourceManager()->Serialise_InitialContentsNeeded();
}
else
{
m_FrameRecord.frameInfo.fileOffset = offset;
m_FrameRecord.frameInfo.firstEvent = 1;
m_FrameRecord.frameInfo.frameNumber = FrameNumber;
m_FrameRecord.frameInfo.immContextId = ResourceId();
RDCEraseEl(m_FrameRecord.frameInfo.stats);
GetResourceManager()->CreateInitialContents();
}
}
void WrappedID3D12Device::EndCaptureFrame(ID3D12Resource *presentImage)
{
SCOPED_SERIALISE_CONTEXT(CONTEXT_CAPTURE_FOOTER);
@@ -972,9 +974,7 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd)
m_State = WRITING_IDLE;
// TODO wait for idle
// TODO free coherent map capture ref-data
GPUSync();
}
byte *thpixels = NULL;
@@ -1238,10 +1238,211 @@ void WrappedID3D12Device::GPUSync()
WaitForSingleObject(m_GPUSyncHandle, 2000);
}
// need to create this dummy here so that we can record D3D12.
ReplayCreateStatus D3D12_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
void WrappedID3D12Device::SetLogFile(const char *logfile)
{
return eReplayCreate_APIUnsupported;
m_pSerialiser = new Serialiser(logfile, Serialiser::READING, false);
m_pSerialiser->SetChunkNameLookup(&GetChunkName);
SAFE_DELETE(m_ResourceManager);
m_ResourceManager = new D3D12ResourceManager(m_State, m_pSerialiser, this);
}
static DriverRegistration D3D12DriverRegistration(RDC_D3D12, "D3D12", &D3D12_CreateReplayDevice);
void WrappedID3D12Device::LazyInit()
{
m_DebugManager = new D3D12DebugManager(this);
}
const FetchDrawcall *WrappedID3D12Device::GetDrawcall(uint32_t eventID)
{
if(eventID >= m_Drawcalls.size())
return NULL;
return m_Drawcalls[eventID];
}
void WrappedID3D12Device::ProcessChunk(uint64_t offset, D3D12ChunkType context)
{
switch(context)
{
case DEVICE_INIT: { break;
}
case CREATE_COMMAND_QUEUE: Serialise_CreateCommandQueue(NULL, IID(), NULL); break;
case CREATE_COMMAND_ALLOCATOR:
Serialise_CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID(), NULL);
break;
case CREATE_COMMAND_LIST:
Serialise_CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, NULL, NULL, IID(), NULL);
break;
case CREATE_GRAPHICS_PIPE: Serialise_CreateGraphicsPipelineState(NULL, IID(), NULL); break;
case CREATE_COMPUTE_PIPE: Serialise_CreateComputePipelineState(NULL, IID(), NULL); break;
case CREATE_DESCRIPTOR_HEAP: Serialise_CreateDescriptorHeap(NULL, IID(), NULL); break;
case CREATE_ROOT_SIG: Serialise_CreateRootSignature(0, NULL, 0, IID(), NULL); break;
case CREATE_COMMITTED_RESOURCE:
Serialise_CreateCommittedResource(NULL, D3D12_HEAP_FLAG_NONE, NULL,
D3D12_RESOURCE_STATE_COMMON, NULL, IID(), NULL);
break;
case CREATE_FENCE: Serialise_CreateFence(0, D3D12_FENCE_FLAG_NONE, IID(), NULL); break;
case SET_RESOURCE_NAME: Serialise_SetResourceName(0x0, ""); break;
case SET_SHADER_DEBUG_PATH: Serialise_SetShaderDebugPath(NULL, NULL); break;
case RELEASE_RESOURCE: Serialise_ReleaseResource(0x0); break;
case CREATE_SWAP_BUFFER: Serialise_WrapSwapchainBuffer(NULL, NULL, 0, NULL); break;
case CAPTURE_SCOPE: Serialise_CaptureScope(offset); break;
default:
// ignore system chunks
if(context == INITIAL_CONTENTS)
GetResourceManager()->Serialise_InitialState(ResourceId(), NULL);
else if(context < FIRST_CHUNK_ID)
m_pSerialiser->SkipCurrentChunk();
else
RDCERR("Unexpected non-device chunk %d at offset %llu", context, offset);
break;
}
}
void WrappedID3D12Device::ReadLogInitialisation()
{
uint64_t frameOffset = 0;
m_pSerialiser->SetDebugText(true);
m_pSerialiser->Rewind();
int chunkIdx = 0;
struct chunkinfo
{
chunkinfo() : count(0), totalsize(0), total(0.0) {}
int count;
uint64_t totalsize;
double total;
};
map<D3D12ChunkType, chunkinfo> chunkInfos;
SCOPED_TIMER("chunk initialisation");
for(;;)
{
PerformanceTimer timer;
uint64_t offset = m_pSerialiser->GetOffset();
D3D12ChunkType context = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
if(context == CAPTURE_SCOPE)
{
// immediately read rest of log into memory
m_pSerialiser->SetPersistentBlock(offset);
}
chunkIdx++;
ProcessChunk(offset, context);
m_pSerialiser->PopContext(context);
RenderDoc::Inst().SetProgress(FileInitialRead, float(offset) / float(m_pSerialiser->GetSize()));
if(context == CAPTURE_SCOPE)
{
frameOffset = offset;
GetResourceManager()->ApplyInitialContents();
m_Queue->ReplayLog(READING, 0, 0, false);
}
uint64_t offset2 = m_pSerialiser->GetOffset();
chunkInfos[context].total += timer.GetMilliseconds();
chunkInfos[context].totalsize += offset2 - offset;
chunkInfos[context].count++;
if(context == CAPTURE_SCOPE)
break;
if(m_pSerialiser->AtEnd())
break;
}
if(m_State == READING)
{
GetFrameRecord().drawcallList = m_Queue->GetParentDrawcall().Bake();
m_Queue->GetParentDrawcall().children.clear();
SetupDrawcallPointers(&m_Drawcalls, m_FrameRecord.frameInfo.immContextId,
m_FrameRecord.drawcallList, NULL, NULL);
}
#if !defined(RELEASE)
for(auto it = chunkInfos.begin(); it != chunkInfos.end(); ++it)
{
double dcount = double(it->second.count);
RDCDEBUG(
"% 5d chunks - Time: %9.3fms total/%9.3fms avg - Size: %8.3fMB total/%7.3fMB avg - %s (%u)",
it->second.count, it->second.total, it->second.total / dcount,
double(it->second.totalsize) / (1024.0 * 1024.0),
double(it->second.totalsize) / (dcount * 1024.0 * 1024.0), GetChunkName(it->first),
uint32_t(it->first));
}
#endif
m_FrameRecord.frameInfo.fileSize = m_pSerialiser->GetSize();
m_FrameRecord.frameInfo.persistentSize = m_pSerialiser->GetSize() - frameOffset;
m_FrameRecord.frameInfo.initDataSize = chunkInfos[(D3D12ChunkType)INITIAL_CONTENTS].totalsize;
RDCDEBUG("Allocating %llu persistant bytes of memory for the log.",
m_pSerialiser->GetSize() - frameOffset);
m_pSerialiser->SetDebugText(false);
}
void WrappedID3D12Device::ReplayLog(uint32_t startEventID, uint32_t endEventID,
ReplayLogType replayType)
{
uint64_t offs = m_FrameRecord.frameInfo.fileOffset;
m_pSerialiser->SetOffset(offs);
bool partial = true;
if(startEventID == 0 && (replayType == eReplay_WithoutDraw || replayType == eReplay_Full))
{
startEventID = m_FrameRecord.frameInfo.firstEvent;
partial = false;
}
D3D12ChunkType header = (D3D12ChunkType)m_pSerialiser->PushContext(NULL, NULL, 1, false);
RDCASSERTEQUAL(header, CAPTURE_SCOPE);
m_pSerialiser->SkipCurrentChunk();
m_pSerialiser->PopContext(header);
if(!partial)
{
GetResourceManager()->ApplyInitialContents();
GetResourceManager()->ReleaseInFrameResources();
GPUSync();
}
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");
}
+26 -1
View File
@@ -34,7 +34,9 @@
#include "driver/dxgi/dxgi_wrapped.h"
#include "replay/replay_driver.h"
#include "d3d12_common.h"
#include "d3d12_debug.h"
#include "d3d12_manager.h"
#include "d3d12_replay.h"
struct D3D12InitParams : public RDCInitParams
{
@@ -233,6 +235,13 @@ private:
DummyID3D12DebugDevice m_DummyDebug;
WrappedID3D12DebugDevice m_WrappedDebug;
D3D12Replay m_Replay;
D3D12DebugManager *m_DebugManager;
void LazyInit();
void ProcessChunk(uint64_t offset, D3D12ChunkType context);
unsigned int m_InternalRefcount;
RefCounter12<ID3D12Device> m_RefCounter;
RefCounter12<ID3D12Device> m_SoftRefCounter;
@@ -241,6 +250,7 @@ private:
uint32_t m_FrameCounter;
vector<FetchFrameInfo> m_CapturedFrames;
FetchFrameRecord m_FrameRecord;
vector<FetchDrawcall *> m_Drawcalls;
PerformanceTimer m_FrameTimer;
vector<double> m_FrameTimes;
@@ -284,7 +294,6 @@ private:
UINT m_DescriptorIncrements[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES];
void Serialise_CaptureScope(uint64_t offset);
bool Serialise_BeginCaptureFrame(bool applyInitialState);
void EndCaptureFrame(ID3D12Resource *presentImage);
public:
@@ -305,12 +314,23 @@ public:
ID3D12Device *GetReal() { return m_pDevice; }
static const char *GetChunkName(uint32_t idx);
D3D12ResourceManager *GetResourceManager() { return m_ResourceManager; }
D3D12DebugManager *GetDebugManager() { return m_DebugManager; }
Serialiser *GetSerialiser() { return m_pSerialiser; }
ResourceId GetResourceID() { return m_ResourceID; }
Threading::CriticalSection &GetCapTransitionLock() { return m_CapTransitionLock; }
void ReleaseSwapchainResources(IDXGISwapChain *swap, IUnknown **backbuffers, int numBackbuffers);
void FirstFrame(WrappedIDXGISwapChain3 *swap);
FetchFrameRecord GetFrameRecord() { return m_FrameRecord; }
const FetchDrawcall *GetDrawcall(uint32_t eventID);
void SetLogFile(const char *logfile);
void SetLogVersion(uint32_t fileversion)
{
LazyInit();
m_InitParams.SerialiseVersion = fileversion;
}
D3D12Replay *GetReplay() { return &m_Replay; }
WrappedID3D12CommandQueue *GetQueue() { return m_Queue; }
ID3D12CommandAllocator *GetAlloc() { return m_Alloc; }
ID3D12GraphicsCommandList *GetList() { return m_List; }
@@ -320,6 +340,11 @@ public:
void StartFrameCapture(void *dev, void *wnd);
bool EndFrameCapture(void *dev, void *wnd);
bool Serialise_BeginCaptureFrame(bool applyInitialState);
void ReadLogInitialisation();
void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType);
// interface for DXGI
virtual IUnknown *GetRealIUnknown() { return GetReal(); }
virtual IID GetBackbufferUUID() { return __uuidof(ID3D12Resource); }
+2 -1
View File
@@ -297,6 +297,8 @@ public:
void SerialiseResourceStates(vector<D3D12_RESOURCE_BARRIER> &barriers,
map<ResourceId, SubresourceStateVector> &states);
bool Serialise_InitialState(ResourceId resid, ID3D12DeviceChild *res);
private:
bool SerialisableResource(ResourceId id, D3D12ResourceRecord *record);
ResourceId GetID(ID3D12DeviceChild *res);
@@ -306,7 +308,6 @@ private:
bool Force_InitialState(ID3D12DeviceChild *res);
bool Need_InitialStateChunk(ID3D12DeviceChild *res);
bool Prepare_InitialState(ID3D12DeviceChild *res);
bool Serialise_InitialState(ResourceId resid, ID3D12DeviceChild *res);
void Create_InitialState(ResourceId id, ID3D12DeviceChild *live, bool hasData);
void Apply_InitialState(ID3D12DeviceChild *live, InitialContentData data);
+465
View File
@@ -0,0 +1,465 @@
/******************************************************************************
* 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_replay.h"
#include "d3d12_device.h"
D3D12Replay::D3D12Replay()
{
m_pDevice = NULL;
m_Proxy = false;
}
void D3D12Replay::Shutdown()
{
for(size_t i = 0; i < m_ProxyResources.size(); i++)
m_ProxyResources[i]->Release();
m_ProxyResources.clear();
m_pDevice->Release();
}
FetchTexture D3D12Replay::GetTexture(ResourceId id)
{
FetchTexture tex;
tex.ID = ResourceId();
return tex;
}
ShaderReflection *D3D12Replay::GetShader(ResourceId shader, string entryPoint)
{
return NULL;
}
void D3D12Replay::FreeTargetResource(ResourceId id)
{
if(m_pDevice->GetResourceManager()->HasLiveResource(id))
{
ID3D12DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id);
SAFE_RELEASE(resource);
}
}
void D3D12Replay::FreeCustomShader(ResourceId id)
{
if(m_pDevice->GetResourceManager()->HasLiveResource(id))
{
ID3D12DeviceChild *resource = m_pDevice->GetResourceManager()->GetLiveResource(id);
SAFE_RELEASE(resource);
}
}
FetchFrameRecord D3D12Replay::GetFrameRecord()
{
return m_pDevice->GetFrameRecord();
}
vector<EventUsage> D3D12Replay::GetUsage(ResourceId id)
{
return vector<EventUsage>();
}
vector<DebugMessage> D3D12Replay::GetDebugMessages()
{
return vector<DebugMessage>();
}
APIProperties D3D12Replay::GetAPIProperties()
{
APIProperties ret;
ret.pipelineType = ePipelineState_D3D11;
ret.degraded = false;
return ret;
}
vector<ResourceId> D3D12Replay::GetBuffers()
{
vector<ResourceId> ret;
return ret;
}
FetchBuffer D3D12Replay::GetBuffer(ResourceId id)
{
FetchBuffer ret;
ret.ID = ResourceId();
return ret;
}
vector<ResourceId> D3D12Replay::GetTextures()
{
vector<ResourceId> ret;
return ret;
}
D3D11PipelineState D3D12Replay::MakePipelineState()
{
D3D11PipelineState ret;
return ret;
}
void D3D12Replay::ReadLogInitialisation()
{
m_pDevice->ReadLogInitialisation();
}
void D3D12Replay::SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv)
{
RDCERR("Should never hit SetContextFilter");
}
void D3D12Replay::ReplayLog(uint32_t endEventID, ReplayLogType replayType)
{
m_pDevice->ReplayLog(0, endEventID, replayType);
}
vector<uint32_t> D3D12Replay::GetPassEvents(uint32_t eventID)
{
vector<uint32_t> passEvents;
return passEvents;
}
uint64_t D3D12Replay::MakeOutputWindow(void *w, bool depth)
{
return m_pDevice->GetDebugManager()->MakeOutputWindow(w, depth);
}
void D3D12Replay::DestroyOutputWindow(uint64_t id)
{
m_pDevice->GetDebugManager()->DestroyOutputWindow(id);
}
bool D3D12Replay::CheckResizeOutputWindow(uint64_t id)
{
return m_pDevice->GetDebugManager()->CheckResizeOutputWindow(id);
}
void D3D12Replay::GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h)
{
m_pDevice->GetDebugManager()->GetOutputWindowDimensions(id, w, h);
}
void D3D12Replay::ClearOutputWindowColour(uint64_t id, float col[4])
{
m_pDevice->GetDebugManager()->ClearOutputWindowColour(id, col);
}
void D3D12Replay::ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil)
{
m_pDevice->GetDebugManager()->ClearOutputWindowDepth(id, depth, stencil);
}
void D3D12Replay::BindOutputWindow(uint64_t id, bool depth)
{
m_pDevice->GetDebugManager()->BindOutputWindow(id, depth);
}
bool D3D12Replay::IsOutputWindowVisible(uint64_t id)
{
return m_pDevice->GetDebugManager()->IsOutputWindowVisible(id);
}
void D3D12Replay::FlipOutputWindow(uint64_t id)
{
m_pDevice->GetDebugManager()->FlipOutputWindow(id);
}
void D3D12Replay::InitPostVSBuffers(uint32_t eventID)
{
}
void D3D12Replay::InitPostVSBuffers(const vector<uint32_t> &passEvents)
{
}
ResourceId D3D12Replay::GetLiveID(ResourceId id)
{
return m_pDevice->GetResourceManager()->GetLiveID(id);
}
bool D3D12Replay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
FormatComponentType typeHint, float *minval, float *maxval)
{
*minval = 0.0f;
*maxval = 1.0f;
return false;
}
bool D3D12Replay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
FormatComponentType typeHint, float minval, float maxval,
bool channels[4], vector<uint32_t> &histogram)
{
histogram.resize(256, 0);
return false;
}
MeshFormat D3D12Replay::GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage)
{
return MeshFormat();
}
void D3D12Replay::GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector<byte> &retData)
{
}
byte *D3D12Replay::GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm,
float blackPoint, float whitePoint, size_t &dataSize)
{
dataSize = 0;
return NULL;
}
void D3D12Replay::ReplaceResource(ResourceId from, ResourceId to)
{
m_pDevice->GetResourceManager()->ReplaceResource(from, to);
}
void D3D12Replay::RemoveReplacement(ResourceId id)
{
m_pDevice->GetResourceManager()->RemoveReplacement(id);
}
vector<uint32_t> D3D12Replay::EnumerateCounters()
{
return vector<uint32_t>();
}
void D3D12Replay::DescribeCounter(uint32_t counterID, CounterDescription &desc)
{
desc = CounterDescription();
}
vector<CounterResult> D3D12Replay::FetchCounters(const vector<uint32_t> &counters)
{
return vector<CounterResult>();
}
void D3D12Replay::RenderMesh(uint32_t eventID, const vector<MeshFormat> &secondaryDraws,
const MeshDisplay &cfg)
{
}
void D3D12Replay::BuildTargetShader(string source, string entry, const uint32_t compileFlags,
ShaderStageType type, ResourceId *id, string *errors)
{
}
void D3D12Replay::BuildCustomShader(string source, string entry, const uint32_t compileFlags,
ShaderStageType type, ResourceId *id, string *errors)
{
}
bool D3D12Replay::RenderTexture(TextureDisplay cfg)
{
return false;
}
void D3D12Replay::RenderCheckerboard(Vec3f light, Vec3f dark)
{
}
void D3D12Replay::RenderHighlightBox(float w, float h, float scale)
{
}
void D3D12Replay::FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
vector<ShaderVariable> &outvars, const vector<byte> &data)
{
return;
}
vector<PixelModification> D3D12Replay::PixelHistory(vector<EventUsage> events, ResourceId target,
uint32_t x, uint32_t y, uint32_t slice,
uint32_t mip, uint32_t sampleIdx,
FormatComponentType typeHint)
{
return vector<PixelModification>();
}
ShaderDebugTrace D3D12Replay::DebugVertex(uint32_t eventID, uint32_t vertid, uint32_t instid,
uint32_t idx, uint32_t instOffset, uint32_t vertOffset)
{
return ShaderDebugTrace();
}
ShaderDebugTrace D3D12Replay::DebugPixel(uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive)
{
return ShaderDebugTrace();
}
ShaderDebugTrace D3D12Replay::DebugThread(uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3])
{
return ShaderDebugTrace();
}
uint32_t D3D12Replay::PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y)
{
return ~0U;
}
void D3D12Replay::PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace,
uint32_t mip, uint32_t sample, FormatComponentType typeHint,
float pixel[4])
{
}
ResourceId D3D12Replay::RenderOverlay(ResourceId texid, FormatComponentType typeHint,
TextureDisplayOverlay overlay, uint32_t eventID,
const vector<uint32_t> &passEvents)
{
return ResourceId();
}
ResourceId D3D12Replay::ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip,
FormatComponentType typeHint)
{
return ResourceId();
}
bool D3D12Replay::IsRenderOutput(ResourceId id)
{
return false;
}
void D3D12Replay::InitCallstackResolver()
{
m_pDevice->GetSerialiser()->InitCallstackResolver();
}
bool D3D12Replay::HasCallstacks()
{
return m_pDevice->GetSerialiser()->HasCallstacks();
}
Callstack::StackResolver *D3D12Replay::GetCallstackResolver()
{
return m_pDevice->GetSerialiser()->GetCallstackResolver();
}
ResourceId D3D12Replay::CreateProxyTexture(const FetchTexture &templateTex)
{
return ResourceId();
}
void D3D12Replay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data,
size_t dataSize)
{
}
ResourceId D3D12Replay::CreateProxyBuffer(const FetchBuffer &templateBuf)
{
return ResourceId();
}
void D3D12Replay::SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize)
{
}
extern "C" __declspec(dllexport) HRESULT
__cdecl RENDERDOC_CreateWrappedD3D12Device(IUnknown *pAdapter,
D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid,
void **ppDevice);
ReplayCreateStatus D3D12_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
{
RDCDEBUG("Creating a D3D12 replay device");
HMODULE lib = NULL;
lib = LoadLibraryA("d3d12.dll");
if(lib == NULL)
{
RDCERR("Failed to load d3d12.dll");
return eReplayCreate_APIInitFailed;
}
lib = LoadLibraryA("dxgi.dll");
if(lib == NULL)
{
RDCERR("Failed to load dxgi.dll");
return eReplayCreate_APIInitFailed;
}
if(GetD3DCompiler() == NULL)
{
RDCERR("Failed to load d3dcompiler_??.dll");
return eReplayCreate_APIInitFailed;
}
ID3D12Device *device = NULL;
D3D12InitParams initParams;
RDCDriver driverFileType = RDC_D3D12;
string driverName = "D3D12";
if(logfile)
{
auto status = RenderDoc::Inst().FillInitParams(logfile, driverFileType, driverName,
(RDCInitParams *)&initParams);
if(status != eReplayCreate_Success)
return status;
}
// initParams.SerialiseVersion is guaranteed to be valid/supported since otherwise the
// FillInitParams (which calls D3D12InitParams::Serialise) would have failed above, so no need to
// check it here.
if(initParams.MinimumFeatureLevel < D3D_FEATURE_LEVEL_11_0)
initParams.MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D12Device *dev = NULL;
HRESULT hr = RENDERDOC_CreateWrappedD3D12Device(NULL, initParams.MinimumFeatureLevel,
__uuidof(ID3D12Device), (void **)&dev);
if(FAILED(hr))
{
RDCERR("Couldn't create a d3d12 device :(.");
return eReplayCreate_APIHardwareUnsupported;
}
WrappedID3D12Device *wrappedDev = (WrappedID3D12Device *)device;
if(logfile)
wrappedDev->SetLogFile(logfile);
wrappedDev->SetLogVersion(initParams.SerialiseVersion);
RDCLOG("Created device.");
D3D12Replay *replay = wrappedDev->GetReplay();
replay->SetProxy(logfile == NULL);
*driver = (IReplayDriver *)replay;
return eReplayCreate_Success;
}
static DriverRegistration D3D12DriverRegistration(RDC_D3D12, "D3D12", &D3D12_CreateReplayDevice);
+164
View File
@@ -0,0 +1,164 @@
/******************************************************************************
* 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 "api/replay/renderdoc_replay.h"
#include "core/core.h"
#include "replay/replay_driver.h"
#include "d3d12_common.h"
class WrappedID3D12Device;
class D3D12Replay : public IReplayDriver
{
public:
D3D12Replay();
void SetProxy(bool proxy) { m_Proxy = proxy; }
bool IsRemoteProxy() { return m_Proxy; }
void Shutdown();
void SetDevice(WrappedID3D12Device *d) { m_pDevice = d; }
APIProperties GetAPIProperties();
vector<ResourceId> GetBuffers();
FetchBuffer GetBuffer(ResourceId id);
vector<ResourceId> GetTextures();
FetchTexture GetTexture(ResourceId id);
vector<DebugMessage> GetDebugMessages();
ShaderReflection *GetShader(ResourceId shader, string entryPoint);
vector<EventUsage> GetUsage(ResourceId id);
FetchFrameRecord GetFrameRecord();
void SavePipelineState() { MakePipelineState(); }
D3D11PipelineState GetD3D11PipelineState() { return D3D11PipelineState(); }
GLPipelineState GetGLPipelineState() { return GLPipelineState(); }
VulkanPipelineState GetVulkanPipelineState() { return VulkanPipelineState(); }
void FreeTargetResource(ResourceId id);
void FreeCustomShader(ResourceId id);
void ReadLogInitialisation();
void SetContextFilter(ResourceId id, uint32_t firstDefEv, uint32_t lastDefEv);
void ReplayLog(uint32_t endEventID, ReplayLogType replayType);
vector<uint32_t> GetPassEvents(uint32_t eventID);
uint64_t MakeOutputWindow(void *w, bool depth);
void DestroyOutputWindow(uint64_t id);
bool CheckResizeOutputWindow(uint64_t id);
void GetOutputWindowDimensions(uint64_t id, int32_t &w, int32_t &h);
void ClearOutputWindowColour(uint64_t id, float col[4]);
void ClearOutputWindowDepth(uint64_t id, float depth, uint8_t stencil);
void BindOutputWindow(uint64_t id, bool depth);
bool IsOutputWindowVisible(uint64_t id);
void FlipOutputWindow(uint64_t id);
void InitPostVSBuffers(uint32_t eventID);
void InitPostVSBuffers(const vector<uint32_t> &passEvents);
ResourceId GetLiveID(ResourceId id);
bool GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
FormatComponentType typeHint, float *minval, float *maxval);
bool GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample,
FormatComponentType typeHint, float minval, float maxval, bool channels[4],
vector<uint32_t> &histogram);
MeshFormat GetPostVSBuffers(uint32_t eventID, uint32_t instID, MeshDataStage stage);
void GetBufferData(ResourceId buff, uint64_t offset, uint64_t len, vector<byte> &retData);
byte *GetTextureData(ResourceId tex, uint32_t arrayIdx, uint32_t mip,
FormatComponentType typeHint, bool resolve, bool forceRGBA8unorm,
float blackPoint, float whitePoint, size_t &dataSize);
void BuildTargetShader(string source, string entry, const uint32_t compileFlags,
ShaderStageType type, ResourceId *id, string *errors);
void ReplaceResource(ResourceId from, ResourceId to);
void RemoveReplacement(ResourceId id);
vector<uint32_t> EnumerateCounters();
void DescribeCounter(uint32_t counterID, CounterDescription &desc);
vector<CounterResult> FetchCounters(const vector<uint32_t> &counters);
ResourceId CreateProxyTexture(const FetchTexture &templateTex);
void SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t mip, byte *data,
size_t dataSize);
ResourceId CreateProxyBuffer(const FetchBuffer &templateBuf);
void SetProxyBufferData(ResourceId bufid, byte *data, size_t dataSize);
void RenderMesh(uint32_t eventID, const vector<MeshFormat> &secondaryDraws, const MeshDisplay &cfg);
bool RenderTexture(TextureDisplay cfg);
void RenderCheckerboard(Vec3f light, Vec3f dark);
void RenderHighlightBox(float w, float h, float scale);
void FillCBufferVariables(ResourceId shader, string entryPoint, uint32_t cbufSlot,
vector<ShaderVariable> &outvars, const vector<byte> &data);
vector<PixelModification> PixelHistory(vector<EventUsage> events, ResourceId target, uint32_t x,
uint32_t y, uint32_t slice, uint32_t mip,
uint32_t sampleIdx, FormatComponentType typeHint);
ShaderDebugTrace DebugVertex(uint32_t eventID, uint32_t vertid, uint32_t instid, uint32_t idx,
uint32_t instOffset, uint32_t vertOffset);
ShaderDebugTrace DebugPixel(uint32_t eventID, uint32_t x, uint32_t y, uint32_t sample,
uint32_t primitive);
ShaderDebugTrace DebugThread(uint32_t eventID, uint32_t groupid[3], uint32_t threadid[3]);
void PickPixel(ResourceId texture, uint32_t x, uint32_t y, uint32_t sliceFace, uint32_t mip,
uint32_t sample, FormatComponentType typeHint, float pixel[4]);
uint32_t PickVertex(uint32_t eventID, const MeshDisplay &cfg, uint32_t x, uint32_t y);
ResourceId RenderOverlay(ResourceId texid, FormatComponentType typeHint,
TextureDisplayOverlay overlay, uint32_t eventID,
const vector<uint32_t> &passEvents);
void BuildCustomShader(string source, string entry, const uint32_t compileFlags,
ShaderStageType type, ResourceId *id, string *errors);
ResourceId ApplyCustomShader(ResourceId shader, ResourceId texid, uint32_t mip,
FormatComponentType typeHint);
bool IsRenderOutput(ResourceId id);
void FileChanged() {}
void InitCallstackResolver();
bool HasCallstacks();
Callstack::StackResolver *GetCallstackResolver();
private:
D3D11PipelineState MakePipelineState();
bool m_Proxy;
vector<ID3D12Resource *> m_ProxyResources;
WrappedID3D12Device *m_pDevice;
};
@@ -188,20 +188,24 @@
<ClCompile Include="d3d12_command_list_wrap.cpp" />
<ClCompile Include="d3d12_command_queue_wrap.cpp" />
<ClCompile Include="d3d12_common.cpp" />
<ClCompile Include="d3d12_debug.cpp" />
<ClCompile Include="d3d12_device.cpp" />
<ClCompile Include="d3d12_device_wrap.cpp" />
<ClCompile Include="d3d12_hooks.cpp" />
<ClCompile Include="d3d12_manager.cpp" />
<ClCompile Include="d3d12_replay.cpp" />
<ClCompile Include="d3d12_resources.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="d3d12_command_list.h" />
<ClInclude Include="d3d12_command_queue.h" />
<ClInclude Include="d3d12_common.h" />
<ClInclude Include="d3d12_debug.h" />
<ClInclude Include="d3d12_device.h" />
<ClInclude Include="d3d12_manager.h" />
<ClInclude Include="..\dx\official\d3d12.h" />
<ClInclude Include="..\dx\official\d3d12sdklayers.h" />
<ClInclude Include="d3d12_replay.h" />
<ClInclude Include="d3d12_resources.h" />
</ItemGroup>
<ItemGroup>
@@ -16,6 +16,9 @@
<Filter Include="Wrapped">
<UniqueIdentifier>{b66407e3-297a-4a8d-bdae-09468c64ca18}</UniqueIdentifier>
</Filter>
<Filter Include="Replay">
<UniqueIdentifier>{97a405db-4782-4c62-b6c1-ca6a398c6a60}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\dx\official\d3d12.h">
@@ -42,6 +45,12 @@
<ClInclude Include="d3d12_command_queue.h">
<Filter>Core IFaces</Filter>
</ClInclude>
<ClInclude Include="d3d12_replay.h">
<Filter>Replay</Filter>
</ClInclude>
<ClInclude Include="d3d12_debug.h">
<Filter>Replay</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="d3d12_common.cpp">
@@ -71,5 +80,11 @@
<ClCompile Include="d3d12_commands.cpp">
<Filter>Core IFaces</Filter>
</ClCompile>
<ClCompile Include="d3d12_replay.cpp">
<Filter>Replay</Filter>
</ClCompile>
<ClCompile Include="d3d12_debug.cpp">
<Filter>Replay</Filter>
</ClCompile>
</ItemGroup>
</Project>
-2
View File
@@ -1532,8 +1532,6 @@ void WrappedVulkan::ContextReplayLog(LogState readType, uint32_t startEventID, u
m_RootEvents.clear();
m_CmdBuffersInProgress = 0;
if(m_State == EXECUTING)
{
FetchAPIEvent ev = GetEvent(startEventID);
-1
View File
@@ -357,7 +357,6 @@ private:
// on replay, the current command buffer for the last chunk we
// handled.
ResourceId m_LastCmdBufferID;
int m_CmdBuffersInProgress;
// this is a list of uint64_t file offset -> uint32_t EIDs of where each
// drawcall is used. E.g. the drawcall at offset 873954 is EID 50. If a
@@ -311,7 +311,6 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(Serialiser *localSerialiser,
if(m_State < WRITING)
{
m_LastCmdBufferID = cmdId;
m_CmdBuffersInProgress++;
}
SERIALISE_ELEMENT(ResourceId, devId, GetResID(device));
@@ -509,7 +508,6 @@ bool WrappedVulkan::Serialise_vkEndCommandBuffer(Serialiser *localSerialiser,
if(m_State < WRITING)
{
m_LastCmdBufferID = cmdid;
m_CmdBuffersInProgress--;
}
if(m_State == EXECUTING)