Add support for tracking and saving mid-frame and persistent maps

This commit is contained in:
baldurk
2016-10-18 19:10:06 +02:00
parent 681eb21b0a
commit 2fe22e96b5
8 changed files with 439 additions and 30 deletions
@@ -439,7 +439,60 @@ void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists(
if(capframe)
{
// flush coherent maps
vector<MapState> maps = m_pDevice->GetMaps();
for(auto it = maps.begin(); it != maps.end(); ++it)
{
WrappedID3D12Resource *res = it->res;
UINT subres = it->subres;
size_t size = (size_t)it->totalSize;
// only need to flush memory that could affect this submitted batch of work
if(refdIDs.find(res->GetResourceID()) == refdIDs.end())
{
RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing",
res->GetResourceID());
continue;
}
size_t diffStart = 0, diffEnd = 0;
bool found = true;
byte *ref = res->GetShadow(subres);
byte *data = res->GetMap(subres);
if(ref)
found = FindDiffRange(data, ref, size, diffStart, diffEnd);
else
diffEnd = size;
if(found)
{
RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", res->GetResourceID(),
(uint64_t)diffStart, (uint64_t)diffEnd);
D3D12_RANGE range = {diffStart, diffEnd};
m_pDevice->MapDataWrite(res, subres, data, range);
if(ref == NULL)
{
res->AllocShadow(subres, size);
ref = res->GetShadow(subres);
}
// update comparison shadow for next time
memcpy(ref, res->GetMap(subres), size);
GetResourceManager()->MarkPendingDirty(res->GetResourceID());
}
else
{
RDCDEBUG("Persistent map flush not needed for %llu", res->GetResourceID());
}
}
for(UINT i = 0; i < NumCommandLists; i++)
{
SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS);
@@ -264,6 +264,13 @@ void WrappedID3D12CommandQueue::ProcessChunk(uint64_t offset, D3D12ChunkType chu
case RESOURCE_BARRIER: m_ReplayList->Serialise_ResourceBarrier(0, NULL); break;
case MAP_DATA_WRITE:
m_pDevice->Serialise_MapDataWrite(m_pSerialiser, NULL, 0, NULL, D3D12_RANGE());
break;
case WRITE_TO_SUB:
m_pDevice->Serialise_WriteToSubresource(m_pSerialiser, NULL, 0, NULL, NULL, 0, 0);
break;
case BEGIN_QUERY:
m_ReplayList->Serialise_BeginQuery(NULL, D3D12_QUERY_TYPE_OCCLUSION, 0);
break;
+3
View File
@@ -279,6 +279,9 @@ void Serialiser::Serialise(const char *name, D3D12Descriptor &el);
\
D3D12_CHUNK_MACRO(RESOURCE_BARRIER, "ID3D12GraphicsCommandList::ResourceBarrier") \
\
D3D12_CHUNK_MACRO(MAP_DATA_WRITE, "ID3D12Resource::Unmap") \
D3D12_CHUNK_MACRO(WRITE_TO_SUB, "ID3D12Resource::WriteToSubresource") \
\
D3D12_CHUNK_MACRO(BEGIN_QUERY, "ID3D12GraphicsCommandList::BeginQuery") \
D3D12_CHUNK_MACRO(END_QUERY, "ID3D12GraphicsCommandList::EndQuery") \
D3D12_CHUNK_MACRO(RESOLVE_QUERY, "ID3D12GraphicsCommandList::ResolveQueryData") \
+195
View File
@@ -702,6 +702,195 @@ IUnknown *WrappedID3D12Device::WrapSwapchainBuffer(WrappedIDXGISwapChain3 *swap,
return pRes;
}
void WrappedID3D12Device::Map(WrappedID3D12Resource *Resource, UINT Subresource)
{
MapState map;
map.res = Resource;
map.subres = Subresource;
D3D12_RESOURCE_DESC desc = Resource->GetDesc();
m_pDevice->GetCopyableFootprints(&desc, Subresource, 1, 0, NULL, NULL, NULL, &map.totalSize);
{
SCOPED_LOCK(m_MapsLock);
m_Maps.push_back(map);
}
}
void WrappedID3D12Device::Unmap(WrappedID3D12Resource *Resource, UINT Subresource, byte *mapPtr,
const D3D12_RANGE *pWrittenRange)
{
MapState map = {};
{
SCOPED_LOCK(m_MapsLock);
for(auto it = m_Maps.begin(); it != m_Maps.end(); ++it)
{
if(it->res == Resource && it->subres == Subresource)
{
map = *it;
m_Maps.erase(it);
break;
}
}
}
if(map.res == NULL)
return;
bool capframe = false;
{
SCOPED_LOCK(m_CapTransitionLock);
capframe = (m_State == WRITING_CAPFRAME);
}
D3D12_RANGE range = {0, (SIZE_T)map.totalSize};
if(pWrittenRange)
range = *pWrittenRange;
if(capframe)
MapDataWrite(Resource, Subresource, mapPtr, range);
}
bool WrappedID3D12Device::Serialise_MapDataWrite(Serialiser *localSerialiser,
WrappedID3D12Resource *Resource, UINT Subresource,
byte *mapPtr, D3D12_RANGE range)
{
SERIALISE_ELEMENT(ResourceId, res, GetResID(Resource));
SERIALISE_ELEMENT(UINT, sub, Subresource);
SERIALISE_ELEMENT_BUF(byte *, data, mapPtr, range.End - range.Begin);
SERIALISE_ELEMENT(uint64_t, begin, (uint64_t)range.Begin);
SERIALISE_ELEMENT(uint64_t, end, (uint64_t)range.End);
if(m_State < WRITING && GetResourceManager()->HasLiveResource(res))
{
ID3D12Resource *r = GetResourceManager()->GetLiveAs<ID3D12Resource>(res);
D3D12_RANGE range = {};
byte *mapPtr = NULL;
HRESULT hr = r->Map(sub, &range, (void **)&mapPtr);
if(SUCCEEDED(hr))
{
memcpy(mapPtr + begin, data, end - begin);
range.Begin = begin;
range.End = end;
r->Unmap(sub, &range);
}
else
{
RDCERR("Failed to map resource on replay %08x", hr);
}
SAFE_DELETE_ARRAY(data);
}
return true;
}
void WrappedID3D12Device::MapDataWrite(WrappedID3D12Resource *Resource, UINT Subresource,
byte *mapPtr, D3D12_RANGE range)
{
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CONTEXT(MAP_DATA_WRITE);
Serialise_MapDataWrite(localSerialiser, Resource, Subresource, mapPtr, range);
m_FrameCaptureRecord->AddChunk(scope.Get());
GetResourceManager()->MarkResourceFrameReferenced(Resource->GetResourceID(), eFrameRef_Write);
}
bool WrappedID3D12Device::Serialise_WriteToSubresource(Serialiser *localSerialiser,
WrappedID3D12Resource *Resource,
UINT Subresource, const D3D12_BOX *pDstBox,
const void *pSrcData, UINT SrcRowPitch,
UINT SrcDepthPitch)
{
SERIALISE_ELEMENT(ResourceId, res, GetResID(Resource));
SERIALISE_ELEMENT(UINT, sub, Subresource);
SERIALISE_ELEMENT(bool, HasBox, pDstBox != NULL);
SERIALISE_ELEMENT_OPT(D3D12_BOX, box, *pDstBox, HasBox);
SERIALISE_ELEMENT(UINT, rowPitch, SrcRowPitch);
SERIALISE_ELEMENT(UINT, depthPitch, SrcDepthPitch);
size_t dataSize = 0;
if(m_State >= WRITING)
{
// if we have a box, calculate how much data from user's pitch
if(HasBox)
{
UINT numSlicesBeforeLast = pDstBox->back - pDstBox->front - 1;
UINT numRows = pDstBox->bottom - pDstBox->top;
dataSize = depthPitch * numSlicesBeforeLast + rowPitch * numRows;
}
else
{
D3D12_RESOURCE_DESC desc = Resource->GetDesc();
UINT64 totalBytes = 0;
// otherwise fetch the whole resource size
m_pDevice->GetCopyableFootprints(&desc, sub, 1, 0, NULL, NULL, NULL, &totalBytes);
dataSize = (size_t)totalBytes;
}
}
SERIALISE_ELEMENT_BUF(byte *, data, pSrcData, dataSize);
if(m_State < WRITING && GetResourceManager()->HasLiveResource(res))
{
ID3D12Resource *r = GetResourceManager()->GetLiveAs<ID3D12Resource>(res);
HRESULT hr = r->Map(sub, NULL, NULL);
if(SUCCEEDED(hr))
{
r->WriteToSubresource(sub, HasBox ? &box : NULL, data, rowPitch, depthPitch);
r->Unmap(sub, NULL);
}
else
{
RDCERR("Failed to map resource on replay %08x", hr);
}
SAFE_DELETE_ARRAY(data);
}
return true;
}
void WrappedID3D12Device::WriteToSubresource(WrappedID3D12Resource *Resource, UINT Subresource,
const D3D12_BOX *pDstBox, const void *pSrcData,
UINT SrcRowPitch, UINT SrcDepthPitch)
{
bool capframe = false;
{
SCOPED_LOCK(m_CapTransitionLock);
capframe = (m_State == WRITING_CAPFRAME);
}
if(capframe)
{
CACHE_THREAD_SERIALISER();
SCOPED_SERIALISE_CONTEXT(WRITE_TO_SUB);
Serialise_WriteToSubresource(localSerialiser, Resource, Subresource, pDstBox, pSrcData,
SrcRowPitch, SrcDepthPitch);
m_FrameCaptureRecord->AddChunk(scope.Get());
GetResourceManager()->MarkResourceFrameReferenced(Resource->GetResourceID(), eFrameRef_Write);
}
}
HRESULT WrappedID3D12Device::Present(WrappedIDXGISwapChain3 *swap, UINT SyncInterval, UINT Flags)
{
if((Flags & DXGI_PRESENT_TEST) != 0)
@@ -980,6 +1169,12 @@ bool WrappedID3D12Device::EndFrameCapture(void *dev, void *wnd)
m_State = WRITING_IDLE;
GPUSync();
{
SCOPED_LOCK(m_MapsLock);
for(auto it = m_Maps.begin(); it != m_Maps.end(); ++it)
it->res->FreeShadow();
}
}
byte *thpixels = NULL;
+24
View File
@@ -52,6 +52,7 @@ struct D3D12InitParams : public RDCInitParams
};
class WrappedID3D12Device;
class WrappedID3D12Resource;
// give every impression of working but do nothing.
// Just allow the user to call functions so that they don't
@@ -242,6 +243,9 @@ private:
D3D12Replay m_Replay;
D3D12DebugManager *m_DebugManager;
Threading::CriticalSection m_MapsLock;
vector<MapState> m_Maps;
void ProcessChunk(uint64_t offset, D3D12ChunkType context);
unsigned int m_InternalRefcount;
@@ -423,6 +427,26 @@ public:
void NewSwapchainBuffer(IUnknown *backbuffer) {}
void ReleaseSwapchainResources(WrappedIDXGISwapChain3 *swap);
void Map(WrappedID3D12Resource *Resource, UINT Subresource);
void Unmap(WrappedID3D12Resource *Resource, UINT Subresource, byte *mapPtr,
const D3D12_RANGE *pWrittenRange);
IMPLEMENT_FUNCTION_THREAD_SERIALISED(void, MapDataWrite, WrappedID3D12Resource *Resource,
UINT Subresource, byte *mapPtr, D3D12_RANGE range);
IMPLEMENT_FUNCTION_THREAD_SERIALISED(void, WriteToSubresource, WrappedID3D12Resource *Resource,
UINT Subresource, const D3D12_BOX *pDstBox,
const void *pSrcData, UINT SrcRowPitch, UINT SrcDepthPitch);
vector<MapState> GetMaps()
{
vector<MapState> ret;
{
SCOPED_LOCK(m_MapsLock);
ret = m_Maps;
}
return ret;
}
void InternalRef() { InterlockedIncrement(&m_InternalRefcount); }
void InternalRelease() { InterlockedDecrement(&m_InternalRefcount); }
void SoftRef() { m_SoftRefCounter.AddRef(); }
+17
View File
@@ -279,6 +279,15 @@ struct CmdListRecordingInfo
vector<D3D12ResourceRecord *> bundles;
};
class WrappedID3D12Resource;
struct MapState
{
WrappedID3D12Resource *res;
UINT subres;
UINT64 totalSize;
};
struct D3D12ResourceRecord : public ResourceRecord
{
enum
@@ -322,6 +331,14 @@ struct D3D12ResourceRecord : public ResourceRecord
D3D12ResourceType type;
D3D12ResourceRecord *bakedCommands;
CmdListRecordingInfo *cmdInfo;
struct MapData
{
byte *realPtr;
byte *shadowPtr;
};
vector<MapData> m_Map;
};
typedef vector<D3D12_RESOURCE_STATES> SubresourceStateVector;
+122 -5
View File
@@ -29,6 +29,7 @@
std::vector<WrappedID3D12Resource::AddressRange> WrappedID3D12Resource::m_Addresses;
std::map<ResourceId, WrappedID3D12Resource *> WrappedID3D12Resource::m_List;
std::map<WrappedID3D12PipelineState::DXBCKey, WrappedID3D12PipelineState::ShaderEntry *>
WrappedID3D12PipelineState::m_Shaders;
@@ -169,7 +170,7 @@ D3D12ResourceType IdentifyTypeByPtr(ID3D12DeviceChild *ptr)
return Resource_Unknown;
}
TrackedResource *GetTracked(ID3D12DeviceChild *ptr)
TrackedResource12 *GetTracked(ID3D12DeviceChild *ptr)
{
if(ptr == NULL)
return NULL;
@@ -177,12 +178,12 @@ TrackedResource *GetTracked(ID3D12DeviceChild *ptr)
#undef D3D12_TYPE_MACRO
#define D3D12_TYPE_MACRO(iface) \
if(UnwrapHelper<iface>::IsAlloc(ptr)) \
return (TrackedResource *)GetWrapped((iface *)ptr);
return (TrackedResource12 *)GetWrapped((iface *)ptr);
ALL_D3D12_TYPES;
if(WrappedID3D12PipelineState::ShaderEntry::IsAlloc(ptr))
return (TrackedResource *)(WrappedID3D12PipelineState::ShaderEntry *)ptr;
return (TrackedResource12 *)(WrappedID3D12PipelineState::ShaderEntry *)ptr;
return NULL;
}
@@ -216,7 +217,7 @@ ResourceId GetResID(ID3D12DeviceChild *ptr)
if(ptr == NULL)
return ResourceId();
TrackedResource *res = GetTracked(ptr);
TrackedResource12 *res = GetTracked(ptr);
if(res == NULL)
{
@@ -239,7 +240,7 @@ D3D12ResourceRecord *GetRecord(ID3D12DeviceChild *ptr)
if(ptr == NULL)
return NULL;
TrackedResource *res = GetTracked(ptr);
TrackedResource12 *res = GetTracked(ptr);
if(res == NULL)
{
@@ -256,6 +257,122 @@ D3D12ResourceRecord *GetRecord(ID3D12DeviceChild *ptr)
return res->GetResourceRecord();
}
byte *WrappedID3D12Resource::GetMap(UINT Subresource)
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
if(Subresource < map.size())
return map[Subresource].realPtr;
return NULL;
}
byte *WrappedID3D12Resource::GetShadow(UINT Subresource)
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
if(Subresource >= map.size())
map.resize(Subresource + 1);
return map[Subresource].shadowPtr;
}
void WrappedID3D12Resource::AllocShadow(UINT Subresource, size_t size)
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
if(Subresource >= map.size())
map.resize(Subresource + 1);
if(map[Subresource].shadowPtr == NULL)
map[Subresource].shadowPtr = Serialiser::AllocAlignedBuffer(size);
}
void WrappedID3D12Resource::FreeShadow()
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
for(size_t i = 0; i < map.size(); i++)
{
Serialiser::FreeAlignedBuffer(map[i].shadowPtr);
map[i].shadowPtr = NULL;
}
}
HRESULT STDMETHODCALLTYPE WrappedID3D12Resource::Map(UINT Subresource,
const D3D12_RANGE *pReadRange, void **ppData)
{
// don't care about maps without returned pointers - we'll just intercept the WriteToSubresource
// calls
if(ppData == NULL)
return m_pReal->Map(Subresource, pReadRange, ppData);
void *mapPtr = NULL;
// pass a NULL range as we might want to read from the whole range
HRESULT hr = m_pReal->Map(Subresource, NULL, &mapPtr);
if(ppData)
*ppData = mapPtr;
if(SUCCEEDED(hr) && GetResourceRecord())
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
if(Subresource >= map.size())
map.resize(Subresource + 1);
map[Subresource].realPtr = (byte *)mapPtr;
// need to register this so we can flush any updates in case it's left persistant
m_pDevice->Map(this, Subresource);
}
return hr;
}
void STDMETHODCALLTYPE WrappedID3D12Resource::Unmap(UINT Subresource, const D3D12_RANGE *pWrittenRange)
{
if(GetResourceRecord())
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
// may not have a map if e.g. no pointer was requested
if(Subresource < map.size())
{
m_pDevice->Unmap(this, Subresource, map[Subresource].realPtr, pWrittenRange);
map[Subresource].realPtr = NULL;
Serialiser::FreeAlignedBuffer(map[Subresource].shadowPtr);
}
}
return m_pReal->Unmap(Subresource, pWrittenRange);
}
HRESULT STDMETHODCALLTYPE WrappedID3D12Resource::WriteToSubresource(UINT DstSubresource,
const D3D12_BOX *pDstBox,
const void *pSrcData,
UINT SrcRowPitch,
UINT SrcDepthPitch)
{
if(GetResourceRecord())
{
vector<D3D12ResourceRecord::MapData> &map = GetResourceRecord()->m_Map;
if(DstSubresource < map.size())
{
m_pDevice->WriteToSubresource(this, DstSubresource, pDstBox, pSrcData, SrcDepthPitch,
SrcDepthPitch);
}
else
{
RDCERR("WriteToSubresource without matching map!");
}
}
return m_pReal->WriteToSubresource(DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch);
}
WrappedID3D12DescriptorHeap::WrappedID3D12DescriptorHeap(ID3D12DescriptorHeap *real,
WrappedID3D12Device *device,
const D3D12_DESCRIPTOR_HEAP_DESC &desc)
+17 -24
View File
@@ -29,10 +29,10 @@
#include "d3d12_device.h"
#include "d3d12_manager.h"
class TrackedResource
class TrackedResource12
{
public:
TrackedResource()
TrackedResource12()
{
m_ID = ResourceIDGen::GetNewUniqueID();
m_pRecord = NULL;
@@ -41,8 +41,8 @@ public:
D3D12ResourceRecord *GetResourceRecord() { return m_pRecord; }
void SetResourceRecord(D3D12ResourceRecord *record) { m_pRecord = record; }
private:
TrackedResource(const TrackedResource &);
TrackedResource &operator=(const TrackedResource &);
TrackedResource12(const TrackedResource12 &);
TrackedResource12 &operator=(const TrackedResource12 &);
ResourceId m_ID;
D3D12ResourceRecord *m_pRecord;
@@ -51,7 +51,9 @@ private:
extern const GUID RENDERDOC_ID3D12ShaderGUID_ShaderDebugMagicValue;
template <typename NestedType, typename NestedType1 = NestedType, typename NestedType2 = NestedType1>
class WrappedDeviceChild12 : public RefCounter12<NestedType>, public NestedType2, public TrackedResource
class WrappedDeviceChild12 : public RefCounter12<NestedType>,
public NestedType2,
public TrackedResource12
{
protected:
WrappedID3D12Device *m_pDevice;
@@ -737,6 +739,11 @@ public:
bool Resident() { return resident; }
void SetResident(bool r) { resident = r; }
byte *GetMap(UINT Subresource);
byte *GetShadow(UINT Subresource);
void AllocShadow(UINT Subresource, size_t size);
void FreeShadow();
//////////////////////////////
// implement ID3D12Resource
@@ -752,31 +759,17 @@ public:
return m_pReal->GetHeapProperties(pHeapProperties, pHeapFlags);
}
virtual HRESULT STDMETHODCALLTYPE Map(UINT Subresource, const D3D12_RANGE *pReadRange, void **ppData)
{
D3D12NOTIMP("Resource mapping");
return m_pReal->Map(Subresource, pReadRange, ppData);
}
virtual void STDMETHODCALLTYPE Unmap(UINT Subresource, const D3D12_RANGE *pWrittenRange)
{
D3D12NOTIMP("Resource mapping");
return m_pReal->Unmap(Subresource, pWrittenRange);
}
virtual HRESULT STDMETHODCALLTYPE Map(UINT Subresource, const D3D12_RANGE *pReadRange,
void **ppData);
virtual void STDMETHODCALLTYPE Unmap(UINT Subresource, const D3D12_RANGE *pWrittenRange);
virtual HRESULT STDMETHODCALLTYPE WriteToSubresource(UINT DstSubresource, const D3D12_BOX *pDstBox,
const void *pSrcData, UINT SrcRowPitch,
UINT SrcDepthPitch)
{
D3D12NOTIMP("Resource mapping");
return m_pReal->WriteToSubresource(DstSubresource, pDstBox, pSrcData, SrcRowPitch, SrcDepthPitch);
}
UINT SrcDepthPitch);
virtual HRESULT STDMETHODCALLTYPE ReadFromSubresource(void *pDstData, UINT DstRowPitch,
UINT DstDepthPitch, UINT SrcSubresource,
const D3D12_BOX *pSrcBox)
{
D3D12NOTIMP("Resource mapping");
// don't have to do anything here
return m_pReal->ReadFromSubresource(pDstData, DstRowPitch, DstDepthPitch, SrcSubresource,
pSrcBox);
}