描述符集合布局和管线布局
本节的代码是 08-init_pipeline_layout.cpp
在前面的例子中,您创建了一个uniform 缓冲区,但是您没有告诉着色器该如何使用它。缓冲区包含了MVP转换的Uiform变量,它只会被顶点着色器使用,但是Vulkan还不知道这一点。
我们通过使用描述符来实现这一点。
描述符和描述符集合
描述符是一个特殊的不透明的着色器变量,着色器使用它以间接的方式访问缓冲区和图像资源。它可以被认为是一个资源的“指针”。Vulkan API允许在绘制操作之间更改这些变量,以便着色器能够为每次绘制访问不同的资源。
在样例例子中,您只有一个Uniform 缓冲区。但是你可以创建两个Uniform 缓冲区,每个缓冲区都有一个不同的MVP来给出不同的场景视图。然后,您可以很容易地改变描述符,以指向任何一个Uniform 缓冲区,以便在MVP矩阵之间来回切换。
描述符集合被称为“集合”,因为它可以引用一组同构资源,可以用相同的布局绑定(Layout Binding)来描述。
在本例中,您没有使用纹理,但是使用多个描述符的一种可能方法是用两个描述符构造一个描述符集合,每个描述符引用一个单独的纹理。因此,在绘制过程中,两种纹理都是可用的。然后,命令缓冲区中的命令可以通过指定所需纹理的索引来选择纹理。
需要注意的是,您只是在“描述”这里的描述符集合,实际上并没有真正地分配或创建描述符集合本身,稍后您将在"Descriptor_Set"示例中进行描述。
为了描述描述符集合,您可以使用描述符集合布局。
描述符集布局
描述符集合布局是用来描述描述符列表里的内容。
对于每个描述符集合,您还需要一个布局绑定,您可以使用它来描述每个描述符集合:
VkDescriptorSetLayoutBinding layout_binding = {};
layout_binding.binding = 0;
layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
layout_binding.descriptorCount = 1;
layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
layout_binding.pImmutableSamplers = NULL;
- 您只有一个描述符集合,所以
binding
成员的惟一选择是0。 - 因为这个描述符引用了一个Uniform 缓冲区,所以您适当地设置了
descriptorType
。 - 在这个描述符集合中,您只有一个描述符,它由
descriptorCount
成员表示。 - 您指出,这个Uniform 缓冲区资源将被绑定到shader顶点阶段。
当这个描述符集的绑定被定义好之后,我们就可以创建一个描述符集合布局:
#define NUM_DESCRIPTOR_SETS 1
VkDescriptorSetLayoutCreateInfo descriptor_layout = {};
descriptor_layout.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptor_layout.pNext = NULL;
descriptor_layout.bindingCount = 1;
descriptor_layout.pBindings = &layout_binding;
info.desc_layout.resize(NUM_DESCRIPTOR_SETS);
res = vkCreateDescriptorSetLayout(info.device, &descriptor_layout, NULL,
info.desc_layout.data());
管线布局
管道布局包含一个描述符集合布局的列表。它还可以包含一个推送常量范围的列表,这是将常量传递给着色器的另一种方法,在这里先不涉及。
与描述符集合一样,您只是定义了布局。实际的描述符集合的内存分配和填充,会在稍后的uniform 缓冲引用中。
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {};
pPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pPipelineLayoutCreateInfo.pNext = NULL;
pPipelineLayoutCreateInfo.pushConstantRangeCount = 0;
pPipelineLayoutCreateInfo.pPushConstantRanges = NULL;
pPipelineLayoutCreateInfo.setLayoutCount = NUM_DESCRIPTOR_SETS;
pPipelineLayoutCreateInfo.pSetLayouts = info.desc_layout.data();
res = vkCreatePipelineLayout(info.device, &pPipelineLayoutCreateInfo, NULL,
&info.pipeline_layout);
稍后您将使用管道布局来创建图形管道。
描述符的着色器引用
值得指出的是,着色器明确地引用了着色器语言中的这些描述符。
例如, 在 GLSL里:
layout (set=M, binding=N) uniform sampler2D variableNameArray[I];
- M表示管线布局中的
pSetLayouts
- N表示M的描述符集合布局中的
pBindings
- I表示N的描述符集合中描述符的索引
在您将要使用的顶点着色器中,Uniform 缓冲区的布局代码看起来像:
layout (std140, binding = 0) uniform bufferVals {
mat4 mvp;
} myBufferVals;
这将uniform 缓冲区内容映射到myBufferVals
结构。“set=M”没有指定,默认为0。
“std140”是描述数据如何在统一块中打包的标准。如果您希望将更多的数据放在一个统一的块中,您可能希望引用它。更多信息请查看 这个文档 。
© Copyright 2016 LunarG, Inc