bishopnator wrote: ↑Thu Feb 20, 2025 3:26 pm
Are the examples there outdated?
No, the example is just invalid. I'll rewrite it a little bit.
I was so preocuppied with making sure the example explains how RootLayouts work compared to D3D11 that I didn't realize the example was invalid.
The reason UAVs are in only in baked descriptors is because we need to do a lot of analysis that is better done baked.
And constant params cannot be in baked descriptors due to a couple mistakes early on (originally OgreNext 2.2 started being worked on while I got a few things wrong about Vulkan). Ideally, it should be possible.
If I split the UAVs description to e.g. mDescBindingRanges[1] and leave all other types in mDescBindingRanges[0] and also additionally set mBaked[1] to true, does it have any impact on HLSL (D3D11 RS) and GLSL (GL3Plus, but not Vulkan) shaders?
It should not have any impact.
I think I don't have to change anything in my shaders, right?
You don't, for D3D11 and OpenGL.
But for Vulkan we are using GLSL with a few macros defined by the RootLayout, and that would basically mean that either you write it by hand, or patch up the output from SPIRV-Cross to get what OgreNext wants.
so I am not very familiar with the reasons why the sets were introduced in the first place
The manual section you linked to explains the reasons. Basically Vulkan/D3D12 went away with the table model; and went for baking everything into a baked descriptor. i.e. from a low level perspective instead of D3D11 binding all 128 texture slots(\*):
(\*) This code is just to make a point. In reality drivers use heavy optimizations to send as little data as possible (i.e. they don't loop over all 128 slots every time a texture changes).
Code: Select all
for( int i = 0; i < D3D11_COMMONSHADER_CONSTANT_BUFFER_HW_SLOT_COUNT; ++i );
set_bind_to_gpu( i, const_buffers[i] );
for( int i = 0; i < D3D11_COMMONSHADER_INPUT_RESOURCE_REGISTER_COUNT; ++i )
set_bind_to_gpu( i, texture[i] );
Vulkan instead just sets a single pointer:
Code: Select all
set_bind_to_gpu( set_idx, baked_descriptor_set_ptr );
Our abstraction got this wrong, because our baked Descriptors aren't fully baked (we do as much early work as possible; but ultimately the Vulkan descriptor is uploaded every time it's bound; which is not the ideal practice).
Vulkan's idea is that if you're likely going to have a lot of resources that can be bound once, resources that rarely change (e.g. materials), and resources that need to change often (e.g. per-instance world matrices); so we are guaranteed at least 4 sets:
Code: Select all
set_bind_to_gpu( 0, descriptor_of_stuff_that_never_changes );
for each instance
if( instance->material_pool != last_pool )
set_bind_to_gpu( 1, instance->descriptors_with_materials );
set_bind_to_gpu( 2, instance->descriptors_with_instance_data );
If you still have questions, this article describes Vulkan's descriptor sets.
TL;DR: GPUs internally have up to 4 different ways in which their resources are bound; which means "which path is the optimal" is different depending on the HW model.
Root Layouts is not the only solution that can solve this; it is one of possibly many. However I'm quite happy with how Root Layouts ended up because it let us emulate the D3D11/GL model, the C++ code is in control (but optionally the shader can take control), it gives us a lot of predictability on CPU and memory consumption, and it allows many shaders to share the same descriptor signature.