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