Vulkan Tutorial 24 Descriptor pool and sets
操作系統:Windows8.1
顯卡:Nivida GTX965M
開發工具:Visual Studio 2017
Introduction
描述符布局描述了前一章節討論過的可以綁定的描述符的類型。在本章節,我們創建描述符集,它將實際指定一個VkBuffer來綁定到一個uniform buffer描述符。
Descriptor pool描述符集合不能集合創建,它們必須像命令緩衝區一樣,從對象池中分配使用。對於描述符集合相當於調用描述符對象池。我們將寫一個新的函數createDescriptorPool來配置。
void initVulkan {
...
createUniformBuffer;
createDescriptorPool;
...
}
...
void createDescriptorPool {
}
我們首先需要明確我們使用的描述符集合包含哪些描述符類型,並且有多少,這裡使用VkDescriptorPoolSize結構體集合。
VkDescriptorPoolSize poolSize = {};
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.descriptorCount = 1;
現在我們只有一個uniform buffer類型的單描述符。對象池大小將被VkDescriptorPoolCreateInfo結構體引用:
VkDescriptorPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;
我們也需要指定最大的描述符集合的分配數量:
poolInfo.maxSets = 1;
該結構體與命令對象池類似,有一些可選項用於決定每個描述符集合是否可以獨立管理生命周期:VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT。創建完畢後我們不會進一步使用它,所以我們不需要該flag。在這裡設置flags默認值為0。
VkDescriptorPool descriptorPool;
...
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
throw std::runtime_error("failed to create descriptor pool!");
}
添加新的類成員對象保存描述符對象池的句柄,通過調用vkCreateDescriptorPool創建它。描述符對象池應該僅在程序退出的時候銷毀,很想其他的繪製資源:
void cleanup {
cleanupSwapChain;
vkDestroyDescriptorPool(device, descriptorPool, nullptr);
...
}
Descriptor set
為了分配描述符集合從對象池中,我們需要添加一個createDescriptorSet函數:
void initVulkan {
...
createDescriptorPool;
createDescriptorSet;
...
}
...
void createDescriptorSet {
}
描述符集合通過VkDescriptorSetAllocateInfo結構體描述具體的分配。需要指定用於分配的描述符對象池,分配的描述符集合數量,以及基於此的描述符布局:
VkDescriptorSetLayout layouts = {descriptorSetLayout};
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = layouts;
添加類成員存儲描述符集合的句柄,並使用vkAllocateDescriptorSets分配:
VkDescriptorPool descriptorPool;
VkDescriptorSet descriptorSet;
...
if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) {
throw std::runtime_error("failed to allocate descriptor set!");
}
我們不需要明確清理描述符集合,因為它們會在描述符對象池銷毀的時候自動清理。調用vkAllocateDescriptorSets會分配一個具有uniform buffer描述符的描述符集合。
描述符集合已經分配了,但是內部的描述符需要配置。描述符需要引用緩衝區,就像uniform buffer描述符,使用VkDescriptorBufferInfo結構體進行配置。該結構體指定緩衝區和描述符內部包含的數據的區域:
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = uniformBuffer;
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
描述符的配置更新使用vkUpdateDescriptorSets函數,它需要VkWriteDescriptorSet結構體的數組作為參數。
VkWriteDescriptorSet descriptorWrite = {};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSet;
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
前兩個欄位指定描述符集合更新和綁定的設置。我們為uniform buffer 綁定的索引設定為0。描述符可以是數組,所以我們需要指定要更新的數組索引。在這裡沒有使用數組,所以簡單的設置為0。
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
我們在這裡再一次指定描述符類型。可以通過數組一次性更新多個描述符,使用dstArrayElement起始索引。descriptorCount欄位描述多少描述符需要被更新。
descriptorWrite.pBufferInfo = &bufferInfo;
descriptorWrite.pImageInfo = nullptr; // Optional
descriptorWrite.pTexelBufferView = nullptr; // Optional
最後的欄位引用descriptorCount結構體的數組,它配置了實際的描述符。它的類型根據實際需要的三個描述符類型來設定。pBufferInfo欄位用於指定描述符引用的緩衝區數據,pImageInfo欄位用於指定描述符引用的圖像數據,描述符使用pTexelBufferView引用緩衝區視圖。我們的描述符是基於緩衝區的,所以我們使用pBufferInfo。
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);
使用vkUpdateDescriptorSets應用實際的更新。它接受兩種數組的參數:一個數組是VkWriteDescriptorSet,另一個是VkCopyDescriptorSet。後一個數組可以用於兩個描述符之間進行拷貝操作。
Using a descriptor set我們現在需要更新createCommandBuffers函數,使用cmdBindDescriptorSets將描述符集合綁定到實際的著色器的描述符中:
vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
與頂點和索引緩衝區不同,描述符集合不是圖形管線唯一的。因此,我們需要指定是否要將描述符集綁定到圖形或者計算管線。下一個參數是描述符所基於的布局。接下來的三個參數指定首個描述符的索引,要綁定的集合的數量以及要綁定的集合的數組。我們稍後回來。最後兩個參數指定用於動態描述符的偏移數組。我們在後續的章節中會看到這些。
如果此時運行程序,會看不到任何內容在屏幕上。問題在於,由於我們在投影矩陣中進行了Y-flip操作,所以頂點現在以順時針順序而不是逆時針順序繪製。這導致背面剔除以防止任何背面的集合體被繪製。來到createGraphicsPipeline函數,修改VkPipelineRasterizationStateCreateInfo結構體的frontFace如下:
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
運行程序如下:
矩形已經變為正方形,因為投影矩陣現在修正了寬高比。updateUniformData需要考慮屏幕的尺寸大小變化,所以我們不需要重新創建描述符集合在recreateSwapChain中。
Multiple descriptor sets正如某些結構體和函數調用時候的提示所示,實際上可以綁定多個描述符集合。你需要在管線創建布局的時候為每個描述符集合指定描述符布局。著色器可以引用具體的描述符集合如下:
layout(set = 0, binding = 0) uniform UniformBufferObject { ... }
我們可以使用此功能將每個對象和發生變化的描述符分配到單獨的描述符集合中,在這種情況下,可以避免重新綁定大部分描述符,而這些描述符可能會更有效率。
項目代碼 GitHub地址。


※Java總結之線程(1)
※如何使用Node.js編寫命令工具——以vue-cli為例
※限制input「type=number」的輸入位數策略整理
※ASP.NET MVC 重寫RazorViewEngine實現多主題切換
※我的面試準備過程——JVM相關
TAG:科技優家 |
※Rogue Swarm demo:將Vulkan和PowerVR Series8XE帶入我們的生活
※Oculus Quest和Go現已支持Vulkan
※Oculus Medium 2.0更新採用Vulkan新渲染引擎提高解析度
※Intel OpenCV庫支持Vulkan:獨立顯卡走來
※Vulkan即將推出macOS和iOS,但不會感謝Apple
※新面孔Model】陳曦出鏡美國版《Vulkan Magazine》一月刊時尚大片
※[視頻]歌計劃在 Android P 中支持圖形 API Vulkan 1.1
※Flyme 7體驗版王者榮耀Vulkan來了 不過Pro 7除外
※研發實戰:如何在Oculus Mobile VR平台進行Vulkan開發
※AMD終止支持功勛API Mantle:曾催生DX12、Vulkan
※Android Q將原生支持Vulkan,安卓手機和手游的春天?
※Wine 3.3開發版發布:Bug修復 支持Vulkan!
※Android Q將支持Vulkan原生渲染引擎:流暢度/遊戲體驗大提升
※Vulkan API終於登陸macOS/iOS平台 但與蘋果無關
※Vulkan API 終於登陸 macOS、iOS,但與蘋果無關
※《殭屍世界大戰》開啟Vulkan AMD Vega 64表現如何?
※Flyme 7體驗版11.13發布:支持王者榮耀Vulkan模式
※《殭屍世界大戰》開啟Vulkan:AMD Vega 64性能超了RTX 2080 Ti
※Wine 3.3上線:首次支持Vulkan圖形介面 修復35處BUG
※Vulkan下RTX2080Ti竟沒法玩《殭屍世界大戰》?