入门:调试Vulkan Samples(十二)——Pipeline

入门:调试Vulkan Samples(十二)——Pipeline

Pipeline

渲染管线(pipeline)描述顶点数据依次经过一系列阶段处理,最后转化为渲染目标上像素的过程。

渲染管线示意图

渲染管线示意图中绿色框表示固定(fixed-function)管线阶段,黄色框表示可编程(shader)管线阶段。


Vulkan的pipeline主要由几个shader stage、一串固定管线state, 一个pipeline layout和一个render pass组成。

VkPipeline 的创建需初始化VkGraphicsPipelineCreateInfo结构:

typedef struct VkGraphicsPipelineCreateInfo {
    VkStructureType                                  sType;
    const void*                                      pNext;
    VkPipelineCreateFlags                            flags;
    uint32_t                                         stageCount;
    const VkPipelineShaderStageCreateInfo*           pStages;
    const VkPipelineVertexInputStateCreateInfo*      pVertexInputState;
    const VkPipelineInputAssemblyStateCreateInfo*    pInputAssemblyState;
    const VkPipelineTessellationStateCreateInfo*     pTessellationState;
    const VkPipelineViewportStateCreateInfo*         pViewportState;
    const VkPipelineRasterizationStateCreateInfo*    pRasterizationState;
    const VkPipelineMultisampleStateCreateInfo*      pMultisampleState;
    const VkPipelineDepthStencilStateCreateInfo*     pDepthStencilState;
    const VkPipelineColorBlendStateCreateInfo*       pColorBlendState;
    const VkPipelineDynamicStateCreateInfo*          pDynamicState;
    VkPipelineLayout                                 layout;
    VkRenderPass                                     renderPass;
    uint32_t                                         subpass;
    VkPipeline                                       basePipelineHandle;
    int32_t                                          basePipelineIndex;
} VkGraphicsPipelineCreateInfo;


Vertex Input State

Vertex input state属于渲染管线示意图的input assembler阶段。

VkPipelineVertexInputStateCreateInfo 结构用于描述顶点数据结构,以便vertex shader访问:

    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;

该结构体主要包含两项属性:bingding和arrtibute。这些属性实例对象在vertex buffer阶段已经创建。


Vertex Input Assembly State

Vertex input assembly state属于渲染管线示意图的input assembler阶段。

VkPipelineInputAssemblyStateCreateInfo 结构用于描述输入的顶点数据几何图元的拓扑结构:

    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;


Rasterization State

光栅化阶段负责把图元离散化成一行一行的片段传递给片段着色器。该阶段还包括背面剔除、深度剔除(early-z)等操作。Rasterization state对应渲染管线示意图的Rasterization阶段。

VkPipelineRasterizationStateCreateInfo 结构包括描述该阶段剔除和深度相关的设置:

    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_FALSE;
    rs.rasterizerDiscardEnable = VK_FALSE;
    rs.depthBiasEnable = VK_FALSE;
    rs.depthBiasConstantFactor = 0;
    rs.depthBiasClamp = 0;
    rs.depthBiasSlopeFactor = 0;
    rs.lineWidth = 1.0f;

其中,polygonMode为片段生成模式,包括正常填充模式、线框模式和点模式。

顶点处理阶段之后还有primitive assembly阶段负责把被视锥裁剪后的顶点组装成新的图元。光栅化阶段处理的是primitive assembly阶段之后的图元。


Multisample State

VkPipelineMultisampleStateCreateInfo 结构用于配置管线多重采样相关的设置:

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;

其中,rasterizationSamples 为VK_SAMPLE_COUNT_1_BIT表示不在光栅化阶段做多重采样。

多重采样是为了抗锯齿,管线上的多重采样设置指的是MSAA硬件抗锯齿,区别于一些后期的AA技术。


Depth Stencil State

在片段颜色被混合之前,还需要经过 Scissor Test、Alpha Test 、Stencil Test 和Depth Test等片段剔除操作。Depth stencil state属于渲染管线示意图Fragment shader和Color blending之间的阶段(示意图未给出)。

VkPipelineDepthStencilStateCreateInfo 结构描述该阶段depth和stencil相关的设置:

    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;

其中,depthTestEnable表示是否开启深度测试;depthCompareOp表示深度比较规则,大部分情况下是VK_COMPARE_OP_LESS_OR_EQUAL; depthWriteEnable表示是否开启深度写入(透明渲染一般不开启)。

Stencil buffer也叫模板缓冲区,示例没用到,stencilTestEnable置成false;

Depth和stencil归类在一起配置,大部分原因是stencil buffer占用的是depth buffer的8位内存空间。


Color Blend State

颜色混合阶段描述片段着色器输出的颜色如何跟frambuffer现有的颜色进行混合。Color Blend state对应渲染管线示意图的Color blending阶段。

VkPipelineColorBlendStateCreateInfo结构由颜色混合参数组成:

    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;

其中,colorWriteMask为颜色掩码,0xf表示不过滤RGBA任何分量的值。

最常见的透明颜色混合模式参数设置为:

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

blendEnable 为fasle,其他等价于XXXBlendOp为VK_BLEND_OP_ADD, 同时srcXXXBlendFactor为VK_BLEND_FACTOR_ONE, dstXXXBlendFactor为VK_BLEND_FACTOR_ZERO。


Dynamic State

Vulkan开放了一些state的配置可以动态设置,而不需要创建新的pipeline,比如viewport的大小、深度偏移量和颜色混合常数等。

VkPipelineDynamicStateCreateInfo 结构用来保存这些动态设置:

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;

其中,pDynamicStates 指向保存动态设置枚举的数组,比如,配置viewport为动态设置为:

dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;


Viewport State

VkPipelineViewportStateCreateInfo结构用来描述viewport和scissor的配置:

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

示例的viewport和scissor被配置成动态设置,结构体的pScissors和pViewports均置为NULL。


创建 Pipeline

最后,把上述初始化好的结构体实例对象分别赋值给VkGraphicsPipelineCreateInfo结构对应的成员变量,完成VKPipeline对象的创建:

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);

其中,pipeline layout、shader stage和render pass之前的章节已创建好。

编辑于 2018-11-12

文章被以下专栏收录