1. 程式人生 > >Vulkan Cookbook 第五章 5 建立統一紋理(uniform texel)緩衝區

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>;