我可以在不将图像绑定到该绑定点的情况下在 Vulkan 中创建不可变采样器吗?

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

我一直在阅读 Vulkan 规范和 Khronos 的一些示例,但我找不到很多关于不可变采样器的一般信息。

我想要做的是拥有一个充满不可变采样器(VK_DESCRIPTOR_TYPE_SAMPLER 类型,而不是...COMBINED_IMAGE_SAMPLER)的描述符集,当我想对纹理进行采样时,我在我的着色器中像这样访问采样器:

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;
}

使用此着色器的想法是:

但是,我在 Khronos 示例中看到的方式是:

在 Vulkan 规范中,它没有说明哪种方式 "correct" 只是指出:

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.

现在,如果我的着色器按照我预期的方式工作,我就不会问这个问题了。我 运行 遇到的问题是,在验证时,Vulkan 层抱怨我的 VkPipeline 正在使用从未绑定过的描述符集(设置 0,在采样器所在的位置绑定 0)!即使我在那里绑定垃圾数据,我仍然必须(至少一次)用垃圾更新描述符集,以抑制另一个验证错误。然而与此同时,Vulkan 规范说:

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

因此甚至不允许将数据绑定到该绑定点!

我现在非常不确定我的不可变采样器方法是否应该有效,因为它有点模棱两可。规范说我可以绑定一个没有图像的采样器,但当我这样做时会抱怨,我发现的几个例子是绑定一个组合图像采样器。我只是做错了吗?

如果我的方法应该有效并且可以工作,我真的很喜欢这样,因为我正在尝试为 DirectX 12 和 Vulkan 构建一个系统。 DX12 在其 "root layout"(流水线布局)中有一席之地,所有不可变采样器都被绑定,而没有与之关联的图像。我想模仿这种行为以保持渲染器之间的奇偶校验,但我非常不确定 Vulkan 是否真的可以做到这一点,而且它在规范中非常模糊。

你想做的事是完全可能和合法的。您遇到的问题是由于您对 Vulkan 规范没有说明的事情所做的假设。您正在创建不存在的含义。

I am not binding any descriptor set to set 0 in this example because there is nothing to bind, right?

错了。

您在此处所做的假设是不可变采样器描述符驻留在 管道对象中。他们没有,Vulkan 规范从未声称他们有。

哦,是的,管道对象被赋予描述符布局,其中包含不可变的采样器。因此,在构造对 texture 函数的调用时,允许实现使用该不可变采样器数据。

但是描述符 data 不在管道中。它存在于描述符集中。

Vulkan 规范在这一点上没有歧义。如果管线的布局包含描述符集,并且着色器在执行时使用该集,则必须有一个在执行时绑定的描述符集,它与该集索引的管线布局兼容。

该实现是否真的会从不可变采样器描述符中获取数据?那些不可变的描述符实际上会将数据存储在描述符内存中,还是会将数据存储在管道中?谁在乎; Vulkan 规范说所有使用的描述符都需要绑定。

这条规则没有例外。

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" 表示调用 vkUpdateDescriptorSets。该函数更新各种集合中描述符中的数据。但它只会更新您为其选择的数据。

此外,如果您尝试更新不可变采样器的采样器,它将忽略 pImageInfosampler 的值。这是由标准指定的(尽管是倾斜的):

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.

添加了重点。

既然存在条件,那么如果描述符绑定使用不可变采样器,sampler 将被忽略。毕竟,您可以将不可变采样器与 image/samplers 结合使用。在这种情况下,pImageInfo 中的 sampler 忽略。

这并不意味着这些描述符没有内容;您只是不允许 更改 它们。您可以在仅包含不可变采样器的描述符集上调用 vkUpdateDescriptorSets;它什么也做不了。

但是你还是得分配和使用这样的一套。

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.

那就是验证层的一个bug。你应该报告它。

Vulkan 规范中没有任何内容表明在使用集合之前必须更新集合中的所有描述符。

要关闭错误验证层,请随意使用 vkUpdateDescriptorSets 验证构建。不要费心传递有效的 sampler 句柄,因为它实际上不会做任何事情。