现在,我们可以结合前几章中所有结构体和对象来创建图形管线。它们是:
- 着色器阶段:定义图像管线可编程阶段的着色器模块
- 固定功能状态:定义管线固定功能阶段的结构体,包括输入组装、光栅化、视口和颜色混合
- 管线布局:着色器引用的可动态更新的
uniform
和push values
- 渲染通道:管线阶段引用的附件和其用法
这些结合起来就可以完整定义图形管线的功能了,现在我们在createGraphicsPipeline
函数末尾填充VkGraphicsPipelineCreateInfo
结构体。记得要在vkDestroyShaderModule
之前完成创建。
我们首先引用VkPipelineShaderStageCreateInfo
结构体:
VkGraphicsPipelineCreateInfo pipelineInfo{};
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineInfo.stageCount = 2;
pipelineInfo.pStages = shaderStages;
然后是固定功能状态:
pipelineInfo.pVertexInputState = &vertexInputInfo;
pipelineInfo.pInputAssemblyState = &inputAssembly;
pipelineInfo.pViewportState = &viewportState;
pipelineInfo.pRasterizationState = &rasterizer;
pipelineInfo.pMultisampleState = &multisampling;
pipelineInfo.pDepthStencilState = nullptr; // Optional
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr; // Optional
然后是管线布局,注意这里是个句柄:
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
最后,引用渲染通道和该图形管线要用的子通道的下标。该管线也可以使用其它渲染通道,但它们必须与renderPass
兼容。兼容性描述在这里,我们不会在本教程中使用。
pipelineInfo.renderPass = renderPass;
pipelineInfo.subpass = 0;
还有两个参数basePipelineHandle
和basePipelineIndex
。Vulkan允许你从现有管线派生来创建新的图形管线。派生的目的是降低设置管线的成本,并且在拥有相同父亲的管线之间切换可以拥有更好的性能。我们可以通过basePipelineHandle
指定现有管线,或通过basePipelineIndex
引用一个即将通过索引创建的管线。我们现在只有一个管线,所以这里设置为null
和无效索引。要使用这两个值还要在VkGraphicsPipelineCreateInfo
的flags
上设置VK_PIPELINE_CREATE_DERIVATIVE_BIT
。
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE; // Optional
pipelineInfo.basePipelineIndex = -1; // Optional
接下来,创建一个成员变量来保存VkPipeline
对象:
VkPipeline graphicsPipeline;
创建图形管线:
if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
throw std::runtime_error("failed to create graphics pipeline!");
}
vkCreateGraphicsPipelines
函数相比其它Vulkan的对象创建函数拥有更多的参数,其目的是为了同时创建多个管线对象。
其第二个参数可以传递一个VkPipelineCache
对象,它可以让我们存储和重用管线创建相关的数据,甚至可以存储到文件以跨程序使用。它可以显著加快管线的创建。我们之后在管线缓存一章中在讨论它。
常见的绘图操作均需要图形管线,因此,它也应该在程序结束时销毁:
void cleanup() {
vkDestroyPipeline(device, graphicsPipeline, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
...
}
现在,我们可以运行下程序,确保为了创建图形管线所做的这么多工作没有问题。我们已经非常接近能在屏幕上看到三角形了。接下来的几章,我们将从交换链图像创建真正的帧缓冲并准备绘制命令。
目录
上一节 绘制一个三角形/图形管线基础/渲染通道(Render passes)
下一节 绘制一个三角形/绘制/帧缓冲(Framebuffers)