Don't save every queue creation in D3D12 device record

* Otherwise we try to create every queue that has ever existed on replay.
* Check for resource leaks in Resource_Lifetimes tests.
This commit is contained in:
baldurk
2020-02-03 16:12:34 +00:00
parent c3b6b6890e
commit d7b61176c5
9 changed files with 101 additions and 6 deletions
+2 -1
View File
@@ -105,7 +105,7 @@ class WrappedID3D12CommandQueue : public ID3D12CommandQueue,
HWND m_pPresentHWND = NULL;
ResourceId m_ResourceID;
D3D12ResourceRecord *m_QueueRecord;
D3D12ResourceRecord *m_QueueRecord, *m_CreationRecord;
CaptureState &m_State;
@@ -148,6 +148,7 @@ public:
ResourceId GetResourceID() { return m_ResourceID; }
ID3D12CommandQueue *GetReal() { return m_pReal; }
D3D12ResourceRecord *GetResourceRecord() { return m_QueueRecord; }
D3D12ResourceRecord *GetCreationRecord() { return m_CreationRecord; }
WrappedID3D12Device *GetWrappedDevice() { return m_pDevice; }
const rdcarray<D3D12ResourceRecord *> &GetCmdLists() { return m_CmdListRecords; }
D3D12DrawcallTreeNode &GetParentDrawcall() { return m_Cmd.m_ParentDrawcall; }
+13
View File
@@ -339,6 +339,7 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real,
m_ResourceID = ResourceIDGen::GetNewUniqueID();
m_QueueRecord = NULL;
m_CreationRecord = NULL;
m_Cmd.m_pDevice = m_pDevice;
@@ -349,6 +350,15 @@ WrappedID3D12CommandQueue::WrappedID3D12CommandQueue(ID3D12CommandQueue *real,
m_QueueRecord->DataInSerialiser = false;
m_QueueRecord->InternalResource = true;
m_QueueRecord->Length = 0;
// a bit of a hack, we make a parallel resource record with the same lifetime as the command
// queue. It will hold onto our create chunk and not get thrown away as we clear and re-fill
// submissions into the queue record itself. We'll pull it into the capture by marking the
// queues as referenced.
m_CreationRecord =
m_pDevice->GetResourceManager()->AddResourceRecord(ResourceIDGen::GetNewUniqueID());
m_CreationRecord->type = Resource_CommandQueue;
m_CreationRecord->InternalResource = true;
}
m_pDevice->GetResourceManager()->AddCurrentResource(GetResourceID(), this);
@@ -360,6 +370,9 @@ WrappedID3D12CommandQueue::~WrappedID3D12CommandQueue()
{
SAFE_DELETE(m_FrameReader);
if(m_CreationRecord)
m_CreationRecord->Delete(m_pDevice->GetResourceManager());
if(m_QueueRecord)
m_QueueRecord->Delete(m_pDevice->GetResourceManager());
m_pDevice->GetResourceManager()->ReleaseCurrentResource(GetResourceID());
+9 -4
View File
@@ -1812,11 +1812,16 @@ void WrappedID3D12Device::StartFrameCapture(void *dev, void *wnd)
m_HeaderChunk = scope.Get();
}
// keep all queues alive during the capture, by adding a refcount
for(auto it = m_Queues.begin(); it != m_Queues.end(); ++it)
(*it)->AddRef();
m_State = CaptureState::ActiveCapturing;
// keep all queues alive during the capture, by adding a refcount. Also reference the creation
// record so that it's pulled in as initialisation chunks.
for(auto it = m_Queues.begin(); it != m_Queues.end(); ++it)
{
(*it)->AddRef();
GetResourceManager()->MarkResourceFrameReferenced((*it)->GetCreationRecord()->GetResourceID(),
eFrameRef_Read);
}
}
GetResourceManager()->MarkResourceFrameReferenced(m_ResourceID, eFrameRef_Read);
+5 -1
View File
@@ -114,7 +114,7 @@ HRESULT WrappedID3D12Device::CreateCommandQueue(const D3D12_COMMAND_QUEUE_DESC *
SCOPED_SERIALISE_CHUNK(D3D12Chunk::Device_CreateCommandQueue);
Serialise_CreateCommandQueue(ser, pDesc, riid, (void **)&wrapped);
m_DeviceRecord->AddChunk(scope.Get());
wrapped->GetCreationRecord()->AddChunk(scope.Get());
}
else
{
@@ -141,7 +141,11 @@ HRESULT WrappedID3D12Device::CreateCommandQueue(const D3D12_COMMAND_QUEUE_DESC *
// while capturing don't allow any queues to be freed, by adding another refcount, since we
// gather any commands submitted to them at the end of the capture.
if(capframe)
{
GetResourceManager()->MarkResourceFrameReferenced(
wrapped->GetCreationRecord()->GetResourceID(), eFrameRef_Read);
wrapped->AddRef();
}
*ppCommandQueue = (ID3D12CommandQueue *)wrapped;
}
@@ -397,11 +397,17 @@ float4 main(v2f IN) : SV_Target0
descheap = NULL;
};
ID3D12ResourcePtr rtvtex = MakeTexture(DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, screenWidth, screenHeight)
.RTV()
.InitialState(D3D12_RESOURCE_STATE_RENDER_TARGET);
ID3D12ResourcePtr cb = SetupBuf();
ID3D12ResourcePtr img = SetupImg();
ID3D12DescriptorHeapPtr descheap = SetupDescHeap(cb, img);
while(Running())
{
D3D12_CPU_DESCRIPTOR_HANDLE offrtv = MakeRTV(rtvtex).CreateCPU(1);
D3D12_CPU_DESCRIPTOR_HANDLE rtv;
// acquire and clear the backbuffer
@@ -457,6 +463,45 @@ float4 main(v2f IN) : SV_Target0
TrashDescHeap(descheap);
}
// use a temporary queue
{
GPUSync();
ID3D12CommandQueuePtr tempQueue;
{
D3D12_COMMAND_QUEUE_DESC desc = {};
desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
dev->CreateCommandQueue(&desc, __uuidof(ID3D12CommandQueue), (void **)&tempQueue);
}
ID3D12GraphicsCommandListPtr cmd = GetCommandBuffer();
Reset(cmd);
ClearRenderTargetView(cmd, offrtv, {0.6f, 0.5f, 0.4f, 1.0f});
OMSetRenderTargets(cmd, {offrtv}, {});
cmd->Close();
ID3D12CommandList *submit = cmd.GetInterfacePtr();
tempQueue->ExecuteCommandLists(1, &submit);
// manually insert this into freeCommandBuffers since our normal lifetime management doesn't
// handle submissino on other queues.
freeCommandBuffers.push_back(cmd);
m_GPUSyncCounter++;
CHECK_HR(tempQueue->Signal(m_GPUSyncFence, m_GPUSyncCounter));
CHECK_HR(m_GPUSyncFence->SetEventOnCompletion(m_GPUSyncCounter, m_GPUSyncHandle));
WaitForSingleObject(m_GPUSyncHandle, 10000);
tempQueue = NULL;
}
// create resources mid-frame and use then trash them
{
cb = SetupBuf();
@@ -4,6 +4,13 @@ import rdtest
class D3D11_Resource_Lifetimes(rdtest.TestCase):
demos_test_name = 'D3D11_Resource_Lifetimes'
demos_frame_cap = 200
def check_capture(self):
self.check_final_backbuffer()
# Check for resource leaks
if len(self.controller.GetResources()) > 75:
raise rdtest.TestFailureException(
"Too many resources found: {}".format(len(self.controller.GetResources())))
@@ -4,6 +4,12 @@ import rdtest
class D3D12_Resource_Lifetimes(rdtest.TestCase):
demos_test_name = 'D3D12_Resource_Lifetimes'
demos_frame_cap = 200
def check_capture(self):
self.check_final_backbuffer()
# Check for resource leaks
if len(self.controller.GetResources()) > 75:
raise rdtest.TestFailureException(
"Too many resources found: {}".format(len(self.controller.GetResources())))
@@ -4,6 +4,13 @@ import rdtest
class GL_Resource_Lifetimes(rdtest.TestCase):
demos_test_name = 'GL_Resource_Lifetimes'
demos_frame_cap = 200
def check_capture(self):
self.check_final_backbuffer()
# Check for resource leaks
if len(self.controller.GetResources()) > 75:
raise rdtest.TestFailureException(
"Too many resources found: {}".format(len(self.controller.GetResources())))
@@ -4,6 +4,13 @@ import rdtest
class VK_Resource_Lifetimes(rdtest.TestCase):
demos_test_name = 'VK_Resource_Lifetimes'
demos_frame_cap = 200
def check_capture(self):
self.check_final_backbuffer()
# Check for resource leaks
if len(self.controller.GetResources()) > 75:
raise rdtest.TestFailureException(
"Too many resources found: {}".format(len(self.controller.GetResources())))