Vulkan【15】图形管线(Graphics Pipline)

创建图形管线

本节的代码是 14-init_pipeline.cpp

你越来越接近把这些拉到一起来渲染一个立方体!下一步是通过设置图形管道来配置GPU来进行渲染。

一个图形管线由着色阶段、管线布局、渲染过程和固定功能管线阶段组成。您在前面的部分中定义了着色阶段和管线布局。在这里,您将配置其余的固定功能管线阶段。这包括填充一些用于创建管线的“create info”数据结构。在这里执行的大部分工作都配置了逐片段操作,就在这些片段被放置到framebuffer之前。

如下图:

Graphics Pipeline

下一步是配置管线状态对象,由右下方的灰色方框表示。最后一步是将指向左上角的紫色管线框连接起来,以完成图形管线的定义。

动态状态

动态管线状态是这样的一种状态:它可以在命令缓冲区执行期间被命令改变。
在命令缓冲区执行过程中,预先通知哪些状态是动态的,这对于驱动程序来说是很有用的,因为它设置了用于命令缓冲区执行的GPU。

样例提供了它打算在命令缓冲区执行期间更改的状态列表。在这里,代码首先创建一个动态状态列表,并在它们开始时全部禁用。

VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
VkPipelineDynamicStateCreateInfo dynamicState = {};
memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.pNext = NULL;
dynamicState.pDynamicStates = dynamicStateEnables;
dynamicState.dynamicStateCount = 0;

稍后,示例表明它将通过一个命令缓冲区命令动态地改变一些状态,所以在配置viewport 和scissors时,它将改变dynamicStateEnables数组。
为了清晰起见,修改dynamicStateEnables的代码会始终保持在viewport 和 scissors配置之后。

管线顶点输入状态

当你创建顶点缓冲时,你已经初始化了顶点输入状态,因为在那个时候它很简单。输入状态包括顶点数据的格式和排列。您可以查看“顶点缓冲区”示例,看看如何设置vi_bindingvi_binding 变量。

VkPipelineVertexInputStateCreateInfo vi;
vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vi.pNext = NULL;
vi.flags = 0;
vi.vertexBindingDescriptionCount = 1;
vi.pVertexBindingDescriptions = &info.vi_binding;
vi.vertexAttributeDescriptionCount = 2;
vi.pVertexAttributeDescriptions = info.vi_attribs;

管线顶点输入装配状态

输入装配状态基本上表明了你希望你的顶点画成什么样的几何。比如点、线、三角条带或者三角扇形。在这里,我们只使用三角形列表,每三个顶点构成一个三角形:

VkPipelineInputAssemblyStateCreateInfo ia;
ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
ia.pNext = NULL;
ia.flags = 0;
ia.primitiveRestartEnable = VK_FALSE;
ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;

管线光栅化状态

下一个数据结构在GPU中配置光栅化操作。

VkPipelineRasterizationStateCreateInfo rs;
rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rs.pNext = NULL;
rs.flags = 0;
rs.polygonMode = VK_POLYGON_MODE_FILL;
rs.cullMode = VK_CULL_MODE_BACK_BIT;
rs.frontFace = VK_FRONT_FACE_CLOCKWISE;
rs.depthClampEnable = VK_TRUE;
rs.rasterizerDiscardEnable = VK_FALSE;
rs.depthBiasEnable = VK_FALSE;
rs.depthBiasConstantFactor = 0;
rs.depthBiasClamp = 0;
rs.depthBiasSlopeFactor = 0;
rs.lineWidth = 1.0f;

这些字段设置了一些相当常见的值。您可能会发现到frontFace成员与GL函数glFrontFace()之间的相关性。

管线颜色混合状态

混合是另一个“固定管道的结束”操作,您可以在这里进行配置,以简单地替换目标中的像素:

VkPipelineColorBlendStateCreateInfo cb;
cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
cb.pNext = NULL;
cb.flags = 0;
VkPipelineColorBlendAttachmentState att_state[1];
att_state[0].colorWriteMask = 0xf;
att_state[0].blendEnable = VK_FALSE;
att_state[0].alphaBlendOp = VK_BLEND_OP_ADD;
att_state[0].colorBlendOp = VK_BLEND_OP_ADD;
att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_ZERO;
att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO;
att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
att_state[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
cb.attachmentCount = 1;
cb.pAttachments = att_state;
cb.logicOpEnable = VK_FALSE;
cb.logicOp = VK_LOGIC_OP_NO_OP;
cb.blendConstants[0] = 1.0f;
cb.blendConstants[1] = 1.0f;
cb.blendConstants[2] = 1.0f;
cb.blendConstants[3] = 1.0f;

注意,有些配置信息是根据每个附件提供的。在您的管线中,您需要为每个颜色附件都有一个VkPipelineColorBlendAttachmentState。在这个例子里,只有一个颜色附件。

colorWriteMask表示R,G,B,A这四个部分中哪些可以被写入。此处,你允许四个都可被写入。

禁用blendEnable表明在att_state[0]中剩下的与混合相关的设置将不起作用。

您还禁用了“写像素逻辑”操作,因为在将像素写入framebuffer时,这个示例只是做了一个简单的替换。

混合常量用于一些“混合因素”(例如,VK_BLEND_FACTOR_CONSTANT_COLOR),并被设置为一些合理的东西,只是它们在本示例中没有使用。

管道视口状态

"渲染立方体"样例将使用命令缓冲区中的命令来设置viewport和scissors 矩形。这段代码告诉驱动程序,这些viewport和scissors 状态是动态的,且忽略了pViewPortspScissors 成员。

VkPipelineViewportStateCreateInfo vp = {};
vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
vp.pNext = NULL;
vp.flags = 0;
vp.viewportCount = 1;
dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
vp.scissorCount = 1;
dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;
vp.pScissors = NULL;
vp.pViewports = NULL;

管道深度模板状态

继续使用后端固定功能初始化,通过为常用的配置设置深度缓冲,并禁用模板操作。

VkPipelineDepthStencilStateCreateInfo ds;
ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
ds.pNext = NULL;
ds.flags = 0;
ds.depthTestEnable = VK_TRUE;
ds.depthWriteEnable = VK_TRUE;
ds.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
ds.depthBoundsTestEnable = VK_FALSE;
ds.minDepthBounds = 0;
ds.maxDepthBounds = 0;
ds.stencilTestEnable = VK_FALSE;
ds.back.failOp = VK_STENCIL_OP_KEEP;
ds.back.passOp = VK_STENCIL_OP_KEEP;
ds.back.compareOp = VK_COMPARE_OP_ALWAYS;
ds.back.compareMask = 0;
ds.back.reference = 0;
ds.back.depthFailOp = VK_STENCIL_OP_KEEP;
ds.back.writeMask = 0;
ds.front = ds.back;

因为您确实想要深度缓冲,所以您可以启用深度缓冲写入和测试。另外,您将深度缓冲比较操作设置为常用的VK_COMPARE_OP_LESS_OR_EQUAL。最后,您禁用了模板操作,因为这个示例不需要它。

管线多重采样状态

在这个例子中,你不会去做任何高昂的多重采样才做,所以通过设置无多重采样来完成管线配置。

VkPipelineMultisampleStateCreateInfo ms;
ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
ms.pNext = NULL;
ms.flags = 0;
ms.pSampleMask = NULL;
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
ms.sampleShadingEnable = VK_FALSE;
ms.alphaToCoverageEnable = VK_FALSE;
ms.alphaToOneEnable = VK_FALSE;
ms.minSampleShading = 0.0;

把所有的东西都组合到一起——创建图形管线

最后,您拥有创建管道所需的所有信息:

VkGraphicsPipelineCreateInfo pipeline;
pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline.pNext = NULL;
pipeline.layout = info.pipeline_layout;
pipeline.basePipelineHandle = VK_NULL_HANDLE;
pipeline.basePipelineIndex = 0;
pipeline.flags = 0;
pipeline.pVertexInputState = &vi;
pipeline.pInputAssemblyState = &ia;
pipeline.pRasterizationState = &rs;
pipeline.pColorBlendState = &cb;
pipeline.pTessellationState = NULL;
pipeline.pMultisampleState = &ms;
pipeline.pDynamicState = &dynamicState;
pipeline.pViewportState = &vp;
pipeline.pDepthStencilState = &ds;
pipeline.pStages = info.shaderStages;
pipeline.stageCount = 2;
pipeline.renderPass = info.render_pass;
pipeline.subpass = 0;

res = vkCreateGraphicsPipelines(info.device, NULL, 1,
                                &pipeline, NULL, &info.pipeline);

info.pipeline_layout, info.shaderStages, 和info.render_pass 成员已经在本教程之前的几个章节中被初始化。剩下的也在本节中被设置。

在创建管线之后,您就可以继续下一节并绘制立方体了。

© Copyright 2016 LunarG, Inc

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值