在 vulkan 计算着色器中加载/存储到特定的 mip 级别

问题描述

正如标题所暗示的,我想在计算着色器中读取和写入特定 mip 级别的特定像素。我知道在 Vulkan 方面,我可以指定我想要在 ImageView 中解决多少 mip 级别,但我不确定这在 glsl 中是如何工作的。我可以在单个 ImageView 中使用单个 image3D:

layout(binding = 0,rgb8) uniform image3D img;

还是每个 mip 级别需要一个 image2D 从而需要多个 ImageView?

layout(binding = 0,rgb8) uniform image2d mipLvl0;
layout(binding = 1,rgb8) uniform image2d mipLvl1;
layout(binding = 2,rgb8) uniform image2d mipLvl2;

因为 imageLoad/Store 都有一个ivec3 的重载,我假设我可以在第一种情况下将 mip 级别指定为 z 坐标。

解决方法

您不能将 mipmap 金字塔视为单个绑定描述符。

然而,您可以将金字塔中的每个 mipmap 绑定到一个 arrayed 描述符:

layout(binding = 0,rgb8) uniform image2d img[3];

此描述符将被排列,这意味着在此示例中,此集合的绑定 0 的 VkDescriptorSetLayoutBinding::descriptorCount 将为 3。您还必须将图像的每个 mipmap 绑定到描述符中的不同数组索引,因此该描述符的 descriptorCountpImageInfo 需要为 vkUpdateDescriptorSet 调用提供多个图像。并且数组元素的数量需要在着色器中说明,因此它不能动态更改(如果您的着色器不访问它们,您可以在描述符中保留其中的一些未指定)。

此外,您必须遵循实现的规则来索引不透明类型的数组。大多数桌面实现允许这些是动态统一表达式(并且您需要激活 shaderStorageImageArrayDynamicIndexing 功能),因此您可以使用 uniform 变量而不是常量表达式。但表述不能随意;它们必须在单个绘制调用中解析为相同的值。

此外,使用一组图像并不能绕过着色器可以使用的图像数量限制。但是,大多数桌面硬件对这些限制非常慷慨。