Vulkan Cookbook 第五章 5 创建统一纹理(uniform texel)缓冲区

创建统一纹理(uniform texel)缓冲区

译者注:示例代码点击此处

统一纹理缓冲区准许我们以类似于图像读取数据的方式读取数据,它们的内容不是解释为单个(标量)值的数组,而是解释为具有一个、两个、三个或四个组件的格式化像素(纹素)。通过这样的缓冲区,我们可以访问比通常图像提供的数据大得多的数据。

当我们想要使用缓冲区作为统一的纹理缓冲区时,我们需要指定VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT用法。

怎么做...

  1. 获取物理设备句柄并将其存储在名为physical_device的VkPhysicalDevice类型变量中。
  2. 选择将存储缓冲区的格式,使用该格式初始化名为format的VkFormat类型格式。
  3. 创建一个名为format_properties的VkFormatProperties类型变量。
  4. 调用vkGetPhysicalDeviceFormatProperties( physical_device, format, &format_properties )并提供物理设备句柄,format变量和指向format_properties变量的指针。
  5. 通过检查format_properties变量的bufferFeatures成员是否设置了VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT位,确保所选格式适用于统一纹理缓冲区。
  6. 获取从所选物理设备句柄创建的逻辑设备句柄,将其存储在名为logical_device的VkDevice类型变量中。
  7. 创建一个名为uniform_texel_buffer的VkBuffer类型变量
  8. 使用logical_device变量创建一个具有所需大小和用法的缓冲区。不要忘记在缓冲区创建期间包含VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT用法。将创建的句柄存在名为uniform_texel_buffer变量中(请参阅第4章,资源和内存中的创建缓冲区内容)。
  9. 使用VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT属性(或使用现有属性)分配内存对象并将其绑定到缓冲区。如果分配了新的内存对象,则将其存储在名为memory_object的VkDeviceMemory类型变量中(请参阅第4章,资源和内存中的为缓冲区分配和绑定内存对象内容)。
  10. 使用logical_device、uniform_texel_buffer和format变量以及所需的偏移量和内存范围创建缓冲区视图。将生成的句柄存储在名为uniform_texel_buffer_view的VkBufferView类型变量中(请参阅第4章,资源和内存中的创建缓冲区视图内容)。

这个怎么运作...

统一纹理缓冲区提供解释为一维图像的数据,但是这些数据可能比典型图像大得多。Vulkan规范要求每个驱动程序支持至少4096个纹素的1D图像。但对于纹理缓冲区,此最小要求限制高达65536个元素。

提示:统一纹理缓冲区绑定到VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER类型的描述符。

使用VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT用法创建统一纹理缓冲区。但除此之外,我们还需要选择合适的格式。并非所有格式都于此类缓冲区兼容。可以与统一纹理缓冲区一起使用的强制格式列表包括(但不限于)一下内容:

  • VK_FORMAT_R8_UNORM, VK_FORMAT_R8_SNORM, VK_FORMAT_R8_UINT, and VK_FORMAT_R8_SINT
  • VK_FORMAT_R8G8_UNORM, VK_FORMAT_R8G8_SNORM, VK_FORMAT_R8G8_UINT, and VK_FORMAT_R8G8_SINT
  • VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, and VK_FORMAT_R8G8B8A8_SINT
  • VK_FORMAT_B8G8R8A8_UNORM
  • VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SNORM_PACK32, VK_FORMAT_A8B8G8R8_UINT_PACK32, and VK_FORMAT_A8B8G8R8_SINT_PACK32
  • VK_FORMAT_A2B10G10R10_UNORM_PACK32 and VK_FORMAT_A2B10G10R10_UINT_PACK32
  • VK_FORMAT_R16_UINT, VK_FORMAT_R16_SINT and VK_FORMAT_R16_SFLOAT
  • VK_FORMAT_R16G16_UINT, VK_FORMAT_R16G16_SINT and VK_FORMAT_R16G16_SFLOAT
  • VK_FORMAT_R16G16B16A16_UINT, VK_FORMAT_R16G16B16A16_SINT and VK_FORMAT_R16G16B16A16_SFLOAT
  • VK_FORMAT_R32_UINT, VK_FORMAT_R32_SINT and VK_FORMAT_R32_SFLOAT
  • VK_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_SINT and VK_FORMAT_R32G32_SFLOAT
  • VK_FORMAT_R32G32B32A32_UINT, VK_FORMAT_R32G32B32A32_SINT and VK_FORMAT_R32G32B32A32_SFLOAT VK_FORMAT_B10G11R11_UFLOAT_PACK32

要检查其他格式是否可以于统一纹理缓冲区一起使用,需要准备以下代码: 

VkFormatProperties format_properties;
vkGetPhysicalDeviceFormatProperties( physical_device, format, &format_properties );
if( !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT) ) {
  std::cout << "Provided format is not supported for a uniform texel buffer." << std::endl;
  return false; 
}

如果所选格式适合我们的需求,可以创建一个缓冲区,为它分配一个内存对象,并将其绑定到缓冲区。非常重要的是,我们还需要一个缓冲区视图:

if( !CreateBuffer( logical_device, size, usage | VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, uniform_texel_buffer ) ) {
  return false;
}

if( !AllocateAndBindMemoryObjectToBuffer( physical_device, logical_device, uniform_texel_buffer, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memory_object ) ) {
  return false;
}

if( !CreateBufferView( logical_device, uniform_texel_buffer, format, 0, VK_WHOLE_SIZE, uniform_texel_buffer_view ) ) {
  return false;
}
return true;

从API的角度来看,缓冲区内容的结构无关紧要。但是在统一纹理缓冲区的情况下我们需要指定一种数据格式,准许着色器以适当的方式解析缓冲区内容。这就是需要缓冲区视图的原因。

提示:在GLSL着色器中,统一纹理缓冲区是通过samplerBuffer类型的变量(可能带有前缀)定义的。

GLSL着色器中定义的统一纹理缓冲区变量示例如下:

layout (set=m, binding=n) uniform samplerBuffer <variable name>;

猜你喜欢

转载自blog.csdn.net/qq_19473837/article/details/85230057