Vulkan描述符、描述符Pool、Layout概念

2024-09-07 04:20

本文主要是介绍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; // Optionnel

        m_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概念的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1144037

相关文章

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

一文带你迅速搞懂路由器/交换机/光猫三者概念区别

《一文带你迅速搞懂路由器/交换机/光猫三者概念区别》讨论网络设备时,常提及路由器、交换机及光猫等词汇,日常生活、工作中,这些设备至关重要,居家上网、企业内部沟通乃至互联网冲浪皆无法脱离其影响力,本文将... 当谈论网络设备时,我们常常会听到路由器、交换机和光猫这几个名词。它们是构建现代网络基础设施的关键组成

MySQL 事务的概念及ACID属性和使用详解

《MySQL事务的概念及ACID属性和使用详解》MySQL通过多线程实现存储工作,因此在并发访问场景中,事务确保了数据操作的一致性和可靠性,下面通过本文给大家介绍MySQL事务的概念及ACID属性和... 目录一、什么是事务二、事务的属性及使用2.1 事务的 ACID 属性2.2 为什么存在事务2.3 事务

golang 对象池sync.Pool的实现

《golang对象池sync.Pool的实现》:本文主要介绍golang对象池sync.Pool的实现,用于缓存和复用临时对象,以减少内存分配和垃圾回收的压力,下面就来介绍一下,感兴趣的可以了解... 目录sync.Pool的用法原理sync.Pool 的使用示例sync.Pool 的使用场景注意sync.

MySQL连接池(Pool)常用方法详解

《MySQL连接池(Pool)常用方法详解》本文详细介绍了MySQL连接池的常用方法,包括创建连接池、核心方法连接对象的方法、连接池管理方法以及事务处理,同时,还提供了最佳实践和性能提示,帮助开发者构... 目录mysql 连接池 (Pool) 常用方法详解1. 创建连接池2. 核心方法2.1 pool.q

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

【VUE】跨域问题的概念,以及解决方法。

目录 1.跨域概念 2.解决方法 2.1 配置网络请求代理 2.2 使用@CrossOrigin 注解 2.3 通过配置文件实现跨域 2.4 添加 CorsWebFilter 来解决跨域问题 1.跨域概念 跨域问题是由于浏览器实施了同源策略,该策略要求请求的域名、协议和端口必须与提供资源的服务相同。如果不相同,则需要服务器显式地允许这种跨域请求。一般在springbo

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

【MRI基础】TR 和 TE 时间概念

重复时间 (TR) 磁共振成像 (MRI) 中的 TR(重复时间,repetition time)是施加于同一切片的连续脉冲序列之间的时间间隔。具体而言,TR 是施加一个 RF(射频)脉冲与施加下一个 RF 脉冲之间的持续时间。TR 以毫秒 (ms) 为单位,主要控制后续脉冲之前的纵向弛豫程度(T1 弛豫),使其成为显著影响 MRI 中的图像对比度和信号特性的重要参数。 回声时间 (TE)

计算机网络基础概念 交换机、路由器、网关、TBOX

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、VLAN是什么?二 、交换机三、路由器四、网关五、TBOXTelematics BOX,简称车载T-BOX,车联网系统包含四部分,主机、车载T-BOX、手机APP及后台系统。主机主要用于车内的影音娱乐,以及车辆信息显示;车载T-BOX主要用于和后台系统/手机APP通信,实现手机APP的车辆信息显示与控