Vulkan Cookbook 第五章 13 更新描述符集

更新描述符集

译者注:示例代码点击此处

我们已创建了一个描述符池并分配了描述符集。由于创建了布局,我们知道它们的内部结构。现在我们要提供特定的资源(采集器,图像视图,缓冲区或缓冲区视图),这些资源应该稍后通过描述符集绑定到管道。定义应该使用的资源是通过更新描述符集的过程完成的。

做好准备

更新描述符集要求我们为流程中涉及的每个描述符提供大量数据。而且,提供的数据取决于描述符的类型。

对于采样器(samplers)和各种图像(image)描述符,使用具有以下定义的ImageDescriptorInfo类型:

struct ImageDescriptorInfo { 
  VkDescriptorSet                    TargetDescriptorSet;
  uint32_t                           TargetDescriptorBinding;
  uint32_t                           TargetArrayElement;
  VkDescriptorType                   TargetDescriptorType;
  std::vector<VkDescriptorImageInfo> ImageInfos;
};

对于统一(uniform)和存储缓冲区(storage buffers )(及其动态变化),使用BufferDescriptorInfo类型。 它有以下定义:

struct BufferDescriptorInfo { 
  VkDescriptorSet                     TargetDescriptorSet
  uint32_t                            TargetDescriptorBinding
  uint32_t                            TargetArrayElement
  VkDescriptorType                    TargetDescriptorType
  std::vector<VkDescriptorBufferInfo> BufferInfos
};

对于统一(uniform)和存储纹理缓冲区(storage texel buffers,),引入了TexelBufferDescriptorInfo类型,其定义如下:

struct TexelBufferDescriptorInfo { 
  VkDescriptorSet           TargetDescriptorSet;
  uint32_t                  TargetDescriptorBinding;
  uint32_t                  TargetArrayElement;
  VkDescriptorType          TargetDescriptorType;
  std::vector<VkBufferView> TexelBufferViews;
};

当我们想要用新描述符的句柄(尚未绑定)更新描述符集时,使用前面的结构。还可以从其他已更新的集合中赋值描述符数据,为此,使用了CopyDescriptorInfo类型,定义如下:


struct CopyDescriptorInfo {
  VkDescriptorSet TargetDescriptorSet;
  uint32_t        TargetDescriptorBinding;
  uint32_t        TargetArrayElement;
  VkDescriptorSet SourceDescriptorSet;
  uint32_t        SourceDescriptorBinding;
  uint32_t        SourceArrayElement;
  uint32_t        DescriptorCount;
};

 所有前面的结构定义了应该更新的描述符集的句柄、给定集合中描述符的索引、以及如果我们想要更新通过数组访问的描述符的数组索引。 其余参数是特定的类型。

怎么做...

  1. 使用逻辑设备的句柄初始化名为logical_device的VkDevice类型的变量。
  2. 创建一个名为write_descriptors的std::vector<VkWriteDescriptorSet>类型变量,为每个应更新的新描述符添加一个新元素,并为其成员使用一下值:
    ·sType为VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
    ·pNext为nullptr
    ·dstSet为应更新的描述符集句柄
    ·dstBinding为指定集描述符的索引(绑定)
    ·dstArrayElement为数组的开始索引,如果给定的描述符是通过着色器内的数组访问的,则应从中更新描述符(否则为0值)。
    ·descriptorCount为更新的描述符数(pImageInfo、pBufferInfo或pTexelBufferView数组中的元素数)
    ·descriptorType为描述符的类型
    ·在采样器(samplers)和图像(image)描述符的情况下,为descriptorCount设置描述符数量,并在pImageInfo中提供指向其第一个元素的指针(将pBufferInfo和pTexelBufferView成员设置为nullptr)。对每个数组元素使用以下值:
        ·sampler为采样器和组合图像采样器描述符的采样器句柄
        ·imageView为采样图像、存储图像、组合图像采样器和输出附件描述符、图像视图句柄。
        ·ImageLayout为当图像着色器访问描述符时,给定图像将处于的布局。
        ·在统一或存储缓冲区(及其动态)的情况下,为descriptorCount设置描述符数量,并在pBufferInfo中提供指向其第一个元素的指针(将pImageInfo和pTexelBufferView成员设置为nullptr),并为每个数组元素使用以下值:
        ·buffer为缓冲区句柄
        ·offset为缓冲区内的内存偏移量(或动态描述符的基本偏移量)
        ·range为应该用于给定描述符的缓冲区的内存大小
    ·对于均匀纹理像素缓冲区或存储纹理元素缓冲区,为descriptorCount设置描述符数量,并在pTexelBufferView中提供指向其第一个元素的指针(将pImageInfo和pBufferInfo成员设置为nullptr)。
  3. 创建一个名为copy_descriptors的std::vector<VkCopyDescriptorSet>类型的变量。为每个描述符数据添加一个元素到该向量,该数据应该从另一个已经更新的描述符中复制。对每个新元素的成员使用以下值:
        ·sType为VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET
        ·pNext为nullptr
        ·srcSet为应从中复制数据的描述符集句柄
        ·srcBinding为源描述符集中的绑定编号
        ·srcArrayElement为源描述符集中的数组索引
        ·dstSet为应更新数据到其中的描述符集句柄
        ·dstBinding为目标描述符中的绑定编号
        ·dstArrayElement为目标描述符集中的数组索引
        ·descriptorCount为从源集复制并在目标中更新的描述符数量。
  4. 调用vkUpdateDescriptorSets( logical_device, static_cast<uint32_t>(write_descriptors.size()),
    &write_descriptors[0], static_cast<uint32_t>(copy_descriptors.size()), &copy_descriptors[0] )并提供logical_device变量、write_descriptors向量中的元素数、指向write_descriptors第一个元素的指针、copy_descriptors向量中的元素数量、以及指向copy_descriptors向量的第一个元素的指针。 

这个怎么运作...

更新描述符集会导致指定的资源(采样器,图像视图,缓冲区或缓冲区视图)填充指定集中的条目。当更新集绑定到管线时,可以通过着色器访问这些资源。

我们可以将新的(或未使用的)资源写入描述符集。在下面的示例中,我们通过使用“做好准备”部分提到的自定结构体来执行操作:

std::vector<VkWriteDescriptorSet> write_descriptors;

for( auto & image_descriptor : image_descriptor_infos ) {
  write_descriptors.push_back( {
    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                                 // VkStructureType                  sType
    nullptr,                                                                // const void                     * pNext
    image_descriptor.TargetDescriptorSet,                                   // VkDescriptorSet                  dstSet
    image_descriptor.TargetDescriptorBinding,                               // uint32_t                         dstBinding
    image_descriptor.TargetArrayElement,                                    // uint32_t                         dstArrayElement
    static_cast<uint32_t>(image_descriptor.ImageInfos.size()),              // uint32_t                         descriptorCount
    image_descriptor.TargetDescriptorType,                                  // VkDescriptorType                 descriptorType
    image_descriptor.ImageInfos.data(),                                     // const VkDescriptorImageInfo    * pImageInfo
    nullptr,                                                                // const VkDescriptorBufferInfo   * pBufferInfo
    nullptr                                                                 // const VkBufferView             * pTexelBufferView
  } );
}

for( auto & buffer_descriptor : buffer_descriptor_infos ) {
  write_descriptors.push_back( {
    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                                 // VkStructureType                  sType
    nullptr,                                                                // const void                     * pNext
    buffer_descriptor.TargetDescriptorSet,                                  // VkDescriptorSet                  dstSet
    buffer_descriptor.TargetDescriptorBinding,                              // uint32_t                         dstBinding
    buffer_descriptor.TargetArrayElement,                                   // uint32_t                         dstArrayElement
    static_cast<uint32_t>(buffer_descriptor.BufferInfos.size()),            // uint32_t                         descriptorCount
    buffer_descriptor.TargetDescriptorType,                                 // VkDescriptorType                 descriptorType
    nullptr,                                                                // const VkDescriptorImageInfo    * pImageInfo
    buffer_descriptor.BufferInfos.data(),                                   // const VkDescriptorBufferInfo   * pBufferInfo
    nullptr                                                                 // const VkBufferView             * pTexelBufferView
  } );
}

for( auto & texel_buffer_descriptor : texel_buffer_descriptor_infos ) {
  write_descriptors.push_back( {
    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,                                 // VkStructureType                  sType
    nullptr,                                                                // const void                     * pNext
    texel_buffer_descriptor.TargetDescriptorSet,                            // VkDescriptorSet                  dstSet
    texel_buffer_descriptor.TargetDescriptorBinding,                        // uint32_t                         dstBinding
    texel_buffer_descriptor.TargetArrayElement,                             // uint32_t                         dstArrayElement
    static_cast<uint32_t>(texel_buffer_descriptor.TexelBufferViews.size()), // uint32_t                         descriptorCount
    texel_buffer_descriptor.TargetDescriptorType,                           // VkDescriptorType                 descriptorType
    nullptr,                                                                // const VkDescriptorImageInfo    * pImageInfo
    nullptr,                                                                // const VkDescriptorBufferInfo   * pBufferInfo
    texel_buffer_descriptor.TexelBufferViews.data()                         // const VkBufferView             * pTexelBufferView
  } );
}

我们还可以重用其他集合中的描述符。复制已填充的描述符应该比编写描述符更快。可以这样做:

std::vector<VkCopyDescriptorSet> copy_descriptors;

for( auto & copy_descriptor : copy_descriptor_infos ) {
  copy_descriptors.push_back( {
    VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET,                                  // VkStructureType    sType
    nullptr,                                                                // const void       * pNext
    copy_descriptor.SourceDescriptorSet,                                    // VkDescriptorSet    srcSet
    copy_descriptor.SourceDescriptorBinding,                                // uint32_t           srcBinding
    copy_descriptor.SourceArrayElement,                                     // uint32_t           srcArrayElement
    copy_descriptor.TargetDescriptorSet,                                    // VkDescriptorSet    dstSet
    copy_descriptor.TargetDescriptorBinding,                                // uint32_t           dstBinding
    copy_descriptor.TargetArrayElement,                                     // uint32_t           dstArrayElement
    copy_descriptor.DescriptorCount                                         // uint32_t           descriptorCount
  } );
}

更新描述符集的操作是通过单个函数调用执行的:

vkUpdateDescriptorSets( logical_device, static_cast<uint32_t>(write_descriptors.size()), write_descriptors.data(), static_cast<uint32_t>(copy_descriptors.size()), copy_descriptors.data() );

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值