🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

DX12 Descriptor heap CPU handle odd adresses

Started by
7 comments, last by tomas.drinovsky 1 year, 8 months ago

Hello fellow developers,

I have quite a peculiar problem which shattered my understanding of how descriptor heaps work. Maybe you can help me.

Recently we are having troubles with CopyDescriptors call in our engine. For some users it returns error:

D3D12 Error: ID3D12Device::CopyDescriptors: Source ranges and dest ranges overlap, which results in undefined behavior.

I have tracked the problem to CPUDescriptorHandles with odd addresses.

I have this piece of code:

The Updated.TotalCount = 9216 and Immediate.TotalCount = 46864.

Calling _updatedHeap.GetCPUDescriptorHandleForHeapStart() results in Ptr = 1 , calling _immediateHeap.GetCPUDescriptorHandleForHeapStart() results in Ptr = 2.

But I would expect immediateHeap.GetCPUDescriptorHandleForHeapStart() to results in 1 + 9216 * SRVDescriptorSize.

How does the CopyDescriptors work if these addresses are its only input, no other refs are passed. Or is only one descriptor heap per type supported?

btw. The code above uses Vortice C# library, but I checked the behavior in native C++ code as well.

btw #2. The results above are returned on NVIDIA cards. AMD returns numbers more resembling real addresses.

Advertisement

I don't know, but as a guess, I'd say it's because handles let you do an incredible amount of indirection and abstraction, and using metadata about the handle in a system allows obscuring those pesky details. A handle to a thing is often better than a pointer to a thing.

Thanks a lot for the response.

I think I laid out question wrong.

The CPUDescriptorHandle is the pointer, and nothing else:

//from d3d12.h

typedef struct D3D12_CPU_DESCRIPTOR_HANDLE
    {
    SIZE_T ptr;
    } 

And the work with descriptors in the every sample is by offseting that pointer by multiples of descriptor handle increment size for given type (SRV)

My questions are:

  1. Why the two calls CreateDescriptorHeap returns cpu descriptor handles with values 1,2 regardless of how many descriptors count they were created with? This behavior is observed on NVidia cards.
  2. The values in question 1. leads to overlapping descriptor heaps. Is only one heap allowed per type?
  3. Am I missing something?

Ok. I still don't get how NVidia works with handles …. (it probably uses pointer alignment to differentiate between multiple descriptor heaps), but I found out answer to question 2.

In DX before AgilitySDK (Windows version 1903 and lower) there is a bug in DX validation layer resulting in error “D3D12 Error: ID3D12Device::CopyDescriptors: Source ranges and dest ranges overlap, which results in undefined behavior” even for the valid ranges. It's quite hard to find any mentions about this.

Workaround is using InfoQueueFilter to filter out message CopyDescriptorsInvalidRanges from reporting.

Are you sure you are not getting errors when creating the heaps because they do normally return you a HR value so you can see fi soemthing went wrong.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

@NightCreature83 Thanks for reply.

I am sure. Everything works fine, doesn't return any errors until CopyDescriptors command which fails only on the old Windows 10 builds. The old bug in the validation layer was confirmed on official DirectX server https://discord.com/channels/590611987420020747/590965930658496690/1026865246381555742

So right now my problem is solved. There is not much information out there which you can find on google about this, so I hope this topic get indexed and it might save somebody some time in future.

And the only thing which remains is curiosity how the driver works with those odd descriptor pointers.

The descriptor handles are exactly that: they're handles, not pointers. They can be whatever value the driver wants as long as they respect the rules that let you offset them by the descriptor size. It might be efficient for the driver to use an actual pointer address for handles, or it might be more efficient for them to have a different value. Or maybe they don't want to hand apps an actual pointer that would make it easier for them to inspect or manipulate the actual descriptor data.

@MJP

Thanks you for explanation (and frob as well for similar explanation ), I understand that and I don't need to go deeper. I would not question the inner logic of those NVidia values in the first place if there wasn't for a above mention bug in validation layer.

This topic is closed to new replies.

Advertisement