Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I create an Immutable Sampler in Vulkan without binding an image to that bind point?

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:

  • In the pipeline layout I have an immutable sampler at binding point 0 in set 0
  • I also have a descriptor set (3) with an image described at binding point 0 which I bind as part of my command buffer
  • I apply the immutable sampler to the image in the shader
  • Then actually access the image as a sampler2D

However, the way I've seen it done in the Khronos sample is:

  • Describe an immutable sampler of VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER at a bind point in the pipeline layout (providing only the sampler)
  • Create an image and bind it to the same binding point (without a sampler)
  • Access the image as a sampler2D in the shader; the image you've bound is paired with the immutable sampler at that binding

In the Vulkan spec it does not say which way is "correct" only noting that:

If descriptorType specifies a VK_DESCRIPTOR_TYPE_SAMPLER or VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER type descriptor, then pImmutableSamplers 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.

like image 564
Honeybunch Avatar asked May 02 '16 15:05

Honeybunch


1 Answers

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 types VK_DESCRIPTOR_TYPE_SAMPLER and VK_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.

like image 169
Nicol Bolas Avatar answered Sep 30 '22 12:09

Nicol Bolas