Jump to content
  • Advertisement
Sign in to follow this  
iGrfx

DX12 How to change Descriptor Entry between Draw Call?

Recommended Posts

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.

Share this post


Link to post
Share on other sites
Advertisement

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?

Share this post


Link to post
Share on other sites
Posted (edited)
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?

Edited by iGrfx
Complemetary

Share this post


Link to post
Share on other sites

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!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!