4

I have troubles figuring out any use case for VkDescriptorSetLayoutBinding::binding, here is the struct :

struct VkDescriptorSetLayoutBinding 
{
    uint32_t              binding;
    VkDescriptorType      descriptorType;
    uint32_t              descriptorCount;
    VkShaderStageFlags    stageFlags;
    const VkSampler*      pImmutableSamplers;
};

used here to create a DescriptorSetLayout :

struct VkDescriptorSetLayoutCreateInfo 
{
    VkStructureType                        sType;
    const void*                            pNext;
    VkDescriptorSetLayoutCreateFlags       flags;
    uint32_t                               bindingCount;
    const VkDescriptorSetLayoutBinding*    pBindings;
};

I was wondering why the "binding" variable is not deduced from the index in the pBindings array. After some research I found that the vulkan specs says :

The above layout definition allows the descriptor bindings to be specified sparsely such that not all binding numbers between 0 and the maximum binding number need to be specified in the pBindings array. Bindings that are not specified have a descriptorCount and stageFlags of zero, and the value of descriptorType is undefined. However, all binding numbers between 0 and the maximum binding number in the VkDescriptorSetLayoutCreateInfo::pBindings array may consume memory in the descriptor set layout even if not all descriptor bindings are used, though it should not consume additional memory from the descriptor pool.

I can't find in which case you can use those sparsed bindings, why would you leave an empty unused space ?

Nowine
  • 166
  • 8

1 Answers1

3

Binding indices are hard-coded into shaders (you can define binding indices via specialization constants, but otherwise, they're part of the shader code). So let's imagine that you have the code for a shaders stage. And you want to use it in two different pipelines (A and B). And let's say that the descriptor set layouts for these pipelines are not meant to be compatible; we just want to reuse the shader.

Well, the binding indices in your shader didn't change; they can't change. So if this shader has a UBO in binding 3 of set 0, then any descriptor set layout it gets used with must have a UBO in binding 3 of set 0.

Maybe in pipeline A, some shader other than the one we reuse might use bindings 0, 1, and 2 from set 0. But what if none of the other shaders for pipeline B need binding index 2? Maybe the fragment shader in pipeline A used 3 descriptor resources, but the one in pipeline B only needs 2.

Having sparse descriptor bindings allow you to reuse compiled shader modules without having to reassign the binding indices within a shader. Oh yes, you have to make sure that all such shaders are compatible with each other (that they don't use the same set+binding index in different ways), but other than that, you can mix-and-match freely.

And it should be noted that contiguous bindings has almost never been a requirement of any API. In OpenGL, your shader pipeline could use texture units 2, 40, and 32, and that's 100% fine.

Why should it be different for Vulkan, just because its resource binding model is more abstract?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Very clear, thanks. I found that less intuitive in Vulkan because everything is always very precisely setup for something in particular, whereas in OpenGL there is this big global context which serve for anything. – Nowine Aug 08 '19 at 03:07