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時,這個示例只是做了一個簡單的替換。

The blend constants are used for some of the “blend factors” (e.g., VK_BLEND_FACTOR_CONSTANT_COLOR) and are just set to something reasonable, as they are not used in this sample.
混合常量用於一些“混合因素”(例如,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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章