vulkan杂记-描述符布局

我们已经可以传递顶点属性给顶点着色器,但对于一些所有顶
点都共享的属性,比如顶点的变换矩阵,将它们作为顶点属性为每个顶点
都传递一份显然是非常浪费的。

Vulkan 提供了资源描述符来解决这一问题。

描述符是用来在着色器中
访问缓冲和图像数据的一种方式。我们可以将变换矩阵存储在一个缓冲中,
然后通过描述符在着色器中访问它。

使用描述符需要进行下面三部分的设置:

• 在管线创建时指定描述符布局
• 从描述符池分配描述符集
• 在渲染时绑定描述符集

描述符布局用于指定可以被管线访问的资源类型,类似渲染流程指定
可以被访问的附着类型。

描述符集指定了要绑定到描述符上的缓冲和图像
资源,类似帧缓冲指定绑定到渲染流程附着上的图像视图。

最后,将描述
符集绑定到绘制指令上,类似绑定顶点缓冲和帧缓冲到绘制指令上。

有多种类型的描述符,但在本章节,我们只使用 uniform 缓冲对象
(UBO)。

现在,让我们先用结构体定义我们要在着色器
中使用的 uniform 数据:

s t r u c t   UniformBufferObject {
glm : : mat4 model ;
glm : : mat4 view ;
glm : : mat4 p r o j ;
};

我们将要使用的 uniform 数据复制到一个 VkBuffer 中,然后通过一个
uniform 缓冲对象描述符在顶点着色器中访问它:

binding 修饰符类似于我们对顶点属性使用的 location 修饰符。我
们会在描述符布局引用这个 binding 值。

描述符集布局

下一步,我们在应用程序的代码中定义 UBO:

s t r u c t         UniformBufferObject {
glm : : mat4 model ;
glm : : mat4 view ;
glm : : mat4 p r o j ;
};

我们需要在管线创建时提供着色器使用的每一个描述符绑定信息。我
们添加了一个叫做 createDescriptorSetLayout 的函数,来完成这项工作。

我们需要使用 VkDescriptorSetLayoutBinding 结构体来描述每一个绑定:

void c r e a t e D e s c r i p t o r S e t L a y o u t ( ) {
VkDescriptorSetLayoutBinding uboLayoutBinding = { } ;
uboLayoutBinding . b i n d i n g = 0 ;
uboLayoutBinding . d e s c r i p t o r T y p e =
uboLayoutBinding . d e s c r i p t o r C o u n t = 1 ;
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
}

binding 和 descriptorType 成员变量用于指定着色器使用的描述符绑
定和描述符类型。

着色器变量
可以用来表示 uniform 缓冲对象数组,descriptorCount 成员变量用来指定
数组中元素的个数。

我们可以使用数组来指定骨骼动画使用的所有变换矩
阵。在这里,我们的 MVP 矩阵只需要一个 uniform 缓冲对象,所以我们
将 descriptorCount 的值设置为 1。

uboLayoutBinding . s t a g e F l a g s = VK_SHADER_STAGE_VERTEX_BIT;

我们还需要指定描述符在哪一个着色器阶段被使用。stageFlags 成员变
量可以指定通过 VkShaderStageFlagBits 组合或 VK_SHADER_STAGE_ALL_GRAPHICS
指定描述符被使用的着色器阶段。

uboLayoutBinding . pImmutableSamplers = n u l l p t r ;

pImmutableSamplers 成员变量仅用于和图像采样相关的描述符。这里
我们先将其设置为默认值

所有的描述符绑定被组合进一个 VkDescriptorSetLayout 对象。

调用 vkCreateDescriptorSetLayout 函数创建 VkDescriptorSetLayout
对 象。 vkCreateDescriptorSetLayout 函 数 以 VkDescriptorSetLayoutCre-
ateInfo 结构体作为参数:

我们需要在管线创建时指定着色器需要使用的描述符集布局。

管线布局对象指定了管线使用的描述符集布局。修改 VkPipelineLayoutCreateInfo
结构体信息引用布局对象:

VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
p i p e l i n e L a y o u t I n f o . sType= VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;

p i p e l i n e L a y o u t I n f o . setLayoutCount = 1 ;
p i p e l i n e L a y o u t I n f o . pSetLayouts = &d e s c r i p t o r S e t L a y o u t ;

描述符布局对象可以在应用程序的整个生命周期使用,即使使用了新
的管线对象。通常我们在应用程序退出前才清除它:

void cleanup ( ) {
cleanupSwapChain ( ) ;
vk D e s t ro y De s c ri p t or S e t L a y o u t ( d e v i c e ,
descriptorSetLayout , nullptr ) ;
...
}

uniform 缓冲

在下一章节,我们将会为着色器指定包含 UBO 数据的缓冲对象。我
们首先需要创建用于包含数据的缓冲对象,然后在每一帧将新的 UBO 数
据复制到 uniform 缓冲。由于需要频繁的数据更新,在这里使用暂存缓冲
并不会带来性能提升。

由于我们同时并行渲染多帧的缘故,我们需要多个 uniform 缓冲,来
满足多帧并行渲染的需要。

我们可以对并行渲染的每一帧或每一个交换链
图像使用独立的 uniform 缓冲对象。由于我需要在指令缓冲中引用 uniform
缓冲,对于每个交换链图像使用独立的 uniform 缓冲对象相对来说更加方
便。

s t d : : v e c t o r <VkBuffer> u n i f o r m B u f f e r s ;
s t d : : v e c t o r <VkDeviceMemory> uniformBuffersMemory ;

更新 uniform 数据

添加一个叫做 updateUniformBuffer 的函数,然后在 drawFrame 函数
中我们已经可以确定获取交换链图像是哪一个后调用它:

调用 updateUniformBuffer 函数可以在每一帧产生一个新的变换矩阵。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

祝太勇

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

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

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

打赏作者

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

抵扣说明:

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

余额充值