Vulkan 围炉夜话3

简介: Vulkan 围炉夜话

Vulkan 围炉夜话2:https://developer.aliyun.com/article/1598109

创建图形流水线 —— vkCreateGraphicsPipelines

   图形流水线中包含了可编程以及固定函数的流水线阶段,此外还有渲染通道、子通道和流水线布局。可编程阶段中包含了多个着色器阶段,包括顶点、片元、细分、几何和计算着色器。固定函数阶段中包括了多个流水线状态对象(Pipeline State Object,PSO)来记录动态、顶点输入、输入装配、光栅化、融混、视口、多重采用,以及深度 —— 模板状态信息。

VKAPI_ATTR VkResult VKAPI_CALL vkCreateGraphicsPipelines(
    VkDevice                                    device,
    VkPipelineCache                             pipelineCache,
    uint32_t                                    createInfoCount,
    const VkGraphicsPipelineCreateInfo*         pCreateInfos,
    const VkAllocationCallbacks*                pAllocator,
    VkPipeline*                                 pPipelines);
  1. 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;

VkPipelineShaderStageCreateInfo —— 着色器阶段
typedef struct VkPipelineShaderStageCreateInfo {
    VkStructureType                     sType;
    const void*                         pNext;
    VkPipelineShaderStageCreateFlags    flags;
    VkShaderStageFlagBits               stage;
    VkShaderModule                      module;
    const char*                         pName;
    const VkSpecializationInfo*         pSpecializationInfo;
} VkPipelineShaderStageCreateInfo;

typedef struct VkSpecializationInfo {
    uint32_t                           mapEntryCount;
    const VkSpecializationMapEntry*    pMapEntries;
    size_t                             dataSize;
    const void*                        pData;
} VkSpecializationInfo;

typedef struct VkSpecializationMapEntry {
    uint32_t    constantID;
    uint32_t    offset;
    size_t      size;
} VkSpecializationMapEntry;
VkPipelineDynamicStateCreateInfo —— 动态状态

    动态状态设置了当前流水线中所使用的动态状态的数量,以及它们在流水线中对应的对象。其中可以包括视口、模板、线宽、融混常数、模板比较掩码,等等。

    流水线会通过这个数组来决定哪些状态可以在运行时被修改。

typedef struct VkPipelineDynamicStateCreateInfo {
    VkStructureType                      sType;
    const void*                          pNext;
    VkPipelineDynamicStateCreateFlags    flags;
    uint32_t                             dynamicStateCount;
    const VkDynamicState*                pDynamicStates;
} VkPipelineDynamicStateCreateInfo;

typedef enum VkDynamicState {
    VK_DYNAMIC_STATE_VIEWPORT = 0,
    VK_DYNAMIC_STATE_SCISSOR = 1,
    VK_DYNAMIC_STATE_LINE_WIDTH = 2,
    VK_DYNAMIC_STATE_DEPTH_BIAS = 3,
    VK_DYNAMIC_STATE_BLEND_CONSTANTS = 4,
    ...
    VK_DYNAMIC_STATE_MAX_ENUM = 0x7FFFFFFF
} VkDynamicState;
VkPipelineVertexInputStateCreateInfo —— 顶点输入状态

    顶点输入状态设置了输入的绑定信息(VkVertexInputBindingDescription和顶点属性的描述符(VkVertexInputAttributeDescription)。输入绑定信息可以帮助流水线实现对绑定资源的访问,并且按照数据传输进来的频率。另一方面,顶点属性的描述符存储了一些重要的属性信息,例如位置、绑定、格式等。系统可以使用这些属性来解析顶点数据。

typedef struct VkPipelineVertexInputStateCreateInfo {
    VkStructureType                             sType;
    const void*                                 pNext;
    VkPipelineVertexInputStateCreateFlags       flags;
    uint32_t                                    vertexBindingDescriptionCount;
    const VkVertexInputBindingDescription*      pVertexBindingDescriptions;
    uint32_t                                    vertexAttributeDescriptionCount;
    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions;
} VkPipelineVertexInputStateCreateInfo;

typedef struct VkVertexInputBindingDescription {
    uint32_t             binding;
    uint32_t             stride;
    VkVertexInputRate    inputRate;
} VkVertexInputBindingDescription;

typedef struct VkVertexInputAttributeDescription {
    uint32_t    location;
    uint32_t    binding;
    VkFormat    format;
    uint32_t    offset;
} VkVertexInputAttributeDescription;
VkPipelineInputAssemblyStateCreateInfo —— 输入的图元装配状态

   当图形流水线收到了顶点数据之后,它看起来像是一个装满了没有拼装的乐高积木的篮子。所有的顶点都需要按照点、线,或者三角形的形式连接起来,构成用户期望的形状。这个形状信息会影响到后续的光栅化阶段,从而产生与几何形状图元对应的片元数据。这个过程有点类似于装配乐高积木的过程,最终将产生一个可用的几何形状。


   将顶点装配为图元的阶段叫作输入装配阶段,可以通过结构体 VkPipelineinputAssemblyStateCreateInfo 来定义。其中包含了必要的图元拓扑信息,帮助系统根据指定规则将顶点一一连接在一起。输入装配结构体中通过 VkPrimitiveTopology 来实现拓扑信息的设置。

typedef struct VkPipelineInputAssemblyStateCreateInfo {
    VkStructureType                            sType;
    const void*                                pNext;
    VkPipelineInputAssemblyStateCreateFlags    flags;
    VkPrimitiveTopology                        topology;
    VkBool32                                   primitiveRestartEnable;
} VkPipelineInputAssemblyStateCreateInfo;

// 点、线、三角形
typedef enum VkPrimitiveTopology {
    VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0,
    VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 1,
    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 2,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 3,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 4,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 5,
    VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 6,
    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 7,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 8,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 9,
    VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 10,
    VK_PRIMITIVE_TOPOLOGY_MAX_ENUM = 0x7FFFFFFF
} VkPrimitiveTopology;

VkPipelineTessellationStateCreateInfo —— 细分控件和细分计算着色器状态
typedef struct VkPipelineTessellationStateCreateInfo {
    VkStructureType                           sType;
    const void*                               pNext;
    VkPipelineTessellationStateCreateFlags    flags;
    uint32_t                                  patchControlPoints;
} VkPipelineTessellationStateCreateInfo;
VkPipelineRasterizationStateCreateInfo —— 光栅化状态

   片元是图元拓扑经过光栅化阶段之后的产物。光栅化之后的图像中包含了很多小的方块,以网格的形式紧密排列,称为片元。在帧缓存当中,片元的逻辑信息被记录在位置(x,y),与之对应的还有深度信息(z)以及片元着色器中新增的相关数据和属性。


   每个图元都要经历光栅化的过程,并根据拓扑形状产生对应的片元数据。这里首先要计算每个图元的整数位置,从而在帧缓存的网格中找到对应的坐标点。除了位置之外,我们还需要获取一个或者多个深度值以及属性,这些数据将用来决定最终存储到帧缓存中的片元颜色。每个计算得到的坐标点都可以对应一个或者多个深度值,也就是说同一个坐标位置可能会重叠多个图元(全部或者部分)。此时片元的计算需要依据深度信息以及相关联的属性信息来决定。


   片元可以不是正方形的,这并不会影响到光栅化过程的执行。光栅化过程与片元的宽高比并没有关联。片元被假设为正方形,这是为了简化抗锯齿以及纹理映射的过程。


   最终计算得到的片元对应于帧缓存中的一个像素。帧缓存范围之外的所有片元都会被直接舍弃,流水线后续的阶段以及逐片元的测试过程中都不会再处理它们。片元着色器对于剩余的可见片元进行处理,并且修改它们的深度值和对应的属性值。

typedef struct VkPipelineRasterizationStateCreateInfo {
    VkStructureType                            sType;
    const void*                                pNext;
    VkPipelineRasterizationStateCreateFlags    flags;
    VkBool32                                   depthClampEnable;
    VkBool32                                   rasterizerDiscardEnable;
    VkPolygonMode                              polygonMode;
    VkCullModeFlags                            cullMode;
    VkFrontFace                                frontFace;
    VkBool32                                   depthBiasEnable;
    float                                      depthBiasConstantFactor;
    float                                      depthBiasClamp;
    float                                      depthBiasSlopeFactor;
    float                                      lineWidth;
} VkPipelineRasterizationStateCreateInfo;

typedef enum VkPolygonMode {
    VK_POLYGON_MODE_FILL = 0, // 填充
    VK_POLYGON_MODE_LINE = 1, // 仅轮廓线
    VK_POLYGON_MODE_POINT = 2,  // 点
    VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000,
    VK_POLYGON_MODE_MAX_ENUM = 0x7FFFFFFF
} VkPolygonMode;

typedef enum VkCullModeFlagBits {
    VK_CULL_MODE_NONE = 0,            // 三角形无裁剪
    VK_CULL_MODE_FRONT_BIT = 0x00000001,    // 三角形正面裁剪
    VK_CULL_MODE_BACK_BIT = 0x00000002,     // 三角形背面裁剪
    VK_CULL_MODE_FRONT_AND_BACK = 0x00000003, // 三角形正面和背面均裁剪
    VK_CULL_MODE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkCullModeFlagBits;
typedef VkFlags VkCullModeFlags;

typedef enum VkFrontFace {
    VK_FRONT_FACE_COUNTER_CLOCKWISE = 0,    // 顺时针正向
    VK_FRONT_FACE_CLOCKWISE = 1,        // 逆时钟正向
    VK_FRONT_FACE_MAX_ENUM = 0x7FFFFFFF
} VkFrontFace;
VkPipelineColorBlendStateCreateInfo —— 颜色融混状态

   融混也就是将源片元融合到目标片元的过程,这里需要遵循一些特殊的规则,即融混参数。源片元和目标片元都包含了四个分量,其中三个对应于颜色分量(R、G、B),另一个对应于控制透明度的 alpha 分量。


   对于帧缓存中的每一个位置,我们都会将输入的源片元(Rs、Gs、Bs、As)与当前存在的目标片元(Rd、Gd、Bd、Ad)进行融合,并且将结果保存到帧缓存当前的片元位置(x,y)。


   融混计算过程需要较高的计算精度。通常它们需要用到单精度浮点数的精度,并且精度不能低于目标分量的精度。因此,所有的有符号或者无符号的归一化固定数都需要转换到浮点数的形式,以便获得最高的计算精度。


   融混的过程是通过融混操作符、融混参数,以及融混常数来控制的:


融混操作符:定义基本的数学操作,用来融合源数据和目标数据。例如,相加(VK_BLEND_OP_ADD)、相减(VK_BLEND_OP_SUBTRACT),或者逆相减(VK_BLEND_OP_REVERSE_SUBTRACT)。


融混参数:每个分量的计算权重是通过融混参数来决定的。这些参数可以用来修改当前所用的融混操作符。


融混常数:这是一个常数形式的颜色分量(R、G、B、A),可以参与到融混过程中产生新的颜色分量值。

typedef struct VkPipelineColorBlendStateCreateInfo {
    VkStructureType                               sType;
    const void*                                   pNext;
    VkPipelineColorBlendStateCreateFlags          flags;
    VkBool32                                      logicOpEnable;
    VkLogicOp                                     logicOp;
    uint32_t                                      attachmentCount;
    const VkPipelineColorBlendAttachmentState*    pAttachments;
    float                                         blendConstants[4];
} VkPipelineColorBlendStateCreateInfo;

typedef enum VkLogicOp {
    VK_LOGIC_OP_CLEAR = 0,
    VK_LOGIC_OP_AND = 1,
    VK_LOGIC_OP_AND_REVERSE = 2,
    VK_LOGIC_OP_COPY = 3,
    VK_LOGIC_OP_AND_INVERTED = 4,
    VK_LOGIC_OP_NO_OP = 5,
    VK_LOGIC_OP_XOR = 6,
    VK_LOGIC_OP_OR = 7,
    VK_LOGIC_OP_NOR = 8,
    VK_LOGIC_OP_EQUIVALENT = 9,
    VK_LOGIC_OP_INVERT = 10,
    VK_LOGIC_OP_OR_REVERSE = 11,
    VK_LOGIC_OP_COPY_INVERTED = 12,
    VK_LOGIC_OP_OR_INVERTED = 13,
    VK_LOGIC_OP_NAND = 14,
    VK_LOGIC_OP_SET = 15,
    VK_LOGIC_OP_MAX_ENUM = 0x7FFFFFFF
} VkLogicOp;

typedef struct VkPipelineColorBlendAttachmentState {
    VkBool32                 blendEnable;
    VkBlendFactor            srcColorBlendFactor;
    VkBlendFactor            dstColorBlendFactor;
    VkBlendOp                colorBlendOp;
    VkBlendFactor            srcAlphaBlendFactor;
    VkBlendFactor            dstAlphaBlendFactor;
    VkBlendOp                alphaBlendOp;
    VkColorComponentFlags    colorWriteMask;
} VkPipelineColorBlendAttachmentState;

typedef enum VkBlendFactor {
    VK_BLEND_FACTOR_ZERO = 0,
    VK_BLEND_FACTOR_ONE = 1,
    VK_BLEND_FACTOR_SRC_COLOR = 2,
    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 3,
    VK_BLEND_FACTOR_DST_COLOR = 4,
    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 5,
    VK_BLEND_FACTOR_SRC_ALPHA = 6,
    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 7,
    VK_BLEND_FACTOR_DST_ALPHA = 8,
    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 9,
    VK_BLEND_FACTOR_CONSTANT_COLOR = 10,
    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 11,
    VK_BLEND_FACTOR_CONSTANT_ALPHA = 12,
    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 13,
    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 14,
    VK_BLEND_FACTOR_SRC1_COLOR = 15,
    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 16,
    VK_BLEND_FACTOR_SRC1_ALPHA = 17,
    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 18,
    VK_BLEND_FACTOR_MAX_ENUM = 0x7FFFFFFF
} VkBlendFactor;

typedef enum VkBlendOp {
    VK_BLEND_OP_ADD = 0,
    VK_BLEND_OP_SUBTRACT = 1,
    VK_BLEND_OP_REVERSE_SUBTRACT = 2,
    VK_BLEND_OP_MIN = 3,
    VK_BLEND_OP_MAX = 4,
    ...
    VK_BLEND_OP_MAX_ENUM = 0x7FFFFFFF
} VkBlendOp;
VkPipelineViewportStateCreateInfo —— 视口状态

    视口是执行图元渲染所在的表面区域的一部分。它通过 VkViewport 结构体定义了显示的物理维度(像素单位),包括 2D 的展示区域和深度空间。这些数据合并在一起,就可以执行视口的变换了。

    有关视口变换的概念这里简单介绍一下。在视口变换过程中,我们需要使用 VkViewport 中定义的视口 2D 区域和深度空间,将归一化设备坐标系转换到帧缓存的坐标系。

typedef struct VkPipelineViewportStateCreateInfo {
    VkStructureType                       sType;
    const void*                           pNext;
    VkPipelineViewportStateCreateFlags    flags;
    uint32_t                              viewportCount;  // 视口元素数量
    // 视口的数组。如果视口状态是动态的,这个值将被忽略
    const VkViewport*                     pViewports;   
    uint32_t                              scissorCount;   // 裁剪器的数量
    const VkRect2D*                       pScissors;    // 裁剪器数组
} VkPipelineViewportStateCreateInfo;

typedef struct VkViewport {
    float    x;
    float    y;
    float    width;
    float    height;
    float    minDepth;
    float    maxDepth;
} VkViewport;

typedef struct VkRect2D {
    VkOffset2D    offset;
    VkExtent2D    extent;
} VkRect2D;

typedef struct VkOffset2D {
    int32_t    x;
    int32_t    y;
} VkOffset2D;

typedef struct VkExtent2D {
    uint32_t    width;
    uint32_t    height;
} VkExtent2D;
VkPipelineDepthStencilStateCreateInfo —— 深度、模板状态

   深度测试是因为对于每一个已有的片元,其中都可能包含了多个深度值,这表示多个图元在帧缓存的同一个位置产生了叠加。我们需要在深度缓存附件中对这些数值进行比较和存储。深度缓存附件中存储的数值可以用来对片元进行裁减处理。对于任何一个片元来说,它的数值必然被保存在帧缓存的某个位置(xf,yf)上。


   模板测试使用了深度/模板附件,并对帧缓存位置(xf,yf)中存储的数值和一个参考值进行比较。根据模板测试状态的设置,系统可能会随时更新模板/深度附件中的模板值和模板写掩码值。


   深度状态和模板状态的控制需要通过结构体 VkPipelineDepthStencilStateCreateInfo来完成。深度和模板测试的开启和关闭是通过它的成员变量 depthBoundsTestEnable 和 stencilTestEnable 来完成的。

typedef struct VkPipelineDepthStencilStateCreateInfo {
    VkStructureType                           sType;
    const void*                               pNext;
    VkPipelineDepthStencilStateCreateFlags    flags;
    VkBool32                                  depthTestEnable;
    VkBool32                                  depthWriteEnable;
    VkCompareOp                               depthCompareOp;
    VkBool32                                  depthBoundsTestEnable;
    VkBool32                                  stencilTestEnable;
    VkStencilOpState                          front;
    VkStencilOpState                          back;
    float                                     minDepthBounds;
    float                                     maxDepthBounds;
} VkPipelineDepthStencilStateCreateInfo;

typedef enum VkCompareOp {
    VK_COMPARE_OP_NEVER = 0,
    VK_COMPARE_OP_LESS = 1,
    VK_COMPARE_OP_EQUAL = 2,
    VK_COMPARE_OP_LESS_OR_EQUAL = 3,
    VK_COMPARE_OP_GREATER = 4,
    VK_COMPARE_OP_NOT_EQUAL = 5,
    VK_COMPARE_OP_GREATER_OR_EQUAL = 6,
    VK_COMPARE_OP_ALWAYS = 7,
    VK_COMPARE_OP_MAX_ENUM = 0x7FFFFFFF
} VkCompareOp;

typedef struct VkStencilOpState {
    VkStencilOp    failOp;
    VkStencilOp    passOp;
    VkStencilOp    depthFailOp;
    VkCompareOp    compareOp;
    uint32_t       compareMask;
    uint32_t       writeMask;
    uint32_t       reference;
} VkStencilOpState;

typedef enum VkStencilOp {
    VK_STENCIL_OP_KEEP = 0,
    VK_STENCIL_OP_ZERO = 1,
    VK_STENCIL_OP_REPLACE = 2,
    VK_STENCIL_OP_INCREMENT_AND_CLAMP = 3,
    VK_STENCIL_OP_DECREMENT_AND_CLAMP = 4,
    VK_STENCIL_OP_INVERT = 5,
    VK_STENCIL_OP_INCREMENT_AND_WRAP = 6,
    VK_STENCIL_OP_DECREMENT_AND_WRAP = 7,
    VK_STENCIL_OP_MAX_ENUM = 0x7FFFFFFF
} VkStencilOp;

如果动态的深度包围体测试被启用的话,那么我们就可以在运行过程中使用 vkCmdSetDepthBounds 函数来定义它的执行参数。minDepthBounds 和 maxDepthBounds 参数来定义深度包围体测试的属性。

VKAPI_ATTR void VKAPI_CALL vkCmdSetDepthBounds(
    VkCommandBuffer                             commandBuffer,    // 指令缓存
    float                                       minDepthBounds,   // 最小的深度包围体值
    float                                       maxDepthBounds);  // 最大的深度包围体值
VkPipelineMultisampleStateCreateInfo —— 多重采样状态

   多重采样机制可以在 Vulkan 图元光栅化的过程中去除锯齿效果。这一抗锯齿过程需要从给定像素位置的几何体上多次采样,从而产生一个平滑的近似效果,减轻锯齿感,让边界的画质更为平滑。


   计算机图形学中的抗锯齿技术可以提升渲染图像或者屏幕视频内容输出的质量,它可以降低线段绘制的锯齿效果。光栅化的帧缓存中包含了数以百计的微小的正方形像素,并按照网格方式排列。在图像的光栅化过程中,需要对给定像素的几何体执行多次采样,采样的方法将在后面的内容中讨论。简单来说,抗锯齿的主要方法通过点采样来完成。采样的结果被表示为矩形的像素,因此不适合表示曲面形状。图像中的边界如果是圆弧状的(而非水平或者垂直),就会产生锯齿状的效果,最终对像素的着色也是阶梯状的。如果图像或者场景是静止状态的,那么锯齿问题并不会非常明显,但是如果它们处于运动状态,那么锯齿问题就会非常明显。


   当图元(点、线、三角形)被绘制到最终呈现的像素之后,它们将进入多重采样的处理过程。此时 Vulkan 的图元抗锯齿方法可以让边界显得更为平滑,没有锯齿感。这个技术的效率很高,可以节省大量的计算成本(与其他各种抗锯齿技术相比较)。因此这也是 GPU 硬件供应商通常的首选方案。对于一个通道的某一个像素来说,多重采样在计算过程中需要使用不止一个对应的采样结果。多重采样过程中图元对应的每个像素都被采样多次,每次的采样结果中都分别包含了颜色、深度/模板值,我们需要随后将它们合并为一个颜色值。


   根据 Vulkan 的标准所述,单一采样模式下的光栅化过程,它采样的结果等同于多重采样模式下每个像素的中心位置采样结果。

typedef struct VkPipelineMultisampleStateCreateInfo {
    VkStructureType                          sType;
    const void*                              pNext;
    VkPipelineMultisampleStateCreateFlags    flags;
    VkSampleCountFlagBits                    rasterizationSamples;  // 逐像素采样的数量
    // 如果为真则为逐像素着色,否则逐片元着色
    VkBool32                                 sampleShadingEnable; 
    float                                    minSampleShading;
    const VkSampleMask*                      pSampleMask;
    VkBool32                                 alphaToCoverageEnable;
    VkBool32                                 alphaToOneEnable;
} VkPipelineMultisampleStateCreateInfo;

typedef enum VkSampleCountFlagBits {
    VK_SAMPLE_COUNT_1_BIT = 0x00000001,
    VK_SAMPLE_COUNT_2_BIT = 0x00000002,
    VK_SAMPLE_COUNT_4_BIT = 0x00000004,
    VK_SAMPLE_COUNT_8_BIT = 0x00000008,
    VK_SAMPLE_COUNT_16_BIT = 0x00000010,
    VK_SAMPLE_COUNT_32_BIT = 0x00000020,
    VK_SAMPLE_COUNT_64_BIT = 0x00000040,
    VK_SAMPLE_COUNT_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkSampleCountFlagBits;
typedef VkFlags VkSampleCountFlags;

示例
bool VulkanPipeline::createPipeline(VulkanDrawable* drawableObj, VkPipeline* pipeline, VulkanShader* shaderObj, VkBool32 includeDepth, VkBool32 includeVi)
{
  // Initialize the dynamic states, initially it�s empty
  VkDynamicState dynamicStateEnables[VK_DYNAMIC_STATE_RANGE_SIZE];
  memset(dynamicStateEnables, 0, sizeof dynamicStateEnables);

  // Specify the dynamic state information to pipeline through
  // VkPipelineDynamicStateCreateInfo control structure.
  VkPipelineDynamicStateCreateInfo dynamicState = {};
  dynamicState.sType        = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
  dynamicState.pNext        = NULL;
  dynamicState.pDynamicStates   = dynamicStateEnables;
  dynamicState.dynamicStateCount  = 0;

  VkPipelineVertexInputStateCreateInfo vertexInputStateInfo = {};
  vertexInputStateInfo.sType              = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
  vertexInputStateInfo.pNext              = NULL;
  vertexInputStateInfo.flags              = 0;
  if(includeVi)
  {
    vertexInputStateInfo.vertexBindingDescriptionCount  = sizeof(drawableObj->viIpBind) / sizeof(VkVertexInputBindingDescription);
    vertexInputStateInfo.pVertexBindingDescriptions   = &drawableObj->viIpBind;
    vertexInputStateInfo.vertexAttributeDescriptionCount = sizeof(drawableObj->viIpAttrb)/sizeof(VkVertexInputAttributeDescription);
    vertexInputStateInfo.pVertexAttributeDescriptions = drawableObj->viIpAttrb;
  }
  VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {};
  inputAssemblyInfo.sType           = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
  inputAssemblyInfo.pNext           = NULL;
  inputAssemblyInfo.flags           = 0;
  inputAssemblyInfo.primitiveRestartEnable  = VK_FALSE;
  inputAssemblyInfo.topology          = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;

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

  // Create the viewport state create info and provide the 
  // the number of viewport and scissors being used in the
  // rendering pipeline.
  VkPipelineColorBlendAttachmentState colorBlendAttachmentStateInfo[1] = {};
  colorBlendAttachmentStateInfo[0].colorWriteMask     = 0xf;
  colorBlendAttachmentStateInfo[0].blendEnable      = VK_FALSE;
  colorBlendAttachmentStateInfo[0].alphaBlendOp     = VK_BLEND_OP_ADD;
  colorBlendAttachmentStateInfo[0].colorBlendOp     = VK_BLEND_OP_ADD;
  colorBlendAttachmentStateInfo[0].srcColorBlendFactor  = VK_BLEND_FACTOR_ZERO;
  colorBlendAttachmentStateInfo[0].dstColorBlendFactor  = VK_BLEND_FACTOR_ZERO;
  colorBlendAttachmentStateInfo[0].srcAlphaBlendFactor  = VK_BLEND_FACTOR_ZERO;
  colorBlendAttachmentStateInfo[0].dstAlphaBlendFactor  = VK_BLEND_FACTOR_ZERO;

  VkPipelineColorBlendStateCreateInfo colorBlendStateInfo = {};
  colorBlendStateInfo.sType       = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
  colorBlendStateInfo.flags       = 0;
  colorBlendStateInfo.pNext       = NULL;
  colorBlendStateInfo.attachmentCount   = 1;
  colorBlendStateInfo.pAttachments    = colorBlendAttachmentStateInfo;
  colorBlendStateInfo.logicOpEnable   = VK_FALSE;
  colorBlendStateInfo.blendConstants[0] = 1.0f;
  colorBlendStateInfo.blendConstants[1] = 1.0f;
  colorBlendStateInfo.blendConstants[2] = 1.0f;
  colorBlendStateInfo.blendConstants[3] = 1.0f;

  VkPipelineViewportStateCreateInfo viewportStateInfo = {};
  viewportStateInfo.sType                 = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
  viewportStateInfo.pNext                 = NULL;
  viewportStateInfo.flags                 = 0;
  viewportStateInfo.viewportCount             = NUMBER_OF_VIEWPORTS;
  viewportStateInfo.scissorCount              = NUMBER_OF_SCISSORS;
  viewportStateInfo.pScissors               = NULL;
  viewportStateInfo.pViewports              = NULL;

  // Specify the dynamic state count and VkDynamicState enum stating which 
  // dynamic state will use the values from dynamic state commands rather
  // than from the pipeline state creation info.
  dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_VIEWPORT;
  dynamicStateEnables[dynamicState.dynamicStateCount++] = VK_DYNAMIC_STATE_SCISSOR;

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

  VkPipelineMultisampleStateCreateInfo   multiSampleStateInfo = {};
  multiSampleStateInfo.sType          = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
  multiSampleStateInfo.pNext          = NULL;
  multiSampleStateInfo.flags          = 0;
  multiSampleStateInfo.pSampleMask      = NULL;
  multiSampleStateInfo.rasterizationSamples = NUM_SAMPLES;
  multiSampleStateInfo.sampleShadingEnable  = VK_FALSE;
  multiSampleStateInfo.alphaToCoverageEnable  = VK_FALSE;
  multiSampleStateInfo.alphaToOneEnable   = VK_FALSE;
  multiSampleStateInfo.minSampleShading   = 0.0;

  // Populate the VkGraphicsPipelineCreateInfo structure to specify 
  // programmable stages, fixed-function pipeline stages render
  // pass, sub-passes and pipeline layouts
  VkGraphicsPipelineCreateInfo pipelineInfo = {};
  pipelineInfo.sType          = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
  pipelineInfo.pNext          = NULL;
  pipelineInfo.layout         = drawableObj->pipelineLayout;
  pipelineInfo.basePipelineHandle   = 0;
  pipelineInfo.basePipelineIndex    = 0;
  pipelineInfo.flags          = 0;
  pipelineInfo.pVertexInputState    = &vertexInputStateInfo;
  pipelineInfo.pInputAssemblyState  = &inputAssemblyInfo;
  pipelineInfo.pRasterizationState  = &rasterStateInfo;
  pipelineInfo.pColorBlendState   = &colorBlendStateInfo;
  pipelineInfo.pTessellationState   = NULL;
  pipelineInfo.pMultisampleState    = &multiSampleStateInfo;
  pipelineInfo.pDynamicState      = &dynamicState;
  pipelineInfo.pViewportState     = &viewportStateInfo;
  pipelineInfo.pDepthStencilState   = &depthStencilStateInfo;
  pipelineInfo.pStages        = shaderObj->shaderStages;
  pipelineInfo.stageCount       = 2;
  pipelineInfo.renderPass       = appObj->rendererObj->renderPass;
  pipelineInfo.subpass        = 0;

  // Create the pipeline using the meta-data store in the VkGraphicsPipelineCreateInfo object
  if (vkCreateGraphicsPipelines(deviceObj->device, pipelineCache, 1, &pipelineInfo, NULL, pipeline) == VK_SUCCESS)
  {
    return true;
  }
  else
  {
    return false;
  }
}


销毁流水线 —— vkDestroyPipeline

VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline(
    VkDevice                                    device,
    VkPipeline                                  pipeline,
    const VkAllocationCallbacks*                pAllocator);

Vulkan 围炉夜话4:https://developer.aliyun.com/article/1598116

目录
相关文章
|
22天前
|
缓存 API 开发工具
Vulkan 围炉夜话1
Vulkan 围炉夜话
30 15
|
22天前
|
缓存 并行计算 算法
Vulkan 围炉夜话2
Vulkan 围炉夜话
31 13
|
22天前
|
存储 缓存 API
Vulkan 围炉夜话4
Vulkan 围炉夜话
25 5
|
22天前
|
存储 缓存 算法
Vulkan 围炉夜话5
Vulkan 围炉夜话
17 4
|
22天前
|
Unix API 图形学
OpenGL 围炉夜话
OpenGL 围炉夜话
34 10
|
22天前
|
Linux
BuildRoot 围炉夜话
BuildRoot 围炉夜话
63 9
|
22天前
|
Java 虚拟化 数据安全/隐私保护
MacOs 围炉夜话
MacOs 围炉夜话
55 10
|
存储 监控 JavaScript
保熟的TS知识,拜托,超快超酷的好吗
这一步对于很多人来说是最简单的一步,也是最难的一步,说简单是因为这确确实实仅是入门的一步,就是一个环境配置,说难则是因为很多人无法跨出这一步,当你跨出这一步之后,你会发现后面的真的学得很快很快,现在,就让我们一起跨出这一步吧~
55 0
|
JSON 算法 JavaScript
喜大普奔,es2019登场
就在刚4个小时前,TC39将以下特性加入到了 ES2019 中。让我们来看看这些新的特性给我们带来了什么样的改变。
喜大普奔,es2019登场
|
移动开发 监控 前端开发
SegmentFault 技术周刊 Vol.35 - WebGL:打开网页看大片
SegmentFault 技术周刊 Vol.35 - WebGL:打开网页看大片
247 0