创建着色器阶段

VkShaderModule对象只是一个对着色器字节码的包装。我们还需要指定它们在管线处理哪一阶段被使用。指定着色器阶段需要使用VkPipelineShaderStageCreateInfo结构体。

我们首先在createGraphicsPipeline函数中为顶点着色器填写VkPipelineShaderStageCreateInfo结构体信息:

VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;

上面代码,我们首先填写了sType成员变量,然后指定了着色器在管线的哪一阶段被使用。每个可编程阶段都有一个对应这一阶段的枚举值,我们使用这一枚举值指定着色器被使用的阶段。

vertShaderStageInfo.module = vertShaderModule;
vertShaderStageInfo.pName = "main";

module成员变量用于指定阶段使用的着色器模块对象,pName成员变量用于指定阶段调用的着色器函数。我们可以通过使用不同pName在同一份着色器代码中实现所有需要的着色器,比如在同一份代码中实现多个片段着色器,然后通过不同的pName调用它们。但在本教程,我们使用main作为它的值。

VkPipelineShaderStageCreateInfo还有一个可选的成员变量pSpecializationInfo,在这里,我们没有使用它,但这一成员变量非常值得我们在这里对它进行说明,我们可以通过这一成员变量指定着色器用到的常量,我们可以对同一个着色器模块对象指定不同的着色器常量用于管线创建,这使得编译器可以根据指定的着色器常量来消除一些条件分支,这比在渲染时,使用变量配置着色器带来的效率要高得多。如果不使用着色器常量,可以将pSpecializationInfo成员变量设置为nullptr。

接下来,填写用于片段着色器的VkPipelineShaderStageCreateInfo结构体:

VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragShaderStageInfo.module = fragShaderModule;
fragShaderStageInfo.pName = "main";

最后,我们定义包含上面定义的两个结构体的VkPipelineShaderStageCreateInfo数组,我们会在之后使用这一数组在管线创建时引用这两个结构体。

VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};

我们已经完成了管线的可编程阶段的设置,接下来的章节,我们开始配置管线的固定功能阶段。

本章节代码:

C++:

https://vulkan-tutorial.com/code/09_shader_modules.cpp

Vertex Shader:

https://vulkan-tutorial.com/code/09_shader_base.vert

Fragment Shader:

https://vulkan-tutorial.com/code/09_shader_base.frag