I've been reading over the Vulkan spec and some examples from Khronos but I can't find a lot of information on Immutable Samplers in general.
What I'm trying to do is have a descriptor set full of immutable samplers (of type VK_DESCRIPTOR_TYPE_SAMPLER, not ...COMBINED_IMAGE_SAMPLER) and when I want to sample a texture, I access the sampler like this in my shader:
layout (location = 0) out vec4 out_color;
layout (set = 0, binding = 0) uniform sampler immutableSampler;
layout (set = 3, binding = 0) uniform texture2D color;
void main()
{
vec4 textureColor = texture(sampler2D(color, immutableSampler), in_uv);
out_color = textureColor;
}
With this shader the idea is:
sampler2D
However, the way I've seen it done in the Khronos sample is:
sampler2D
in the shader; the image you've bound is paired with the immutable sampler at that bindingIn the Vulkan spec it does not say which way is "correct" only noting that:
If
descriptorType
specifies aVK_DESCRIPTOR_TYPE_SAMPLER
orVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
type descriptor, thenpImmutableSamplers
can be used to initialize a set of immutable samplers.
Now if my shader just worked the way I expected I wouldn't be asking this question. The problem I'm running into is that upon validation the Vulkan layers complain that my VkPipeline is using a descriptor set (set 0, binding 0 where the sampler lives) which has never been bound! Even if I bind garbage data there I'm still going to have to (at least once) update the descriptor set with garbage just to suppress another validation error. However at the same time the Vulkan spec says:
Immutable samplers are permanently bound into the set layout; later binding a sampler into an immutable sampler slot in a descriptor set is not allowed
So binding data to that bind point wouldn't even be allowed!
I'm very unsure right now whether my approach to immutable samplers is even supposed to be valid as it's sort of ambiguous. The spec says I can bind a Sampler without an image but complains when I do and the few examples I've found are binding a Combined Image Sampler. Am I just doing this wrong?
If my approach is supposed to be valid and could work I'd really like that as I'm trying to architect a system for both DirectX 12 and Vulkan. DX12 has a place in its "root layout" (pipeline layout) where ALL immutable samplers are bound without images associated with them. I'd like to emulate this behavior to keep parity between the renderers but I'm very unsure if that's really possible with Vulkan and it's very ambiguous in the spec.
What you want to do is entirely possible and legitimate. The problems you're encountering are due to assumptions you're making about things that the Vulkan specification is not saying. You're creating implications that aren't there.
I am not binding any descriptor set to set 0 in this example because there is nothing to bind, right?
Wrong.
The assumption you're making here is that immutable sampler descriptors reside in the pipeline object. They don't, and the Vulkan specification never claims that they do.
Oh yes, the pipeline object is given the descriptor layout, which contains the immutable samplers. And therefore, an implementation is allowed to use that immutable sampler data when constructing calls to texture
functions.
But descriptor data doesn't live in the pipeline. It lives in descriptor sets.
The Vulkan specification has no ambiguity on this point. If a pipeline's layout contains a descriptor set, and the shader uses that set at execution time, then there must be a descriptor set bound at execution time which is layout-compatible with the pipeline layout for that set index.
Will the implementation actually fetch data from an immutable sampler descriptor? Will those immutable descriptors actually store data in descriptor memory, or will they store the data in the pipeline? Who cares; the Vulkan specification says that all used descriptors need to be bound.
There are no exceptions to this rule.
But there are other issues with that; set 0, binding 0 is a Sampler but the spec clearly says I should not bind a Sampler there.
"bind a Sampler" would mean calling vkUpdateDescriptorSets
. That function updates the data in the descriptors in various sets. But it only updates the data you choose for it to.
Furthermore, if you try to update the sampler of an immutable sampler, it will ignore the value of sampler
in pImageInfo
. This is specified by the standard (though obliquely):
sampler
is a sampler handle, and is used in descriptor updates for typesVK_DESCRIPTOR_TYPE_SAMPLER
andVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
if the binding being updated does not use immutable samplers.
Emphasis added.
Since that conditional is there, then sampler
will be ignored if the descriptor binding uses immutable samplers. After all, you can use immutable samplers with combined image/samplers. The sampler
in pImageInfo
would have to be ignored in such cases.
That doesn't mean these descriptors don't have contents; you're just not allowed to change them. You can call vkUpdateDescriptorSets
on a descriptor set that contains only immutable samplers; it just won't do anything.
But you still have to allocate and use such a set.
If I bind a descriptor set and don't update it though I'd be hitting another error in validation so I'd need to bind it with some sort of data to avoid that.
Then that is a bug in the validation layer. You should report it.
There is nothing in the Vulkan specification that says that all of the descriptors in a set must be updated before the set can be used.
To shut the buggy validation layer up, feel free to use vkUpdateDescriptorSets
in validating builds. Don't bother passing valid sampler
handles, since it won't actually do anything.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With