如何使用具有非标准化纹理坐标的 vulkan 采样器? 不触发 VUID-vkCmdDrawIndexed-None-02703

问题描述

所以我一直在我的纹理采样器中使用非标准化坐标,因为我发现在将纹理用作精灵图集时更容易处理纹理的某些部分。今天,我修补了我的工作站并重新编译了所有内容,验证层开始报告此错误

验证错误:[VUID-vkCmdDrawIndexed-None-02703] 对象 0: 句柄 = 0x210000000021,类型 = VK_OBJECT_TYPE_DESCRIPTOR_SET;目的 1:句柄 = 0x1c000000001c,类型 = VK_OBJECT_TYPE_IMAGE_VIEW;目的 2:句柄=0x1f000000001f,类型=VK_OBJECT_TYPE_SAMPLER; |消息ID = 0x30c87f64 | VkDescriptorSet 0x210000000021[] 在 vkCmdDrawIndexed() 时遇到以下验证错误:VkImageView 0x1c000000001c[] 在绑定#0 索引 0 的描述符中被使用 使用无效运算符的 VkSampler 0x1f000000001f[]。 Vulkan 规范 状态:如果 VkPipeline 对象绑定到使用的管道绑定点 通过此命令访问使用非规范化的 VkSampler 对象 坐标,该采样器不得与任何 SPIR-V 一起使用 带有 ImplicitLod 的 OpImageSample* 或 OpImageSparseSample* 指令, Dref 或 Proj 以他们的名字命名,在任何着色器阶段 (https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-vkCmdDrawIndexed-None-02703)

我知道在使用非标准化纹理坐标(例如无 mipmap 或各向异性)时存在各种限制。这是规范中的(我认为)相关部分: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkSamplerCreateInfo.html

unnormalizedCoordinates 控制是否使用非规范化或 归一化的纹素坐标以寻址图像的纹素。设置时 到 VK_TRUE,用于查找图像坐标的范围 texel 的范围是从零到 x、y 和 z 的图像尺寸。 当设置为 VK_FALSE 时,图像坐标范围为 0 到 1。

当 unnormalizedCoordinates 为 VK_TRUE 时,使用采样器的图像 与在着色器中有以下要求:

The viewType must be either VK_IMAGE_VIEW_TYPE_1D or VK_IMAGE_VIEW_TYPE_2D.
The image view must have a single layer and a single mip level.

当 unnormalizedCoordinates 为 VK_TRUE 时,图像内置函数在 使用采样器的着色器有以下要求:

The functions must not use projection.
The functions must not use offsets.

我满足所有这些要求,除非“投影”和“偏移”意味着“渲染纹理期间发生的事情”。

如果是这种情况,并且在渲染部分纹理时不能使用未归一化的纹理坐标,则: 我不明白这个功能是干什么用的。 在哪里以及为什么要使用非规范化的纹理坐标?此外,许多教程会像下面这样“误导”: https://vulkan-tutorial.com/en/Texture_mapping/Image_view_and_sampler

unnormalizedCoordinates 字段指定了哪个坐标系 您想用来处理图像中的纹素。如果这个字段是 VK_TRUE,那么你可以简单地使用 [0,texWidth) 内的坐标 和 [0,texHeight) 范围。如果是 VK_FALSE,则纹素为 在所有轴上使用 [0,1) 范围寻址。实际应用 几乎总是使用归一化坐标,因为那是可能的 使用具有完全相同分辨率的不同分辨率的纹理 坐标。

这(仅作为示例)听起来像是个人偏好,而不是“方法 a 有效,方法 b 只能在特殊情况下使用,很可能不是什么你要”。确实 --> 当我将样本更改为使用非标准化纹理坐标时,会报告相同的验证错误。那么有人可以解释一下这里发生了什么吗?

谢谢!

解决方法

在着色器中,使用纹理(sampler2D,uv)访问纹理

好吧,这就是你的问题。 GLSL 是针对 OpenGL 而不是 Vulkan 编写的。因此,它不知道 Vulkan 允许而 OpenGL 通常不允许的一些事情。在 OpenGL 中,texture 函数始终使用归一化纹理坐标。唯一不会出现的情况是您使用 rectangle textures,它是与 2D 纹理不同的纹理类型。它们是没有 Vulkan 模拟的 OpenGL 功能,因为在 Vulkan 中,您可以将任何纹理视为“矩形纹理”(“矩形纹理”的唯一真正特征是您可以对它们使用非规范化的纹理坐标)。

我在 GL_KHR_vulkan_glsl extension 中没有看到允许 texture 函数使用非标准化纹理坐标的机制。因此,您必须找到另一种生成 SPIR-V 的方法,否则您需要直接编写 SPIR-V。

,

这是 Khrono 论坛上的帖子的重复,unnormalized texture coords here 上有一个未解决的问题。

任何形式的调用:

 vec4 val = texture( unormSampler,pixelCoord );

其中 unormSampler 包含非规范化采样器导致 SPIR-V 操作码 87,即指令 OpImageSampleImplicitLod。 vulkan 规范(如您所见)明确排除了针对任何非规范化纹理读取的此指令。

然而:

SPIR-V 操作码 88 是非规范化王国的秘密密钥。 OpCode 88 指令是 OpImageSampleExplicitLod。在 Vulkan 规范中的任何地方都没有列出(据我所知)这是使用非规范化采样器的非法操作。

映射到操作码 88 的秘密 GLSL 指令是 textureLod。这是使用它的代码示例。

// Set this up just like usual,except use a unnormalized sampler
layout(binding = 23) uniform sampler2D unormSampler;

void main()
{
    vec4 val = textureLod( unormSampler,pixelCoord,0); // 0 is the mipmap level to sample from
}

我没有尝试其他 mipmap 级别(我依稀记得 Vulkan 规范说没有带有非规范化坐标的 mipmap。

我确实为样本尝试了 VK_FILTER_LINEAR 和 VK_FILTER_NEAREST,它们都按预期工作。 (我的测试有使用 VK_FILTER_NEAREST 时出现的工件)

以下是不适用于 GLSL、Vulkan 和非标准化采样器的列表:

  1. 使用 sampler2Drect – 加载 SPIR-V 模块时产生错误
  1. 使用任何版本的纹理(blablabla); – 导致操作码 87,这是 Vulkan 规范中的“否”

  2. 使用 samplerBuffer - 规范再次对非标准化采样器说不