Skip to content

Commit

Permalink
Add custom D3D12 interface for per-heap descriptor naming by index
Browse files Browse the repository at this point in the history
  • Loading branch information
baldurk committed Dec 13, 2024
1 parent cd603f0 commit 7fe2749
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 4 deletions.
18 changes: 17 additions & 1 deletion docs/behind_scenes/d3d12_support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,23 @@ RenderDoc has initial support for D3D12, but it contains some caveats. In additi

* RenderDoc assumes that even if multiple GPUs are present, that only one will be used - i.e. NodeMask is always 0. Multiple queues are supported.
* RenderDoc captures may not be portable between different systems, only currently supporting capture and replay on the same or similar enough machines.
* Shader debugging is not supported for DXIL shaders.

RenderDoc extensions
--------------------

On D3D12 there is a RenderDoc extension provided with this interface, queried from an ``ID3D12DescriptorHeap``:

.. highlight:: c++
.. code:: c++

MIDL_INTERFACE("52528c37-bfd9-4bbb-99ff-fdb7188619ce")
IRenderDocDescriptorNamer : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SetName(UINT DescriptorIndex, LPCSTR Name) = 0;
};

This interface allows you to set a custom name for descriptors, if using SM6.6 style ``ResourceDescriptorHeap[]`` access for better debugging.

See Also
--------
Expand Down
16 changes: 16 additions & 0 deletions docs/how/how_annotate_capture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,22 @@ In Vulkan you can enable the ``VK_EXT_debug_utils`` extension, which is provided
nameInfo.pObjectName = "Off-screen color framebuffer";
vkSetDebugUtilsObjectNameEXT(device, &nameInfo);

On D3D12 there is a RenderDoc extension provided with this interface, queried from an ``ID3D12DescriptorHeap``:

.. highlight:: c++
.. code:: c++

MIDL_INTERFACE("52528c37-bfd9-4bbb-99ff-fdb7188619ce")
IRenderDocDescriptorNamer : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SetName(UINT DescriptorIndex, LPCSTR Name) = 0;
};


This interface allows you to set a custom name for descriptors, if using SM6.6 style ``ResourceDescriptorHeap[]`` access for better debugging.


Bookmarks
---------

Expand Down
4 changes: 4 additions & 0 deletions renderdoc/driver/d3d12/d3d12_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,10 @@ bool D3D12InitParams::IsSupportedVersion(uint64_t ver)
if(ver == 0x11)
return true;

// 0x12 -> 0x13 - Descriptor heap initial states contain optional user names for descriptors
if(ver == 0x12)
return true;

return false;
}

Expand Down
2 changes: 1 addition & 1 deletion renderdoc/driver/d3d12/d3d12_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ struct D3D12InitParams
UINT SDKVersion = 0;

// check if a frame capture section version is supported
static const uint64_t CurrentVersion = 0x12;
static const uint64_t CurrentVersion = 0x13;

static bool IsSupportedVersion(uint64_t ver);
};
Expand Down
16 changes: 15 additions & 1 deletion renderdoc/driver/d3d12/d3d12_initstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ bool D3D12ResourceManager::Prepare_InitialState(ID3D12DeviceChild *res)
D3D12Descriptor *descs = new D3D12Descriptor[numElems];
memcpy(descs, heap->GetDescriptors(), sizeof(D3D12Descriptor) * numElems);

SetInitialContents(heap->GetResourceID(), D3D12InitialContents(descs, numElems));
D3D12InitialContents initContents(descs, numElems);

if(heap->HasNames())
initContents.descriptorNames = heap->GetNames();

SetInitialContents(heap->GetResourceID(), initContents);
return true;
}
else if(type == Resource_Resource)
Expand Down Expand Up @@ -768,6 +773,7 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI
{
D3D12Descriptor *Descriptors = initial ? initial->descriptors : NULL;
uint32_t numElems = initial ? initial->numDescriptors : 0;
rdcarray<rdcstr> names = initial ? initial->descriptorNames : rdcarray<rdcstr>();

// there's no point in setting up a lazy array when we're structured exporting because we KNOW
// we're going to need all the data anyway.
Expand All @@ -777,6 +783,11 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI
SERIALISE_ELEMENT_ARRAY(Descriptors, numElems);
SERIALISE_ELEMENT(numElems).Named("NumDescriptors"_lit).Important();

if(ser.VersionAtLeast(0x13))
{
SERIALISE_ELEMENT(names).Hidden();
}

ser.SetLazyThreshold(0);

SERIALISE_CHECK_READ_ERRORS();
Expand All @@ -785,6 +796,9 @@ bool D3D12ResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceI
{
WrappedID3D12DescriptorHeap *heap = (WrappedID3D12DescriptorHeap *)GetLiveResource(id);

if(!names.empty())
heap->GetNames() = names;

D3D12_DESCRIPTOR_HEAP_DESC desc = heap->GetDesc();

// this heap doesn't have to be shader visible, we just use it to copy from
Expand Down
1 change: 1 addition & 0 deletions renderdoc/driver/d3d12/d3d12_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ struct D3D12InitialContents
ID3D12DeviceChild *resource;
byte *srcData;
size_t dataSize;
rdcarray<rdcstr> descriptorNames;

rdcarray<uint32_t> subresources;

Expand Down
10 changes: 10 additions & 0 deletions renderdoc/driver/d3d12/d3d12_replay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2129,6 +2129,16 @@ rdcarray<DescriptorLogicalLocation> D3D12Replay::GetDescriptorLocations(
{
// can't set anything except the "bind number" which we just set as the offset.
ret[dst].fixedBindNumber = descriptorId;
if(heap->HasNames())
{
rdcstr name = heap->GetNames()[descriptorId];
if(!name.empty())
{
ret[dst].logicalBindName = StringFormat::Fmt("%s[%u]", name.c_str(), descriptorId);
continue;
}
}

if(sampler)
ret[dst].logicalBindName = StringFormat::Fmt("SamplerDescriptorHeap[%u]", descriptorId);
else
Expand Down
57 changes: 56 additions & 1 deletion renderdoc/driver/d3d12/d3d12_resources.h
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,15 @@ class WrappedID3D12CommandSignature : public WrappedDeviceChild12<ID3D12CommandS

struct D3D12Descriptor;

class WrappedID3D12DescriptorHeap : public WrappedDeviceChild12<ID3D12DescriptorHeap>
MIDL_INTERFACE("52528c37-bfd9-4bbb-99ff-fdb7188619ce")
IRenderDocDescriptorNamer : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SetName(UINT DescriptorIndex, LPCSTR Name) = 0;
};

class WrappedID3D12DescriptorHeap : public WrappedDeviceChild12<ID3D12DescriptorHeap>,
public IRenderDocDescriptorNamer
{
D3D12_CPU_DESCRIPTOR_HANDLE realCPUBase;
D3D12_GPU_DESCRIPTOR_HANDLE realGPUBase;
Expand All @@ -487,6 +495,9 @@ class WrappedID3D12DescriptorHeap : public WrappedDeviceChild12<ID3D12Descriptor
// (which applications then queried and passed to the GPU) which is used for GPU-unwrapping handles
uint64_t m_OriginalWrappedGPUBase;

Threading::CriticalSection namesLock;
rdcarray<rdcstr> names;

public:
ALLOCATE_WITH_WRAPPED_POOL(WrappedID3D12DescriptorHeap);

Expand All @@ -499,6 +510,33 @@ class WrappedID3D12DescriptorHeap : public WrappedDeviceChild12<ID3D12Descriptor
const D3D12_DESCRIPTOR_HEAP_DESC &desc, UINT UnpatchedNumDescriptors);
virtual ~WrappedID3D12DescriptorHeap();

ULONG STDMETHODCALLTYPE AddRef() { return WrappedDeviceChild12::AddRef(); }
ULONG STDMETHODCALLTYPE Release() { return WrappedDeviceChild12::Release(); }
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject)
{
if(riid == __uuidof(IRenderDocDescriptorNamer))
{
*ppvObject = (IRenderDocDescriptorNamer *)this;
// allocate names array now
GetNames();
AddRef();
return S_OK;
}
return WrappedDeviceChild12::QueryInterface(riid, ppvObject);
}

bool HasNames()
{
SCOPED_LOCK(namesLock);
return !names.empty();
}
rdcarray<rdcstr> &GetNames()
{
SCOPED_LOCK(namesLock);
names.resize(numDescriptors);
return names;
}

D3D12Descriptor *GetDescriptors() { return descriptors; }
UINT GetNumDescriptors() { return numDescriptors; }

Expand Down Expand Up @@ -545,6 +583,23 @@ class WrappedID3D12DescriptorHeap : public WrappedDeviceChild12<ID3D12Descriptor
}

uint32_t GetUnwrappedIncrement() const { return increment; }

//////////////////////////////
// implement IRenderDocDescriptorNamer

virtual HRESULT STDMETHODCALLTYPE SetName(UINT DescriptorIndex, LPCSTR Name)
{
if(DescriptorIndex >= numDescriptors)
return E_INVALIDARG;

SCOPED_LOCK(namesLock);
if(!Name || !Name[0])
names[DescriptorIndex].clear();
else
names[DescriptorIndex] = Name;

return S_OK;
}
};

class WrappedID3D12Fence : public WrappedDeviceChild12<ID3D12Fence, ID3D12Fence1>
Expand Down
21 changes: 21 additions & 0 deletions util/test/demos/d3d12/d3d12_descriptor_indexing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@

#include "d3d12_test.h"

MIDL_INTERFACE("52528c37-bfd9-4bbb-99ff-fdb7188619ce")
IRenderDocDescriptorNamer : public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE SetName(UINT DescriptorIndex, LPCSTR Name) = 0;
};

COM_SMARTPTR(IRenderDocDescriptorNamer);

RD_TEST(D3D12_Descriptor_Indexing, D3D12GraphicsTest)
{
static constexpr const char *Description =
Expand Down Expand Up @@ -464,17 +473,29 @@ float4 main(v2f IN) : SV_Target0
MakeSRV(alias1Buf).StructureStride(3 * sizeof(Vec4f)).CreateGPU(150 + 6);
MakeSRV(alias2Buf).StructureStride(3 * sizeof(Vec4f)).CreateGPU(150 + 12);

IRenderDocDescriptorNamerPtr namer = m_CBVUAVSRV;

MakeSRV(smiley).CreateGPU(12);
if(namer)
namer->SetName(12, "smiley");
MakeSRV(smiley).CreateGPU(19);
if(namer)
namer->SetName(19, "another_smiley");
MakeSRV(smiley).CreateGPU(20);
if(namer)
namer->SetName(20, "more_smileys???");
MakeSRV(smiley).CreateGPU(21);
MakeSRV(smiley).CreateGPU(49);
MakeSRV(smiley).CreateGPU(59);
MakeSRV(smiley).CreateGPU(60);
MakeSRV(smiley).CreateGPU(99);
MakeSRV(smiley).CreateGPU(103);
MakeCBV(constBuf).SizeBytes(256).CreateGPU(9);
if(namer)
namer->SetName(9, "constBuf");
MakeUAV(outUAV).Format(DXGI_FORMAT_R32_UINT).CreateGPU(10);
if(namer)
namer->SetName(10, "outUAV");

D3D12_SAMPLER_DESC samplerDesc = {};
samplerDesc.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
Expand Down

0 comments on commit 7fe2749

Please sign in to comment.