Vulkan大闷锅之Descriptor

上一章,我们创建了Uniform Buffer,不过着色器并不能直接访问它。这时我们需要一个Descriptor,类似于不透明的句柄。试想,是否可以绑定多个Buffer给分别的Descriptor。Vulkan已经提供了相当的机制Descriptor Set。这里也可以创建多个Set为不同的用途,比如Uniform和Texture。

VkDescriptorSetLayoutBinding layout_binding = {};
layout_binding.binding = 0;
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
layout_binding.descriptorCount = 1;
layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
layout_binding.pImmutableSamplers = nullptr;

VkDescriptorSetLayoutCreateInfo descriptor_layout = {};
descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptor_layout.pNext = nullptr;
descriptor_layout.bindingCount = 1;
descriptor_layout.pBindings = &layout_binding;

std::vector<VkDescriptorSetLayout> desc_layout;
const int NUM_DESCRIPTOR_SETS = 1;
desc_layout.resize(NUM_DESCRIPTOR_SETS);
res = vkCreateDescriptorSetLayout(device, &descriptor_layout, 
                                    nullptr, desc_layout.data());

VkDescriptorSetLayoutBinding表示单个Descriptor的布局信息。VkDescriptorSetLayout后续还会有别的用途。

VkDescriptorPoolSize type_count[1];
type_count[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
type_count[0].descriptorCount = 1;
VkDescriptorPoolCreateInfo descriptor_pool = {};
descriptor_pool.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptor_pool.pNext = nullptr;
descriptor_pool.maxSets = 1;
descriptor_pool.poolSizeCount = 1;
descriptor_pool.pPoolSizes = type_count;
VkDescriptorPool desc_pool;
res = vkCreateDescriptorPool(device, &descriptor_pool, nullptr, &desc_pool);
assert(res == VK_SUCCESS);

这里先创建了一个内存池。

VkDescriptorSetAllocateInfo desc_alloc_info[1];
desc_alloc_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
desc_alloc_info[0].pNext = nullptr;
desc_alloc_info[0].descriptorPool = desc_pool;
desc_alloc_info[0].descriptorSetCount = 1;
desc_alloc_info[0].pSetLayouts = desc_layout.data();
std::vector<VkDescriptorSet> desc_set;
desc_set.resize(1);
res = vkAllocateDescriptorSets(device, desc_alloc_info, desc_set.data());
assert(res == VK_SUCCESS);

Descriptor Set创建之后,仍需要连接数据。上一章已经准备了uniform_data.buffer_info:

VkWriteDescriptorSet writes[1];
writes[0] = {};
writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[0].pNext = nullptr;
writes[0].dstSet = desc_set[0];
writes[0].descriptorCount = 1;
writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writes[0].pBufferInfo = &uniform_data.buffer_info;
writes[0].dstArrayElement = 0;
writes[0].dstBinding = 0;

vkUpdateDescriptorSets(device, 1, writes, 0, nullptr);

同时,Descriptor Set的布局也是Pipeline布局依赖的信息:

VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {};
pPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pPipelineLayoutCreateInfo.pNext = nullptr;
pPipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pPipelineLayoutCreateInfo.pPushConstantRanges = nullptr;
pPipelineLayoutCreateInfo.setLayoutCount = NUM_DESCRIPTOR_SETS;
pPipelineLayoutCreateInfo.pSetLayouts = desc_layout.data();

VkPipelineLayout pipeline_layout;
res = vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, 
                               nullptr, &pipeline_layout);
assert(res == VK_SUCCESS);

经过一连串代码轰炸,不得不佩服Vulkan的设计师。这样的设计可以说是事无巨细。其余内容请关注后续博文。

Leave a Reply

Your email address will not be published. Required fields are marked *