为什么 VkShaderStageFlagBits 是位掩码?

Why is VkShaderStageFlagBits a bitmask?

在 Vulkan 中,您将 VkPipelineShaderStageCreateInfo 指定给 VkGraphicsPipelineCreateInfo 结构,并且大概每个着色器阶段(例如顶点,和片段着色器)。

那么为什么 stage 字段的类型是 vkShaderStageFlagBits 仅仅是因为它更接近某种 Vulkan 约定?

我的困惑是我被引导相信你会以这种方式使用位掩码的唯一原因是你是否需要将位组合在一起。 (例如,所有 Vulkan 结构中的通用 flags 字段)。我试图找到这个问题的答案,所以我查看了 Vulkan 规范,这让我更加困惑!这是因为它们有两个位 VK_SHADER_STAGE_ALL_GRAPHICSVK_SHADER_STAGE_ALL 它们被定义为:

VK_SHADER_STAGE_ALL_GRAPHICS is a combination of bits used as shorthand to specify all graphics stages defined above (excluding the compute stage).

VK_SHADER_STAGE_ALL is a combination of bits used as shorthand to specify all shader stages supported by the device, including all additional stages which are introduced by extensions.

好吧,如果它们应该是“shorthand”来指定所有位,这是否意味着一个着色器阶段应该能够代表所有阶段的一个版本?

提前致谢!

没错,这主要是为了保持 api 的一致性。 VkShaderStageFlagBits 用于多个位置,其中位掩码比管道创建时更有意义。

一个有意义的例子是描述符集布局绑定,您可以在其中使用标志掩码来指定哪些阶段可以访问您的描述符(采样器、统一缓冲区对象等)。

因此,如果您希望一个 UBO 可从顶点和片段阶段访问,而另一个 UBO 可从几何和曲面细分阶段访问,则在设置 VkDescriptorSetLayoutBinding 时,您将使用不同的阶段标志位组合。管道状态组合在这里很常见。

Vulkan 使用 Vk*FlagBits 类型的字段(例如 VkShaderStageFlagBits),当恰好需要一个已定义的值时,并使用相应的 Vk*Flags 类型(始终是 VkFlags 这只是 uint32_t 的类型定义(例如 typedef VkFlags VkShaderStageFlags),当期望组合零个、一个或多个定义值时。

这有两个原因:

  1. 它给出了一个信号(尽管很微妙),表明一个值是 expected/allowed 还是期望值的某种组合。

  2. 许多编译器在将位值的组合分配给枚举类型的字段时会给出警告,这实际上有助于执行(1)。这是因为要对枚举值进行按位运算,首先将它们提升为整数类型,结果为整数类型,并且大多数编译器的典型设置在从中进行隐式转换时会产生警告(通常提升为错误)整数到枚举类型,因为整数可能不是枚举值之一。

所以 VkPipelineShaderStageCreateInfo::stageVkShaderStageFlagBits 因为那里只有一个着色器阶段是有效的,如果你试图将它设置为像 VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT 这样愚蠢的东西,你可能会收到警告。

但是 VkDescriptorSetLayoutBinding::stageFlagsVkShaderStageFlags,因为它很常见并且预计会在那里包含多个阶段,如果将其设置为 VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,您将不会收到编译器警告。