本文主要是介绍Vulkan描述符、描述符Pool、Layout概念,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、DescriptorSetLayout为了组织和管理着色器资源(如缓冲区、纹理、采样器等),多个相同类型的Descriptor放在一个Layout中以优化GPU对资源的访问
//DescriptorSetLayout定义了哪些描述符Descriptor类型(Buffers、Textures、Samplers)可以包含在其中
VkDescriptorSetLayoutBinding layoutBinding = {
0, // binding
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,//DescriptorSetLayout布局中的描述符类型,表明只有UNIFORM Buffer才能包含在下面创建的DescriptorSetLayout中
1,//descriptorCount
VK_SHADER_STAGE_VERTEX_BIT,//stageFlags
nullptr
};
VkDescriptorSetLayoutCreateInfo descLayoutInfo{};
descLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descLayoutInfo.bindingCount = 1;
descLayoutInfo.pBindings = &layoutBinding;err = m_devFuncs->vkCreateDescriptorSetLayout(dev, &descLayoutInfo, nullptr, &m_descSetLayout);
if (err != VK_SUCCESS)
qFatal("Failed to create descriptor set layout: %d", err);
2、DescriptorPool
//每种类型的 Descriptor,如 Uniform Buffers、Sampled Images、Storage Buffers、Textures 等,都从描述符池DescriptorPool中分配和释放,每个Descriptor包含了指向实际资源的引用。
VkDescriptorPoolSize descPoolSizes{}; //也可以声明为vector<VkDescriptorPoolSize>以指定多种 Descriptor 类型可以从下面创建的描述符池中分配。
descPoolSizes.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;//描述符类型
descPoolSizes.descriptorCount = static_cast<uint32_t>(concurrentFrameCount); //UNIFORM缓冲的数量
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.pNext = nullptr;
poolInfo.maxSets = static_cast<uint32_t>(concurrentFrameCount);
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &descPoolSizes;
if (m_devFuncs->vkCreateDescriptorPool(dev, &poolInfo, nullptr, &m_descPool) != VK_SUCCESS)
{
throw std::runtime_error("echec de la creation de la pool de descripteurs!");
}
用于分配描述符Descriptor的DescriptorPool和用于组织和管理描述符Descriptor的DescriptorSetLayout都已经准备好了,接下来就是创建DescriptorSet了,只要完成了这一步,后面就可以把创建的Descriptor写入DescriptorSet中了
3、DescriptorSet
std::vector<VkDescriptorSetLayout> layouts(concurrentFrameCount, m_descSetLayout);
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.pNext = nullptr;
allocInfo.descriptorPool = m_descPool;
allocInfo.descriptorSetCount = static_cast<uint32_t>(concurrentFrameCount);
allocInfo.pSetLayouts = layouts.data();
//Descriptor Set(描述符集)是一组Descriptor的集合
m_descriptorSets.resize(concurrentFrameCount);
if (m_devFuncs->vkAllocateDescriptorSets(dev, &allocInfo, m_descriptorSets.data()) != VK_SUCCESS)
{
throw std::runtime_error("echec de l'allocation d'un set de descripteurs!");
}
DescriptorSet现在已经在DescriptorSetLayout中了。
最开始创建的Uniform Buffers描述符:
VkDeviceSize bufferSize = sizeof(UniformBufferObject);
m_uniformBuffers.resize(concurrentFrameCount); // concurrentFrameCount correspond à swapchainimages.size()
m_uniformBuffersMemory.resize(concurrentFrameCount);
for (size_t i = 0; i < concurrentFrameCount; i++)
{
createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
m_uniformBuffers[i],
m_uniformBuffersMemory[i]);
}
4、接下来把描述符 m_uniformBuffers 写入DescriptorSet中
void Renderer::flushTexToDescriptorSet(VkDevice dev, int concurrentFrameCount)
{
for (int i = 0; i < concurrentFrameCount; ++i) {VkDescriptorBufferInfo uniformBufferInfo{};
uniformBufferInfo.buffer = m_uniformBuffers[i];//创建的VkBuffer描述符类型
uniformBufferInfo.offset = 0;
uniformBufferInfo.range = sizeof(UniformBufferObject);VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.pNext = NULL;
descriptorWrite.dstSet = m_descriptorSets[i];//写入到索引i的DescriptorSet中
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &uniformBufferInfo;
descriptorWrite.pImageInfo = nullptr; // Optionnel
descriptorWrite.pTexelBufferView = nullptr; // Optionnelm_devFuncs->vkUpdateDescriptorSets(dev, 1, &descriptorWrite, 0, nullptr);//写入
}
}
5、渲染管线VkPipeline ,定义了渲染各个阶段配置,如下图整个渲染大致流程。
pipelineInfo.layout = m_pipelineLayout;
pipelineInfo.renderPass = m_window->defaultRenderPass();err = m_devFuncs->vkCreateGraphicsPipelines(dev, m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline);
if (err != VK_SUCCESS)
qFatal("Failed to create graphics pipeline: %d", err);
所有工作准备好了,接下来Start frame render
VkCommandBuffer cmdBuf = m_window->currentCommandBuffer();
//开始render
m_devFuncs->vkCmdBeginRenderPass(cmdBuf, &rpBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
.................//本次渲染使用的管线配置
m_devFuncs->vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
................//本次渲染使用的描述符资源DescriptorSet
m_devFuncs->vkCmdBindDescriptorSets(cb, VK_PIPELINE_BIND_POINT_GRAPHICS,
m_pipelineLayout,
0,
1,
&m_descriptorSets[currFrameIdx],
0,
nullptr);............
//录制命令
m_devFuncs->vkCmdDrawIndexed(cb, indices.size(), 1, 0, 0, 0);
//结束render
m_devFuncs->vkCmdEndRenderPass(cmdBuf);
参考:Vulkan的DescriptorSet理解_vkallocatedescriptorsets-CSDN博客
这篇关于Vulkan描述符、描述符Pool、Layout概念的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!