• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Jason Smith
      While working on a project using D3D12 I was getting an exception being thrown while trying to get a D3D12_CPU_DESCRIPTOR_HANDLE. The project is using plain C so it uses the COBJMACROS. The following application replicates the problem happening in the project.
      #define COBJMACROS #pragma warning(push, 3) #include <Windows.h> #include <d3d12.h> #include <dxgi1_4.h> #pragma warning(pop) IDXGIFactory4 *factory; ID3D12Device *device; ID3D12DescriptorHeap *rtv_heap; int WINAPI wWinMain(HINSTANCE hinst, HINSTANCE pinst, PWSTR cline, int cshow) { (hinst), (pinst), (cline), (cshow); HRESULT hr = CreateDXGIFactory1(&IID_IDXGIFactory4, (void **)&factory); hr = D3D12CreateDevice(0, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, &device); D3D12_DESCRIPTOR_HEAP_DESC desc; desc.NumDescriptors = 1; desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; desc.NodeMask = 0; hr = ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, (void **)&rtv_heap); D3D12_CPU_DESCRIPTOR_HANDLE rtv = ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_heap); (rtv); } The call to ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart throws an exception. Stepping into the disassembly for ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart show that the error occurs on the instruction
      mov  qword ptr [rdx],rax
      which seems odd since rdx doesn't appear to be used. Any help would be greatly appreciated. Thank you.
    • By lubbe75
      As far as I understand there is no real random or noise function in HLSL. 
      I have a big water polygon, and I'd like to fake water wave normals in my pixel shader. I know it's not efficient and the standard way is really to use a pre-calculated noise texture, but anyway...
      Does anyone have any quick and dirty HLSL shader code that fakes water normals, and that doesn't look too repetitious? 
    • By turanszkij
      I finally managed to get the DX11 emulating Vulkan device working but everything is flipped vertically now because Vulkan has a different clipping space. What are the best practices out there to keep these implementation consistent? I tried using a vertically flipped viewport, and while it works on Nvidia 1050, the Vulkan debug layer is throwing error messages that this is not supported in the spec so it might not work on others. There is also the possibility to flip the clip scpace position Y coordinate before writing out with vertex shader, but that requires changing and recompiling every shader. I could also bake it into the camera projection matrices, though I want to avoid that because then I need to track down for the whole engine where I upload matrices... Any chance of an easy extension or something? If not, I will probably go with changing the vertex shaders.
    • By NikiTo
      Some people say "discard" has not a positive effect on optimization. Other people say it will at least spare the fetches of textures.
      if (color.A < 0.1f) { //discard; clip(-1); } // tons of reads of textures following here // and loops too
      Some people say that "discard" will only mask out the output of the pixel shader, while still evaluates all the statements after the "discard" instruction.

      discard: Do not output the result of the current pixel.
      clip: Discards the current pixel..

      As usual it is unclear, but it suggests that "clip" could discard the whole pixel(maybe stopping execution too)

      I think, that at least, because of termal and energy consuming reasons, GPU should not evaluate the statements after "discard", but some people on internet say that GPU computes the statements anyways. What I am more worried about, are the texture fetches after discard/clip.

      (what if after discard, I have an expensive branch decision that makes the approved cheap branch neighbor pixels stall for nothing? this is crazy)
    • By NikiTo
      I have a problem. My shaders are huge, in the meaning that they have lot of code inside. Many of my pixels should be completely discarded. I could use in the very beginning of the shader a comparison and discard, But as far as I understand, discard statement does not save workload at all, as it has to stale until the long huge neighbor shaders complete.
      Initially I wanted to use stencil to discard pixels before the execution flow enters the shader. Even before the GPU distributes/allocates resources for this shader, avoiding stale of pixel shaders execution flow, because initially I assumed that Depth/Stencil discards pixels before the pixel shader, but I see now that it happens inside the very last Output Merger state. It seems extremely inefficient to render that way a little mirror in a scene with big viewport. Why they've put the stencil test in the output merger anyway? Handling of Stencil is so limited compared to other resources. Does people use Stencil functionality at all for games, or they prefer discard/clip?

      Will GPU stale the pixel if I issue a discard in the very beginning of the pixel shader, or GPU will already start using the freed up resources to render another pixel?!?!

  • Advertisement
  • Advertisement
Sign in to follow this  

DX12 Descriptor binding: DX12 and Vulkan

This topic is 696 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been reading up on how the resource binding methods work in Vulkan and DX12. I'm trying to figure out how to best design an API that abstracts the two with respect to binding descriptors to the pipeline. Naturally, the two API's are similar, but I'm finding that they treat descriptor binding differently in subtle ways.


Disclaimer: Skip to the bottom if you have a deep understanding of this already and just care about my specific question.




In DirectX, you define a "root signature". It can have push constants, inlined descriptors binding points, or descriptor table binding points. It also defines static samples on the signature itself. A descriptor table is a contiguous block of descriptors within a descriptor heap. Binding a table involves specifying the first descriptor in the heap to the pipeline. Tables can hold either UAV/SRV/CBV descriptors or SAMPLER descriptors. You cannot share the two within a single heap--and therefore table. Descriptor tables are also organized into ranges, where each range defines one or more descriptors of a SINGLE type.


Root Signature Example:



Descriptor Heap indirection:




In Vulkan, you define a "pipeline layout". It can have push constants and "descriptor set" binding points. You cannot define inlined descriptors binding points. Each descriptor set defines a set of static samplers. A descriptor set is a first class object in Vulkan. It also has one or more ranges of a SINGLE descriptor type.




Descriptor Sets:




Now, an interesting pattern I'm seeing is that the two API's provide descriptor versioning functionality for completely different things. In DirectX, you can version descriptors implicitly within the command list using the root descriptor bindings. This allows you to do things like specify a custom offset for a constant buffer view. In Vulkan, they provide an explicit UNIFORM_DYNAMIC descriptor type that allows you to version an offset into the command list. See the image below:







Okay, so I'm really just looking for advice on how to organize binding points for an API that wraps these two models.


My current tentative approach is to provide an API for creating buffers and images, and then explicit UAV/SRV/CBV/RTV/DSV views into those objects. The resulting view is an opaque, typeless handle on the frontend that can map to descriptors on DirectX 12 or some staging resource in Vulkan for building descriptor sets.


I think I want to provide an explicit "ResourceSet" object that defines 1..N ranges of views similar to how both the descriptor set and descriptor table models work. I expect that I would make sampler binding a separate API that does its own thing for the two backends. I would really like to treat these ResourceSet objects similar to constant buffers, except that I'm just writing view handles into it.


I need to figure out how to handle versioning of updates to these descriptor sets. In the simplest case, I treat them as fully static. This maps well to both DX12 and Vulkan because I can simply allocate space in a descriptor heap or create a descriptor set, write the descriptors to it, and I'm done.


Handling dynamic updates becomes complicated for both API's and this is the crux of where I'm struggling right now.


Both APIs let me push constants, so that's not really a problem. However, DirectX allows you to version descriptors directly in the command list, but Vulkan allows you to dynamic offsets into buffers. It seems like this is chiefly for CBVs.


So it seems like if I want to do something like have a descriptor set with 3 CBV's, and then do dynamic offsets, I have to explicitly version the entire table in DirectX by allocating some new space in the heap and spilling descriptors to it.


On the other hand, since Vulkan doesn't really have the notion of root descriptors, I'd have to create multiple descriptorset objects and version those out if I want to bind a single dynamic UAV.


Either way, it seems like the preferred model is to build static descriptor sets but provide some fast path for constant buffers, and that's the direction I think I'm going to head in.


Anyway, does this sound like a sane approach? Have you guys find better ways to abstract these two binding models?


Side question: How do you version descriptor sets in vulkan? Do you just have to pool descriptor sets for the frame and spill when updates occur?



Edited by ZBethel

Share this post

Link to post
Share on other sites

Somehow there are no replies, but I find this topic interesting and followed the link. Maybe this should be moved into the Vulkan forum. As I program mostly in C# right now I would like to see how an API for Vulkan/DX12 would look different. In C# I acquire resources by using using{  and release them with } . The compiler then just stacks up resources. Vulkan/DX12 seem to do more.

Didn't we have the topic data-structures recently? Somehow I feel that one does not need two APIs, but two scene graph compilers.

Share this post

Link to post
Share on other sites

I'm also curious to hear how people are starting to take a crack at this.

Share this post

Link to post
Share on other sites

If I understood the question correctly, you are asking about updating descriptor sets / descriptor tables contents. IMO, by these APIs desing this should be avoided, because when you call vkUpdateDescriptorSets/CreateConstantBufferView/etc. you must ensure that GPU is not using this descriptor (you must use fences in this case). I would create multiple descriptor set copies of the same layout (or reserve more space in descriptor heap in case of D3D12) and update these when they are not used by GPU at the moment. In case of double frame buffering - two copies should be fine.

Share this post

Link to post
Share on other sites

I've been thinking more about this, and I've come to realize some things.


I did some investigation into how some real workloads are handling the root signature. I found that a vast majority of what I saw have a structure similar to this:


DX12 style binding slots:


For bucketed scene draws:


0: Some push constants

1: per draw constant buffer

2: per pass constant buffer

3: per material constant buffer

4: A list of SRVs


For various post processing jobs:


0+ constant buffers

simple table of UAVs

simple table of SRVs


I didn't find any use cases where different regions of the same descriptor table were used for different stuff... for the most part is seems a simple list of SRVs / UAVs is enough.


I also realized that Vulkan has the strong notion of a render pass, and that UAVs could be factored into render passes as outputs (which are then transitioned to SRVs).


To me, it seems like having constant buffer binding slots, a way to bind a list of SRVs to the draw call, and a way to bind a list of UAVs to a render pass is enough to support most scenarios.


With regards to list allocation, it seems like descriptor layouts are going to be bounded by the application. Like you said, Witek902, you could just create a free list pool for descriptors and orphan them on update into a recycle queue. Static descriptor sets just get allocated once and held.


For DX12, you could model that same technique by allocating fixed size pieces out of a descriptor heap, or use some sort of buddy allocator. With the descriptor heap approach it becomes a bit weirder because it seems the ideal use case scenario is to keep the same heap bound for the whole frame.


I also read in Gpu Fast Paths that using dynamic constant buffers eats up 4 registers of the USER-DATA memory devoted to the pipeline layout. Apparently using a push constant to offset into a big table is more performant (I'm not sure how portable this is to platforms like mobile). 


Anyway, just some thoughts.

Edited by ZBethel

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement