我可以在Vulkan中创建一个不可变采样器而不将图像绑定到该绑定点吗?

Hon*_*nch 5 graphics vulkan

我一直在阅读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;
}
Run Code Online (Sandbox Code Playgroud)

使用此着色器的想法是:

  • 在管道布局中,我在集合0中的绑定点0处有一个不可变的采样器
  • 我还有一个描述符集(3),其中包含在绑定点0描述的图像,我将其作为命令缓冲区的一部分进行绑定
  • 我将不可变采样器应用于着色器中的图像
  • 然后实际访问图像为 sampler2D

但是,我在Khronos样本中看到它的方式是:

  • 在管道布局中的绑定点描述VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER的不可变采样器(仅提供采样器)
  • 创建一个图像并将其绑定到同一个绑定点(没有采样器)
  • sampler2D在着色器中以图像形式访问图像; 您绑定的图像与该绑定的不可变采样器配对

在Vulkan规范中,它没有说明哪种方式是"正确的"只注意到:

如果descriptorType指定了一个VK_DESCRIPTOR_TYPE_SAMPLERVK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER类型描述符,那么pImmutableSamplers可以用来初始化一组不可变的采样器.

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

不可变采样器永久地绑定到集布局中; 稍后将采样器绑定到描述符集中的不可变采样器槽中是不允许的

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

我现在很不确定我对不可变采样器的处理方法是否应该是有效的,因为它有点含糊不清.规范说我可以在没有图像的情况下绑定一个采样器,但是当我这样做时会抱怨,而我发现的几个例子都是绑定一个组合图像采样器.我这样做错了吗?

如果我的方法应该是有效的并且可以工作,我真的很喜欢,因为我正在尝试为DirectX 12和Vulkan构建一个系统.DX12在其"根布局"(管道布局)中占有一席之地,其中所有不可变采样器都被绑定而没有与它们相关联的图像.我想模仿这种行为以保持渲染器之间的平等,但我不确定是否真的可以使用Vulkan并且它在规范中非常模糊.

Nic*_*las 9

你想要做的是完全可能和合法的.您遇到的问题是由于您对Vulkan规范未提及的事情所做的假设.你正在创造那些不存在的含义.

在这个例子中,我没有绑定任何描述符集来设置0,因为没有什么可以绑定,对吧?

错误.

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

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

但描述符数据并不存在于管道中.它存在于描述符集中.

Vulkan规范在这一点上没有含糊之处.如果管道的布局包含描述符集,并且着色器在执行时使用该集合,那么必须在执行时绑定一个描述符集,该描述符集与该集合索引的管道布局兼容.

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

这条规定没有例外.

但是还有其他问题; 设置0,绑定0是一个采样器,但规范清楚地说我不应该在那里绑定一个采样器.

"绑定采样器"意味着呼叫vkUpdateDescriptorSets.该函数以各种集合更新描述符中的数据.但它只会更新您选择的数据.

此外,如果您尝试更新不可变采样器的采样器,它将忽略samplerin 的值pImageInfo.这由标准规定(虽然倾斜):

sampler是一个采样器句柄,用于类型的描述符更新VK_DESCRIPTOR_TYPE_SAMPLER,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER 如果更新的绑定不使用不可变采样器.

强调补充说.

由于那个条件存在,sampler如果描述符绑定使用不可变采样器,则将被忽略.毕竟,您可以将不可变采样器与组合图像/采样器一起使用.将samplerpImageInfo具有在这种情况下被忽略.

这并不意味着这些描述符不具有的内容; 你不能改变它们.您可以调用vkUpdateDescriptorSets仅包含不可变采样器的描述符集; 它不会做任何事情.

但你仍然需要分配和使用这样的一套.

如果我绑定一个描述符集并且不更新它,虽然我在验证中遇到另一个错误,所以我需要将它与某种数据绑定以避免这种情况.

那是验证层中的一个错误.你应该报告它.

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

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