Advertisement

One DescriptorHeap per frame buffer ?

Started by August 10, 2018 01:30 PM
3 comments, last by CortexDragon 6 years, 5 months ago

Hello,

By digging a bit more in my DX12 learning, I am hitting a problem and I am not certain if my way to handle it, is correct.

I will try to explain myself the best I can :)

Basics DX12 samples and tutorials are generally using 2 Descriptor Heap (CBV / Sampler) and all constant buffer resource creation are generally multiplied by the amount of backbuffer. So when double buffering, I have one descHeap (CBV) allocating two slots for each constant buffer (to avoid conflict when modifying data). But now I'd like to play around with Root Signature Descriptor Table, so I need my CB heap slots to be continuous, however if each time I initialize a CB my descHeap allocate two room to it, I end up with discontinuous CB.

So to avoid this problem, I was thinking of having one CBV/SRV/UAV DescriptorHeap per back buffer and one common Sample DescriptorHeap. So when allocating several CB, they are all continuous in their own heap. Is that a common practice ?

And additionally, for stuffs like textures, I don't want to create two commited resource for them because it will mean upload them 2 times in GPU memory while they are "read only" resource (most of the time). So with my multiple DescHeap system, it will mean multiple heap pointing on the same resource. Is that a problem ?

Hope I've been understandable :)

Thank you.

It depends on how to use them.

  • If your descriptor heap is GPU visible and directly referenced by the GPU using ID3D12GraphicsCommandList::SetDescriptorHeaps (and the commandqueue is executing via ExecuteCommandLists), then you can not safely modify this by the CPU at this time. You must either wait for the GPU to finish, or use a second descriptor heap to write from CPU.
  • GPU-visible descriptor heap can be written to by CPU, if it is not yet bound to GPU.
  • If your descriptor heap is not GPU visible, you can modify this from the CPU any time. You can copy from this to a GPU visible descriptor heap.

You said that you would have a descriptor heap per backbuffer, but not sampler heap? Sampler heap is the same as the rest, so unless you never modify samplers at runtime, you should have a sampler heap per backbuffer.

For textures, you definitely don't want two committed resources. The usual way is to synchronize them, so the GPU can't access them while the upload hasn't finished. You can of course point to a single committed resource from multiple descriptor heaps and arbitrary amount of descriptors. 

Hope that helps! :)

Advertisement
5 hours ago, turanszkij said:

It depends on how to use them.

  • If your descriptor heap is GPU visible and directly referenced by the GPU using ID3D12GraphicsCommandList::SetDescriptorHeaps (and the commandqueue is executing via ExecuteCommandLists), then you can not safely modify this by the CPU at this time. You must either wait for the GPU to finish, or use a second descriptor heap to write from CPU.
  • GPU-visible descriptor heap can be written to by CPU, if it is not yet bound to GPU.
  • If your descriptor heap is not GPU visible, you can modify this from the CPU any time. You can copy from this to a GPU visible descriptor heap.

You said that you would have a descriptor heap per backbuffer, but not sampler heap? Sampler heap is the same as the rest, so unless you never modify samplers at runtime, you should have a sampler heap per backbuffer.

For textures, you definitely don't want two committed resources. The usual way is to synchronize them, so the GPU can't access them while the upload hasn't finished. You can of course point to a single committed resource from multiple descriptor heaps and arbitrary amount of descriptors. 

Hope that helps! :)

Thank you for your reply.

At the moment, my heaps are shaders visible, so having one by frame buffer is the way to go.

If I understand you right, if I only wanted to have common heaps, I will need to have one heap CPU only visible where every frame can access and at the beginning of each frame rendering, I would copy descriptor to a another GPU visible heap. That the way ring buffer are working ?

And for texture, when it's time to destroy their resource, I will have to wait a few frames to be certain another buffer isn't using them ?

You dont need multiple descriptor heaps to give each frameobject a contineous region in a descriptorheap

You can simply have each frameobjects unique buffers use a different region of the same big cbv/srv/uav descriptorheap

Example:

If I have a framecount of 3 (2 backbuffers and 1 front buffer). This means I have 3 frameobjects.

I have 10 constant buffers for each frameobject

I have 20 textures which are shared by each frame object

I have 5 slow changing constant buffers that are shared by each frame object.

 

The cbv/srv/uav descriptor heap is arranged like this:

slots 0 to 9 are the 10 constant buffers views of the first frameobject

slots 10 to 19 are the 10 constant buffers views of the second frameobject

slots 20 to 29 are the 10 constant buffers views of the third frameobject

slots 30 to 49 are the 20 textures shader resource views shared by all frame objects.

slots 50 to 54 are the 5 slow changing constant buffer cbvs shared by all frame objects.

 

I use an enum for my descriptor heap slots to help avoiding mistakes.

 

 

 

This topic is closed to new replies.

Advertisement