操作系統(tǒng):Windows8.1

顯卡:Nivida GTX965M

開(kāi)發(fā)工具:Visual Studio 2017


早起的圖形API在圖形渲染管線的許多階段提供了默認(rèn)的狀態(tài)。在Vulkan中,從viewport的大小到混色函數(shù),需要凡事做到親歷親為。在本章節(jié)中我們會(huì)填充有關(guān)固有功能操作的所有結(jié)構(gòu)體。

Vertex input


VkPipelineVertexInputStateCreateInfo結(jié)構(gòu)體描述了頂點(diǎn)數(shù)據(jù)的格式,該結(jié)構(gòu)體數(shù)據(jù)傳遞到vertex shader中。它以兩種方式進(jìn)行描述:

  • Bindings:根據(jù)數(shù)據(jù)的間隙,確定數(shù)據(jù)是每個(gè)頂點(diǎn)或者是每個(gè)instance(instancing)

  • Attribute 描述:描述將要進(jìn)行綁定及加載屬性的頂點(diǎn)著色器中的相關(guān)屬性類型。

因?yàn)槲覀儗㈨旤c(diǎn)數(shù)據(jù)硬編碼到vertex shader中,所以我們將要填充的結(jié)構(gòu)體沒(méi)有頂點(diǎn)數(shù)據(jù)去加載。我們將會(huì)在vertex buffer章節(jié)中回來(lái)操作。

VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 0;
vertexInputInfo.pVertexBindingDescriptions = nullptr; // OptionalvertexInputInfo.vertexAttributeDescriptionCount = 0;
vertexInputInfo.pVertexAttributeDescriptions = nullptr; // Optional

pVertexBindingDescriptionspVertexAttributeDescriptions成員指向結(jié)構(gòu)體數(shù)組,用于進(jìn)一步描述加載的頂點(diǎn)數(shù)據(jù)信息。在createGraphicsPipeline函數(shù)中的shaderStages數(shù)組后添加該結(jié)構(gòu)體。

Input assembly


VkPipelineInputAssemblyStateCreateInfo結(jié)構(gòu)體描述兩件事情:頂點(diǎn)數(shù)據(jù)以什么類型的幾何圖元拓?fù)溥M(jìn)行繪制及是否啟用頂點(diǎn)索重新開(kāi)始圖元。圖元的拓?fù)浣Y(jié)構(gòu)類型topology枚舉值如下:

  • VK_PRIMITIVE_TOPOLOGY_POINT_LIST:頂點(diǎn)到點(diǎn)

  • VK_PRIMITIVE_TOPOLOGY_LINE_LIST:兩點(diǎn)成線,頂點(diǎn)不共用

  • VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:兩點(diǎn)成線,次索引的頂點(diǎn)作為后一個(gè)頂點(diǎn)的開(kāi)始頂點(diǎn),即頂點(diǎn)共用

  • VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST: 三點(diǎn)成面,頂點(diǎn)不共用

  • VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:三點(diǎn)成面,每第三個(gè)頂點(diǎn)作為下一個(gè)三角形的首個(gè)頂點(diǎn),即頂點(diǎn)共用

正常情況下,頂點(diǎn)數(shù)據(jù)按照緩沖區(qū)中的序列作為索引,但是也可以通過(guò)element buffer緩沖區(qū)自行指定頂點(diǎn)數(shù)據(jù)的索引。通過(guò)復(fù)用頂點(diǎn)數(shù)據(jù)提升性能。如果設(shè)置primitiveRestartEnable成員為VK_TRUE,可以通過(guò)0xFFFF或者0xFFFFFFFF作為特殊索引來(lái)分解線和三角形在_STRIP模式下的圖元拓?fù)浣Y(jié)構(gòu)。

通過(guò)本教程繪制三角形,所以我們堅(jiān)持按照如下格式填充數(shù)據(jù)結(jié)構(gòu):

VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
inputAssembly.primitiveRestartEnable = VK_FALSE;

Viewports and scissors


viewport用于描述framebuffer作為渲染輸出結(jié)果目標(biāo)區(qū)域。它的數(shù)值在本教程中總是設(shè)置在(0, 0)(width, height)。

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

VkViewport viewport = {};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = (float) swapChainExtent.width;
viewport.height = (float) swapChainExtent.height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

記得交換鏈和它的images圖像大小WIDTHHEIGHT會(huì)根據(jù)不同的窗體而不同。交換鏈圖像將會(huì)在幀緩沖區(qū)framebuffers使用,所以我們應(yīng)該堅(jiān)持它們的大小。

 

minDepthmaxDepth數(shù)值指定framebuffer中深度的范圍。這些數(shù)值必須收斂在[0.0f, 1.0f]區(qū)間沖,但是minDepth可能會(huì)大于maxDepth。如果你不做任何指定,建議使用標(biāo)準(zhǔn)的數(shù)值0.0f和1.0f。

 

viewports定義了image圖像到framebuffer幀緩沖區(qū)的轉(zhuǎn)換關(guān)系,裁剪矩形定義了哪些區(qū)域的像素被存儲(chǔ)。任何在裁剪巨型外的像素都會(huì)在光柵化階段丟棄。它們的功能更像過(guò)濾器而不是定義轉(zhuǎn)換關(guān)系。這個(gè)區(qū)別如下圖所示。需要注意的是,對(duì)于圖像比viewport尺寸大的情形,左側(cè)的裁剪矩形只是眾多可能的一個(gè)表現(xiàn)。

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

在本教程中我們需要將圖像繪制到完整的幀緩沖區(qū)framebuffer中,所以我們定義裁剪矩形覆蓋到整體圖像:

VkRect2D scissor = {};
scissor.offset = {0, 0};
scissor.extent = swapChainExtent;

viewport和裁剪矩形需要借助VkPipelineViewportStateCreateInfo結(jié)構(gòu)體聯(lián)合使用??梢允褂枚鄓iewports和裁剪矩形在一些圖形卡,通過(guò)數(shù)組引用。使用該特性需要GPU支持該功能,具體看邏輯設(shè)備的創(chuàng)建。

VkPipelineViewportStateCreateInfo viewportState = {};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportState.viewportCount = 1;
viewportState.pViewports = &viewport;
viewportState.scissorCount = 1;
viewportState.pScissors = &scissor;

Rasterizer


光柵化通過(guò)頂點(diǎn)著色器及具體的幾何算法將頂點(diǎn)進(jìn)行塑形,并將圖形傳遞到片段著色器進(jìn)行著色工作。它也會(huì)執(zhí)行深度測(cè)試depth testing、面裁切face culling和裁剪測(cè)試,它可以對(duì)輸出的片元進(jìn)行配置,決定是否輸出整個(gè)圖元拓?fù)浠蛘呤沁吙?線框渲染)。所有的配置通過(guò)VkPipelineRasterizationStateCreateInfo結(jié)構(gòu)體定義。

VkPipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;

它的depthClampEnable設(shè)置為VK_TRUE,超過(guò)遠(yuǎn)近裁剪面的片元會(huì)進(jìn)行收斂,而不是丟棄它們。它在特殊的情況下比較有用,像陰影貼圖。使用該功能需要得到GPU的支持。

rasterizer.rasterizerDiscardEnable = VK_FALSE;

如果rasterizerDiscardEnable設(shè)置為VK_TRUE,那么幾何圖元永遠(yuǎn)不會(huì)傳遞到光柵化階段。這是基本的禁止任何輸出到framebuffer幀緩沖區(qū)的方法。

rasterizer.polygonMode = VK_POLYGON_MODE_FILL;

polygonMode決定幾何產(chǎn)生圖片的內(nèi)容。下列有效模式:

  • VK_POLYGON_MODE_FILL: 多邊形區(qū)域填充

  • VK_POLYGON_MODE_LINE: 多邊形邊緣線框繪制

  • VK_POLYGON_MODE_POINT: 多邊形頂點(diǎn)作為描點(diǎn)繪制

使用任何模式填充需要開(kāi)啟GPU功能。

rasterizer.lineWidth = 1.0f;

lineWidth成員是直接填充的,根據(jù)片元的數(shù)量描述線的寬度。最大的線寬支持取決于硬件,任何大于1.0的線寬需要開(kāi)啟GPU的wideLines特性支持。

rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;

cullMode變量用于決定面裁剪的類型方式??梢越筩ulling,裁剪front faces,cull back faces 或者全部。frontFace用于描述作為front-facing面的頂點(diǎn)的順序,可以是順時(shí)針也可以是逆時(shí)針。

rasterizer.depthBiasEnable = VK_FALSE;
rasterizer.depthBiasConstantFactor = 0.0f; // Optionalrasterizer.depthBiasClamp = 0.0f; // Optionalrasterizer.depthBiasSlopeFactor = 0.0f; // Optional

光柵化可以通過(guò)添加常量或者基于片元的斜率來(lái)更改深度值。一些時(shí)候?qū)τ陉幱百N圖是有用的,但是我們不會(huì)在章節(jié)中使用,設(shè)置depthBiasEnableVK_FALSE。

Multisampling


VkPipelineMultisampleStateCreateInfo結(jié)構(gòu)體用于配置多重采樣。所謂多重采樣是抗鋸齒anti-aliasing的一種實(shí)現(xiàn)。它通過(guò)組合多個(gè)多邊形的片段著色器結(jié)果,光柵化到同一個(gè)像素。這主要方法在邊緣,這也是最醒目的鋸齒發(fā)生的地方。如果只有一個(gè)多邊形映射到像素是不需要多次運(yùn)行片段著色器進(jìn)行采樣的,相比高分辨率來(lái)說(shuō),它會(huì)花費(fèi)較低的開(kāi)銷。開(kāi)啟該功能需要GPU支持。

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
multisampling.minSampleShading = 1.0f; // Optionalmultisampling.pSampleMask = nullptr; // Optionalmultisampling.alphaToCoverageEnable = VK_FALSE; // Optionalmultisampling.alphaToOneEnable = VK_FALSE; // Optional

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

在本教程中我們不會(huì)使用多重采樣,但是可以隨意的嘗試,具體的參數(shù)請(qǐng)參閱規(guī)范。

Depth and stencil testing


如果使用depth 或者 stencil緩沖區(qū),需要使用VkPipelineDepthStencilStateCreateInfo配置。我們現(xiàn)在不需要使用,所以簡(jiǎn)單的傳遞nullptr,關(guān)于這部分會(huì)專門在深度緩沖區(qū)章節(jié)中討論。

Color blending


片段著色器輸出具體的顏色,它需要與幀緩沖區(qū)framebuffer中已經(jīng)存在的顏色進(jìn)行混合。這個(gè)轉(zhuǎn)換的過(guò)程成為混色,它有兩種方式:

  • 將old和new顏色進(jìn)行混合產(chǎn)出一個(gè)最終的顏色

  • 使用按位操作混合old和new顏色的值

有兩個(gè)結(jié)構(gòu)體用于配置顏色混合。第一個(gè)結(jié)構(gòu)體VkPipelineColorBlendAttachmentState包括了每個(gè)附加到幀緩沖區(qū)的配置。第二個(gè)結(jié)構(gòu)體VkPipelineColorBlendStateCreateInfo包含了全局混色的設(shè)置。在我們的例子中僅使用第一種方式:

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

VkPipelineColorBlendAttachmentState colorBlendAttachment = {};
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
colorBlendAttachment.blendEnable = VK_FALSE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // OptionalcolorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // OptionalcolorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; // OptionalcolorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // OptionalcolorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // OptionalcolorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; // Optional

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

這種針對(duì)每個(gè)幀緩沖區(qū)配置混色的方式,使用如下偽代碼進(jìn)行說(shuō)明:

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

if (blendEnable) {
    finalColor.rgb = (srcColorBlendFactor * newColor.rgb) <colorBlendOp> (dstColorBlendFactor * oldColor.rgb);
    finalColor.a = (srcAlphaBlendFactor * newColor.a) <alphaBlendOp> (dstAlphaBlendFactor * oldColor.a);
} else {
    finalColor = newColor;
}

finalColor = finalColor & colorWriteMask;

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

如果blendEnable設(shè)置為VK_FALSE,那么從片段著色器輸出的新顏色不會(huì)發(fā)生變化,否則兩個(gè)混色操作會(huì)計(jì)算新的顏色。所得到的結(jié)果與colorWriteMask進(jìn)行AND運(yùn)算,以確定實(shí)際傳遞的通道。

 

大多數(shù)的情況下使用混色用于實(shí)現(xiàn)alpha blending,新的顏色與舊的顏色進(jìn)行混合會(huì)基于它們的opacity透明通道。finalColor作為最終的輸出:

finalColor.rgb = newAlpha * newColor + (1 - newAlpha) * oldColor;
finalColor.a = newAlpha.a;

可以通過(guò)一下參數(shù)完成:

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

colorBlendAttachment.blendEnable = VK_TRUE;
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

可以在規(guī)范中找到所有有關(guān)VkBlendFactorVkBlendOp的枚舉值。

 

第二個(gè)結(jié)構(gòu)體持有所有幀緩沖區(qū)的引用,它允許設(shè)置混合操作的常量,該常量可以作為后續(xù)計(jì)算的混合因子:

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

VkPipelineColorBlendStateCreateInfo colorBlending = {};
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlending.logicOpEnable = VK_FALSE;
colorBlending.logicOp = VK_LOGIC_OP_COPY; // OptionalcolorBlending.attachmentCount = 1;
colorBlending.pAttachments = &colorBlendAttachment;
colorBlending.blendConstants[0] = 0.0f; // OptionalcolorBlending.blendConstants[1] = 0.0f; // OptionalcolorBlending.blendConstants[2] = 0.0f; // OptionalcolorBlending.blendConstants[3] = 0.0f; // Optional

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

如果需要使用第二種方式設(shè)置混合操作(bitwise combination), 需要設(shè)置logicOpEnableVK_TURE。二進(jìn)制位操作在logicOp字段中指定。在第一種方式中會(huì)自動(dòng)禁止,等同于為每一個(gè)附加的幀緩沖區(qū)framebuffer關(guān)閉混合操作,blendEnableVK_FALSE。colorWriteMask掩碼會(huì)用確定幀緩沖區(qū)中具體哪個(gè)通道的顏色受到影響。它也可以在兩種方式下禁止,截至目前,片段緩沖區(qū)向幀緩沖區(qū)中輸出的顏色不會(huì)進(jìn)行任何變化。

Dynamic state


之前創(chuàng)建的一些結(jié)構(gòu)體的狀態(tài)可以在運(yùn)行時(shí)動(dòng)態(tài)修改,而不必重新創(chuàng)建。比如viewport的大小,line width和blend constants。如果需要進(jìn)行這樣的操作,需要填充VkPipelineDynamicStateCreateInfo結(jié)構(gòu)體:

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

VkDynamicState dynamicStates[] = {
    VK_DYNAMIC_STATE_VIEWPORT,
    VK_DYNAMIC_STATE_LINE_WIDTH
};

VkPipelineDynamicStateCreateInfo dynamicState = {};
dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicState.dynamicStateCount = 2;
dynamicState.pDynamicStates = dynamicStates;

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

在繪制的過(guò)程中指定這些數(shù)據(jù),這會(huì)導(dǎo)致忽略之前的相關(guān)數(shù)值。我們會(huì)在后續(xù)的章節(jié)中回過(guò)頭來(lái)討論。如果沒(méi)有任何需要?jiǎng)討B(tài)修改的數(shù)值清設(shè)置為nullptr

Pipeline layout


可以在著色器中使用uniform,它是類似與動(dòng)態(tài)狀態(tài)變量的全局變量,可以在繪畫時(shí)修改,可以更改著色器的行為而無(wú)需重新創(chuàng)建它們。它們通常用于將變換矩陣傳遞到頂點(diǎn)著色器或者在片段著色器沖創(chuàng)建紋理采樣器。

 

這些uniform數(shù)值需要在管線創(chuàng)建過(guò)程中,通過(guò)VkPipelineLayout對(duì)象指定。即使在后續(xù)內(nèi)容中用到,我們也仍然需要?jiǎng)?chuàng)建一個(gè)空的pipeline layout。

 

創(chuàng)建類成員變量持有該對(duì)象,因?yàn)槲覀冊(cè)诤罄m(xù)章節(jié)中的函數(shù)中引用它:

VkPipelineLayout pipelineLayout;

createGraphicsPipeline函數(shù)中創(chuàng)建對(duì)象:

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0; // OptionalpipelineLayoutInfo.pSetLayouts = nullptr; // OptionalpipelineLayoutInfo.pushConstantRangeCount = 0; // OptionalpipelineLayoutInfo.pPushConstantRanges = 0; // Optionalif (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {    throw std::runtime_error("failed to create pipeline layout!");
}

平面設(shè)計(jì)培訓(xùn),網(wǎng)頁(yè)設(shè)計(jì)培訓(xùn),美工培訓(xùn),游戲開(kāi)發(fā),動(dòng)畫培訓(xùn)

該結(jié)構(gòu)體還指定了push常量,這是將動(dòng)態(tài)值傳遞給著色器的拎一個(gè)方式。pipeline layout可以在整個(gè)程序的生命周期內(nèi)引用,所以它在程序退出的時(shí)候進(jìn)行銷毀。

void cleanup() {
    vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
    ...
}

Conclusion


這就是所有有關(guān)fixed-function的內(nèi)容,看起來(lái)有很多的工作去做,值得慶幸的是我們幾乎了解了所有有關(guān)渲染管線的內(nèi)容。這個(gè)過(guò)程減少了因?yàn)椴涣私饽承┙M件的默認(rèn)狀態(tài),而造成運(yùn)行時(shí)碰到未知行為的可能性。

 

然而,在我們可以最終創(chuàng)建圖形管線之前,還有一個(gè)對(duì)象需要?jiǎng)?chuàng)建,它就是render pass。

http://www.cnblogs.com/heitao/p/6974203.html