DirectX12's terrible documenation -- some questions

Started by
8 comments, last by @alisonst 8 years, 5 months ago

Having only used OpenGL and read Mantle's documentation (which is excellent) before, I'm having a very hard time learning DirectX12. The documentation is almost nonexistent, some of it hyperlinks on accident to pages of an old preliminary versions that differs greatly, and in code examples they've done mistakes such as trying to call CreateConstantBufferView using a command list instead of a device. So not only is it very sparse, it's plain wrong. This may not seem like a big deal to some since it's easily caught, but it's very exhausting to have to deal with wrong documentation on top of sparse documentation.

Concepts are not explained at all which makes learning the API very exhausting. You have to remember the whole API without understanding it, and try to interpret what it is you're supposed to do based on how the API has been layed out and based on what little has been said. It would be great if someone put in the time to create a short tutorial explaining concepts such as ConstantBufferViews which aren't even mentioned in the documentation except for acknowledging its existence. Some knowledge can be gained from DirectX11 which has better resources online, but not everything.

Therefore I'm hoping to use this thread to get answers to a few questions I have now and questions I may have later. Here are my questions:

1) What are the differences between Shader Resource Views and Constant Buffer Views?

2) What are the different ways for uploading data to the GPU and does the recommended manner differ based on usage patterns?

Thanks.

Advertisement

The D3D12 documentation definitely assumes quite a bit of familiarity with D3D11. This is very much by design, so I understand you're frustrated about this. It's also very true that there are still quite a few errors throughout the docs; I'm sure most of these will get resolved soon.

As for your questions:

D3D has the concept of views, which you can see as an 'interpretation' of a GPU resource for different stages in the shader pipeline. The concept of a view was very prevalent in D3D10 and D3D11, but in D3D12 it's all simplified down to descriptors, even though they still use the name 'view' here and there. You could compare constant buffers to uniform buffer objects in OpenGL. A shader resource view is a view for a resource which can be used by a shader stage, like a texture you sample in the pixel shader stage for example.

Uploading memory would generally work by creating an upload buffer or heap, mapping it (and keeping it mapped) and then copying data over. After that you can schedule a copy from your upload resource/heap to a resource or heap with different properties if need be. How you want to deal with the size of upload and destination heaps and their properties is all up to you and the requirements for your application. There's a bunch of trade-offs to be made which all have their uses in different scenarios, so there's no real one size fits all solution.

I gets all your texture budgets!

Thanks Radikalizm,

Though it's still a bit unclear to me when one would pick a CBV over a SRV as SRVs can reference buffers which presumably can be accessed in shaders. And if they can be accessed in shaders then it must be in a similar manner?

On a different note it's interesting to see the different approaches Mantle and DX12 have taken with memory management. Both seem to have the concept of preferred memory pools because in the DX12 heap properties, the memory pool entry is named "MemoryPoolPreference". So it sounds to me like the driver makes the decision for you as it does in Mantle, though I'm not sure. However, only Mantle has you specify the priority of the heap which says how important it is to have the heap in the preferred memory pool vs having them in less preferred pools or all together paged out.

Then when you submit a Command List to a queue you have to specify all the heaps used so the driver can make sure they're resident. In DX12 however, everything is automatically resident unless you call Evict which suggests to the driver that he can, well.. Evict the memory.

It seems to me that you have more control with the DirectX API whereas Mantle holds your hand a bit and helps you (or forces you) to have a page-out friendly implementation. That's my newbie take on the matter and it may be wrong. In any case it's interesting to learn two such APIs and their differences because it helps you recognize what decisions the driver developers have decided to handle for you, versus what decisions were made simply to fit modern GPU hardware. Both approaches are interesting and I look forward to seeing what Vulkan will do.


Though it's still a bit unclear to me when one would pick a CBV over a SRV as SRVs can reference buffers which presumably can be accessed in shaders. And if they can be accessed in shaders then it must be in a similar manner?

This is a good question. Yes you can put data you would typically put in a constant buffer in a structured buffer and then bind an SRV to the structured buffer and index it in your vertex shader. You would have to profile and see if one performs more optimally.

In the d3d11 days, I assumed constant buffers were distinguished in that they were designed for changing a small amount of constants often (per draw call), and so had special optimizations for this usage, whereas a structured buffer would not be changed by the CPU very often and would be accessed more like a texture.

I'm not sure if future hardware will continue to make a distinction or if it is all the same.

-----Quat

This might be related:

http://www.yosoygames.com.ar/wp/2015/01/uniform-buffers-vs-texture-buffers-the-2015-edition/

I'm not terribly sure whats the difference between "shader storage buffer" (a "structured buffer" in D3Dland) and "texture buffer object". I mean, I know that TBOs uses samplers, texture cache and all of that, but it looks like both *could* be resolved the same way in the GPU, I'm not sure. If it is the case, the particulars noted in the article could be useful (typed buffer access vs untyped buffer access). Just in case, "uniform buffer" is a "constant buffer" in D3D.

I hope it helps. Maybe Mathias will pop in the discussion...

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

Though it's still a bit unclear to me when one would pick a CBV over a SRV


CBVs match the old "shader constants" paradigm. Shader constants are as their name indicates constants. They draw advantages of that fact and for example if they do not vary per shader "thread" you do not need to have a dedicated storage for each thread in hardware, instead all threads can refer to the same value in memory. (gpus could have a thousand "threads" executing in lock step all referring to the same "constant").

SRVs match the old "texture" paradigm. Textures are typically interpolated along the primitive (triangle..), which means their values vary per pixel thread (if you're writing a pixel shader). Each thread so then need to have their specific value loaded at execution which is a bit more involved. In addition textures require filtering, conversion, extra steps that constants do not have. So the pipeline involving textures is going to be a bit deeper (and may require more latency hiding effort). So if you fall closer to one preferred usage situation vs the other that will tell you if you should prefer "constants" or "textures".

Nowadays usage patterns can fall in between the two, in which case you may have to profile if it's a close call on paper between both choices.

This might be related:

http://www.yosoygames.com.ar/wp/2015/01/uniform-buffers-vs-texture-buffers-the-2015-edition/

I'm not terribly sure whats the difference between "shader storage buffer" (a "structured buffer" in D3Dland) and "texture buffer object". I mean, I know that TBOs uses samplers, texture cache and all of that, but it looks like both *could* be resolved the same way in the GPU, I'm not sure. If it is the case, the particulars noted in the article could be useful (typed buffer access vs untyped buffer access). Just in case, "uniform buffer" is a "constant buffer" in D3D.

I hope it helps. Maybe Mathias will pop in the discussion...

From an API perspective, shader storage buffer (aka SSBO, structured buffers) are very different from a texture buffer object (aka TBO). SSBOs can have read and/or write access, may alias to other objects (e.g. a structured buffer is read-only but turns out another variable points to the same memory and has write access; see restrict in C for an explanation of the same problem in CPUs) and are subject to less restrictions than TBOs (more relaxed alignment rules, unbounded indexing).

If it were C/C++, a TBO is more like a read-only array in the stack that may need lots of padding (an array that can be huge though... like 128MB huge) that is guaranteed to not alias with anything that has write access, while SSBOs is much more like a random pointer C with less padding/packing.

From a GCN arch point of view, there is virtually no difference between the two; however the shader compiler may produce better code with TBOs due to the strong assumptions enforced by the API (always read only, size may be known at compile time, doesn't alias with other variables that may have write access, the alignment restrictions can help avoiding bank conflicts, etc)

Needless to say from a historical point of view, lots of old GPUs couldn't do SSBOs (a feature introduced with DX11 hardware) but they could do TBOs (supported since the GeForce 8).

NVIDIA has now also published it's three-part series of "recommended practices" in Structured Buffers. Note that alignment still plays a vital role with SSBOs, but now you have to pad your objects explicitly, whereas TBOs forced the padding (e.g. either you performed two fetches of RGBA_FLOAT32, or avoid padding with 6 fetches of R_FLOAT32.).

Also on the above -- GL SSBO != D3D structured buffer.
GL SSBO ~= D3D UAV(C++) / RW******(HLSL)
i.e. StructuredBuffer is a SRV (Texture Buffer in GL), but RWStructuredBuffer is a UAV (SSBO in GL).

Though it's still a bit unclear to me when one would pick a CBV over a SRV as SRVs can reference buffers which presumably can be accessed in shaders. And if they can be accessed in shaders then it must be in a similar manner?

CBV is designed for cases when every pixel/etc will need to consume all of the data present in the buffer.
SRV is designed for cases when each pixel/etc will consume different parts of the data present in the buffer.
Basically:
* Constant access for all threads -> constant buffer.
* Random access -> buffer.

As mentioned in the link above, AMD (usually) doesn't actually perform any optimizations based on these assumptions any more -- they're both just buffers (except in a few rare cases under D3D11, where small cbuffers can be optimized as magic uniform data). However, I think Nvidia still does perform some extra optimizations when it knows that a buffer contains uniforms/constants.

Also mentioned in that link -- the descriptor sizes for all the different buffer/texture types can be quite different.

1) What are the differences between Shader Resource Views and Constant Buffer Views?

2) What are the different ways for uploading data to the GPU and does the recommended manner differ based on usage patterns?

Re #1: Take a look at Amar's binding tutorial on our official DirectX YT channel: https://www.youtube.com/playlist?list=PLeHvwXyqearVU8fvo2Oq7otKDlLLDAaHW fo

Re #2: We are hoping to post a video soon relating to #2 on the channel as well soon. I'll let you know when we do.

We've posted the video, which should answer your question #2, FrozenS, on our YouTube channelhttps://www.youtube.com/MicrosoftDirectX12andGraphicsEducation, and the direct link is

. I've attached the text file that Brian provided as a cheat sheet as well.

Ta.

This topic is closed to new replies.

Advertisement