[D3D12] SetDescriptorHeaps

Started by
5 comments, last by _the_phantom_ 8 years, 8 months ago

A couple quick questions.

  1. ID3D12GraphicsCommandList::SetDesciptorHeaps, the documentation specifically states that you cannot call this on a Bundle, and yet the Hello World SDK sample does this exact thing (as do several other samples I've found around the internet). The debug layer doesn't appear to issue a warning like the documentation says it should. Is the documentation correct or out of date?
  2. Am I correct that the method above is the link between your heap-based content and the pipeline? From what I gather, you define the structure of your content via the root parameters, but actual binding happens with SetDescriptorHeaps. Now, the method takes an array of heap pointers; am I correct in assuming that the order of those heaps in the list much match up somehow with the root signature? If that's true, then how does that work with descriptor tables, since the root signature can be a two-level hierarchy of tables. It seems hard to manage, unless I'm missing something.

Thanks!

Advertisement
1) Yeah, I've concluded that is a documentation fault too. I've seen functions which say 'only use on a direct command queue' used on a compute only one - if in doubt check the examples I say smile.png

2) It is part of that link, yes. It is a two stage affair.

SetDescriptorHeaps effectively sets from 'base addresses' for the GPU to look at. When you pass it some heap locations you are saying "you'll be looking into these chunks of memory for things".

You then use Set*RootDescriptorTable() to point a slot you defined in the root descriptor at the data in a heap. (Where you would call 'initAsTable' as per the examples)

In C++ terms;
[source]
// SetDescriptorHeaps + Set*RootDescriptorTable for entry 0 in heap.
void func(void** HeapAddress, int offset)
{
void * BaseAddress = HeapAddress[0]; // SetDescriptorHeaps
void * ResourceAddress = BaseAddress + offset; // Set*RootDescriptorTable;
// Resource access now done via Resource address
...
}
[/source]

The resource for the two phase system is that it allows you to create a large heap but reference a subsection of it during a draw.
Hi,

The Hello World Texture example does not use bundles.
The Hello World Bundle does, but doesn't set descriptor heaps.

Perhaps you're confused, assuming that command lists == bundles, which is not true. Bundles are command lists like the regular ones but that are executed from a parent command list via ExecuteBundle, while regular command lists are executed via a command queue's ExecuteCommandLists.
Also they differ slightly in their creation (one is created with D3D12_COMMAND_LIST_TYPE_BUNDLE, the other with D3D12_COMMAND_LIST_TYPE_DIRECT).

Nonetheless, it appears the docs are slightly out of sync. The Bundle restrictions docs are more specific at what you can do:

SetDescriptorHeaps can be called on a bundle, but the bundle descriptor heaps must match the calling command list descriptor heap.

Not 100% sure what that means though (if I interpret this correctly, you can only call SetDescriptorHeaps to set a descriptor already set... which is redundant; unless they allow me to offset it).
In some cases the API allows you to set things redundantly (think rendertarget formats, root signature in both the pipeline state and its direct set call, and so on), one of those is the authority and the other one is there to allow for better optimization (so that the driver doesn't have to wait til submission time to build some things).


SetDescriptorHeaps effectively sets from 'base addresses' for the GPU to look at. When you pass it some heap locations you are saying "you'll be looking into these chunks of memory for things".

You then use Set*RootDescriptorTable() to point a slot you defined in the root descriptor at the data in a heap. (Where you would call 'initAsTable' as per the examples)

Conceptually, that makes sense to me. The confusing part is that Set*RootDescriptorTable already takes a GPU descriptor handle, which defines the GPU pointer to the heap (is that correct?). Is there not enough information in the D3D12_GPU_DESCRIPTOR_HANDLE to identify the heap? I suppose I could see it as a way to simplify the backend by requiring the user to specify the exact set of buffers instead of gathering a list from descriptor handles (which would be more expensive). Secondly, can I provide the heaps in arbitrary order? Do they have to match up somehow with the way I've organized the root parameters?


Perhaps you're confused, assuming that command lists == bundles, which is not true. Bundles are command lists like the regular ones but that are executed from a parent command list via ExecuteBundle, while regular command lists are executed via a command queue's ExecuteCommandLists.
Also they differ slightly in their creation (one is created with D3D12_COMMAND_LIST_TYPE_BUNDLE, the other with D3D12_COMMAND_LIST_TYPE_DIRECT).

The sample I was looking at is HelloWorld/HelloConstBuffers, which uses both bundles and a descriptor heap for the constant buffer.

The sample I was looking at is HelloWorld/HelloConstBuffers, which uses both bundles and a descriptor heap for the constant buffer.

I can't find any reference to Bundles in the HelloConstBuffers sample. The only command list I see being created is direct. Could you point it out? Maybe I missed it.

hanks.

Conceptually, that makes sense to me. The confusing part is that Set*RootDescriptorTable already takes a GPU descriptor handle, which defines the GPU pointer to the heap (is that correct?). Is there not enough information in the D3D12_GPU_DESCRIPTOR_HANDLE to identify the heap? I suppose I could see it as a way to simplify the backend by requiring the user to specify the exact set of buffers instead of gathering a list from descriptor handles (which would be more expensive). Secondly, can I provide the heaps in arbitrary order? Do they have to match up somehow with the way I've organized the root parameters?


I suspect it is done that way to let the driver decide what to do.
Given a heap base address and two pointers into that heap you can store the latter as offsets into the former, potentially taking up less register space vs a full blown reference. A look at the GCN docs would probably give a good reason for this, at least for that bit of hardware.

As for the order; seems not to matter.
I only did a simple test on this (D3D12DynamicIndexing example; swapped order of heaps @ Ln93 in FrameResource.cpp), but it worked fine so I'm willing to assume this holds true of all resources... until I find a situation which breaks it ;)

This topic is closed to new replies.

Advertisement