Code file for this section is 09-init_descriptor_set.cpp
Back in the pipeline_layout sample, you defined the descriptor set layout, but didn't actually allocate it. Recall that the descriptor set that you defined is used to inform the GPU how the data contained in the uniform buffer is mapped to the shader program's uniform variables. Now you can proceed with allocating and initializing the descriptor set.
Like command buffers, descriptor sets are allocated from a pool. So you must first create the pool. Since you know that you need only one descriptor set for a uniform buffer, creating the pool is straightforward:
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 = NULL;
descriptor_pool.maxSets = 1;
descriptor_pool.poolSizeCount = 1;
descriptor_pool.pPoolSizes = type_count;
res = vkCreateDescriptorPool(info.device, &descriptor_pool, NULL,
&info.desc_pool);
Now you can allocate a descriptor set from the pool. Note that you have to provide the descriptor set layout that you defined in the pipeline_layout sample. This layout describes how the descriptor set is to be allocated.
VkDescriptorSetAllocateInfo alloc_info[1];
alloc_info[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info[0].pNext = NULL;
alloc_info[0].descriptorPool = info.desc_pool;
alloc_info[0].descriptorSetCount = NUM_DESCRIPTOR_SETS;
alloc_info[0].pSetLayouts = info.desc_layout.data();
info.desc_set.resize(NUM_DESCRIPTOR_SETS);
res = vkAllocateDescriptorSets(info.device, alloc_info, info.desc_set.data());
Note that you have not actually used the handle for the uniform buffer anywhere yet.
You stashed away the uniform buffer's information in
a VkDescriptorBufferInfo
structure named info.uniform_data.buffer_info
when
you created the uniform buffer.
See the function init_uniform_buffer()
to see how info.uniform_data.buffer_info
is initialized.
info.uniform_data.buffer_info
is an instance of:
typedef struct VkDescriptorBufferInfo {
VkBuffer buffer;
VkDeviceSize offset;
VkDeviceSize range;
} VkDescriptorBufferInfo;
where the buffer
member contains the uniform buffer handle.
VkWriteDescriptorSet writes[1];
writes[0] = {};
writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writes[0].pNext = NULL;
writes[0].dstSet = info.desc_set[0];
writes[0].descriptorCount = 1;
writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
writes[0].pBufferInfo = &info.uniform_data.buffer_info;
writes[0].dstArrayElement = 0;
writes[0].dstBinding = 0;
vkUpdateDescriptorSets(info.device, 1, writes, 0, NULL);
The above steps essentially copy the VkDescriptorBufferInfo
to the descriptor, which
is likely in the device memory.
This buffer info includes the handle to the uniform buffer as well as the offset and size
of the data that is accessed in the uniform buffer.
In this case, the uniform buffer contains only the MVP transform, so the offset is 0
and the size is the size of the MVP, as setup by the pipeline_layout sample
in info.uniform_data.buffer_info
.
The exact byte-wise layout of a descriptor is probably implementation-specific and so is opaque to you. This is why you use Vulkan driver functions to manipulate descriptors, instead of mapping and writing them yourself.
Pipeline Layouts | Index | Render Pass |