创建存储纹理缓冲区
译者注:示例代码点击此处
存储纹理缓冲区(如统一纹理像素缓冲区)是一种向着着色器提供大量图像数据的方法。但它们也准许我们在其中存储数据并对它们执行原子操作。为此我们需要使用VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT创建一个缓冲区。
怎么做...
- 获取物理设备句柄并将其存储在名为physical_device的VkPhysicalDevice类型变量中。
- 选择纹理缓冲区数据格式来初始化名为format的VkFormat类型变量。
- 创建一个名为format_properties的VkFormatProperties类型变量。
- 调用vkGetPhysicalDeviceFormatProperties( physical_device, format, &format_properties )并提供物理设备句柄、format变量和指向format_properties变量的指针。
- 通过检查format_properties变量的bufferFeatures成员是否设置了VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT位,确保所选格式适用于存储纹理缓冲区。
- 如果将对创建的存储纹理缓冲区执行原子操作,请确保所选格式也适用于原子操作。为此请检查是否设置了format_properties变量的bufferFeatures成员的VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT位。
- 获取从所选物理设备句柄创建的逻辑设备句柄。将其存储在名为logical_device的VkDevice类型变量中。
- 创建一个名为storage_texel_buffer的VkBuffer类型变量。
- 使用logical_device变量创建具有所需大小和用法的缓冲区。确保在创建缓冲区期间指定了VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT用法。将缓冲区的句柄存储在storage_texel_buffer变量中(请参阅第4章,资源和内存中的创建缓冲区内容)。
- 使用VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT属性配内存对象(或使用现有内存对象的部分范围)分并将其绑定到缓冲区。如果分配了新的内存对象,请将其存储在名为memory_object的VkDeviceMemory类型变量中(请参阅第4章,资源和内存中的为缓冲区分配和绑定内存对象内容)。
- 使用logical_device、storage_texel_buffer和format变量以及所需的偏移量和内存范围创建缓冲区视图。将生成的句柄存储在名为storage_texel_buffer_view的VkBufferView类型变量中。(请参阅第4章,资源和内存中的的创建缓冲区视图内容)。
这个怎么运作...
存储纹理缓冲区准许我们访问和存储非常大的数组中的数据。另外我们可以对这些缓冲区执行原子操作。
提示:存储纹理缓冲区使用类型描述符VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER。
要使用缓冲区作为存储纹理缓冲区,需要使用VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT创建缓冲区。还需要具有适当格式的缓冲区视图。对于存储存理缓冲区,我们可以选择一种强制格式,包括下列格式:
- VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_R8G8B8A8_SNORM, VK_FORMAT_R8G8B8A8_UINT, and VK_FORMAT_R8G8B8A8_SINT
- VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_SNORM_PACK32, VK_FORMAT_A8B8G8R8_UINT_PACK32, and VK_FORMAT_A8B8G8R8_SINT_PACK32
- 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_R32_UINT and VK_FORMAT_R32_SINT
对于存储纹理缓冲区也可以支持其他格式,但是这种格式不保证可以使用,必须在平台上确认是否可用:
VkFormatProperties format_properties;
vkGetPhysicalDeviceFormatProperties( physical_device, format, &format_properties );
if( !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT) ) {
std::cout << "Provided format is not supported for a uniform texel buffer." << std::endl;
return false;
}
if( atomic_operations &&
!(format_properties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) ) {
std::cout << "Provided format is not supported for atomic operations on storage texel buffers." << std::endl;
return false;
}
对于存储纹理缓冲区,我们需要创建一个缓冲区,分配一个内存对象并将其绑定到缓冲区,以及还需要创建缓冲区视图,该视图将定义缓冲区数据格式:
if( !CreateBuffer( logical_device, size, usage | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, storage_texel_buffer ) ) {
return false;
}
if( !AllocateAndBindMemoryObjectToBuffer( physical_device, logical_device, storage_texel_buffer, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, memory_object ) ) {
return false;
}
if( !CreateBufferView( logical_device, storage_texel_buffer, format, 0, VK_WHOLE_SIZE, storage_texel_buffer_view ) ) {
return false;
}
return true;
我们还可以使用现有的内存对象并将其内存范围绑定到存储纹理缓冲区。
提示:从GLSL的角度来看,存储纹理缓冲区变量是使用imageBuffer(可能带有前缀)关键字定义的。
GLSL着色器中定义的存储纹理缓冲区的示例如下:
layout (set=m, binding=n, r32f) uniform imageBuffer <variable name>;