VulkanTutorial项目详解:描述符池与描述符集的使用

VulkanTutorial项目详解:描述符池与描述符集的使用

VulkanTutorial Tutorial for the Vulkan graphics and compute API VulkanTutorial 项目地址: https://gitcode.com/gh_mirrors/vu/VulkanTutorial

概述

在Vulkan图形编程中,描述符集(Descriptor Sets)是连接着色器与资源(如缓冲区、图像等)的重要桥梁。本文将深入探讨如何在VulkanTutorial项目中创建和使用描述符池与描述符集,特别是针对统一缓冲区(Uniform Buffer)的应用场景。

描述符池的创建

描述符集不能直接创建,必须从描述符池中分配,这与命令缓冲区的管理方式类似。创建描述符池需要以下步骤:

  1. 定义池大小:首先需要指定池中包含哪些类型的描述符及其数量
VkDescriptorPoolSize poolSize{};
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
poolSize.descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
  1. 创建池信息结构体:配置描述符池的创建参数
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = 1;
poolInfo.pPoolSizes = &poolSize;
poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
  1. 创建描述符池:调用vkCreateDescriptorPool完成创建
if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
    throw std::runtime_error("failed to create descriptor pool!");
}

描述符集的分配

有了描述符池后,就可以分配描述符集了:

  1. 准备分配信息:指定从哪个池分配、分配多少组、使用什么布局
std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
VkDescriptorSetAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = descriptorPool;
allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
allocInfo.pSetLayouts = layouts.data();
  1. 实际分配:调用vkAllocateDescriptorSets进行分配
descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
    throw std::runtime_error("failed to allocate descriptor sets!");
}

描述符的配置

分配后的描述符集需要进一步配置才能使用:

  1. 缓冲区信息:为每个统一缓冲区创建描述信息
VkDescriptorBufferInfo bufferInfo{};
bufferInfo.buffer = uniformBuffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
  1. 写入操作:配置如何更新描述符集
VkWriteDescriptorSet descriptorWrite{};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSets[i];
descriptorWrite.dstBinding = 0;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
  1. 执行更新:调用vkUpdateDescriptorSets应用更改
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);

在渲染中使用描述符集

配置完成后,在渲染时需要绑定描述符集:

vkCmdBindDescriptorSets(
    commandBuffer,
    VK_PIPELINE_BIND_POINT_GRAPHICS,  // 用于图形管线
    pipelineLayout,                   // 管线布局
    0,                                // 第一个描述符集的索引
    1,                                // 要绑定的描述符集数量
    &descriptorSets[currentFrame],    // 描述符集数组
    0,                                // 动态偏移量数量
    nullptr                           // 动态偏移量数组
);

内存对齐要求

在定义统一缓冲区结构体时,必须注意内存对齐要求:

  • 标量必须按4字节对齐
  • vec2必须按8字节对齐
  • vec3/vec4和mat4必须按16字节对齐
  • 嵌套结构体必须按其成员的最大对齐要求对齐

可以使用C++11的alignas指定符确保正确对齐:

struct UniformBufferObject {
    alignas(16) glm::mat4 model;
    alignas(16) glm::mat4 view;
    alignas(16) glm::mat4 proj;
};

或者使用GLM的强制对齐类型:

#define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES
#include <glm/glm.hpp>

多描述符集的使用

Vulkan支持同时绑定多个描述符集,这可以通过在着色器中指定set索引实现:

layout(set = 0, binding = 0) uniform UniformBufferObject { ... }

这种机制允许将频繁变更的描述符和不常变更的描述符分开管理,提高渲染效率。

总结

描述符系统是Vulkan资源管理的核心机制之一。通过正确创建描述符池、分配和配置描述符集,并在渲染时正确绑定,我们可以有效地将缓冲区等资源传递给着色器使用。理解并掌握这些概念对于Vulkan图形编程至关重要。

VulkanTutorial Tutorial for the Vulkan graphics and compute API VulkanTutorial 项目地址: https://gitcode.com/gh_mirrors/vu/VulkanTutorial

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

劳阔印

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值