Advertisement

How to change Descriptor Entry between Draw Call?

Started by October 07, 2019 05:11 AM
3 comments, last by turanszkij 5 years, 4 months ago

Here is my code snip:


ID3D12DescriptorHeap* DescHeaps[] = { SRVHeapCache.GetDescriptorHeap() };// I want to bind Different RTV to this heap cache between Draw Calls
	CommandList->SetDescriptorHeaps(1, DescHeaps);
	CommandList->SetGraphicsRootSignature(RootSignature.Get());
	CommandList->SetGraphicsRootConstantBufferView(2, PerPassConstants.GetResource()->GetGPUVirtualAddress());
	CommandList->SetGraphicsRootConstantBufferView(1, PerObjectConstants.GetResource()->GetGPUVirtualAddress());
	
	CommandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
	for (auto Actor : TheScene.Actors)
	{
		CommandList->SetGraphicsRootDescriptorTable(0, SRVHeapCache.GetGPUHandleStart());
		Actor->Draw(D3dDevice.Get(), CommandList.Get(), SRVHeapCache.GetDescriptorHeap());
	}

And in Actor's Draw, I use CopyDescriptorsSimple:


Device->CopyDescriptorsSimple(1, hDescriptor, Mgr->Textures[DiffTextureID].Texture.GetCPUHandle(), D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

But this doesn't work. The content of HeapCache seems to never change in the runtime.

This is too little information to really say what's wrong. Keep in mind that CopyDescriptorsSimple performs an immediate copy of descriptors, but Draw() will only execute after you submit the command list. By the time the GPU executes the draw, you will want to keep descriptors of the draw alive and not overwrite them. For example, this can be done by using the descriptor heap as a ring buffer and always binding different portions of it via SetGraphicsRootDescriptorTable(). Do you update your descriptors with this in mind?

Advertisement
56 minutes ago, turanszkij said:

This is too little information to really say what's wrong. Keep in mind that CopyDescriptorsSimple performs an immediate copy of descriptors, but Draw() will only execute after you submit the command list. By the time the GPU executes the draw, you will want to keep descriptors of the draw alive and not overwrite them. For example, this can be done by using the descriptor heap as a ring buffer and always binding different portions of it via SetGraphicsRootDescriptorTable(). Do you update your descriptors with this in mind?

image.png.996abf842e7c802ca716d51521b59dc2.png

This is what I did, Bind those RTV to Cache. (But this slot will be overwritten before command list be submitted).According to your advice. I should do it like below?

image.png.0ec4f682da778ee67b0d15463a533b35.png

I need to SetGraphicsRootDescriptorTable with CurrentTablePrt. 

During a bunch of DCs, It usually needs to bind different RTV, What's the best practice?

From your image, what does RTV heap has to do with SRV heap? And it's not clear to me what you mean by heap cache. In my case, I solve this problem by having two different kinds of descriptor heaps:

  1. One heap where descriptors are created, deleted, etc, only CPU access
  2. A heap where descriptors are copied before draws. CPU and GPU access.

When I create a Texture object for example, I create descriptors for it in heap1. When I delete the Texture object, I remove its descriptors from heap1.

When I draw an object using a Texture, I copy the descriptor from heap1 to heap2. When I draw an other object with an other texture, I copy from heap1 to heap2, BUT: not overwriting the previously written descriptors, but keeping an offset to the last copied descriptor and copying to the free space. Before each draw that changed descriptors, I call SetGraphicsRootDescriptorTable(), with a GPU descriptor handle like this:


D3D12_GPU_DESCRIPTOR_HANDLE binding_table = heap_start;
binding_table.ptr += ringOffset;

ringOffset is ever increasing with the amount of descriptor sizes that are copied, that you can get like: 


device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

The ringOffset will be reset to zero when a new frame starts. You will also need to look out that if you double buffer your rendering, you will also need to double buffer your descriptor heaps, again, so that an other frame's rendering doesn't read from the heap you are currently writing to.

I hope that helps, good luck!

This topic is closed to new replies.

Advertisement