系列文章目录
OpenGL 围炉夜话
Vulkan 围炉夜话
文章目录
- 系列文章目录
- Vulkan
- 参考书
- 教程
- 学习摘要
- VkImage 、VkBuffer
- VkImage 相关
- VkBuffer 相关
- VkDeviceMemory 映射
- 理解代码流线
- 渲染通道
- 理解渲染通道
- 创建渲染通道
- VkFramebuffer 帧缓存
- 流水线
- 创建流水线缓冲对象(PCO) —— vkCreatePipelineCache
- 合并流水线缓冲 —— vkMergePipelineCaches
- 从流水线缓冲获取数据 —— vkGetPipelineCacheData
- 创建图形流水线 —— vkCreateGraphicsPipelines
- VkPipelineShaderStageCreateInfo —— 着色器阶段
- VkPipelineVertexInputStateCreateInfo —— 顶点输入状态
- VkPipelineInputAssemblyStateCreateInfo —— 输入的图元装配状态
- VkPipelineTessellationStateCreateInfo —— 细分控件和细分计算着色器状态
- VkPipelineViewportStateCreateInfo —— 视口状态
- VkPipelineRasterizationStateCreateInfo —— 光栅化状态
- VkPipelineMultisampleStateCreateInfo —— 多重采样状态
- VkPipelineDepthStencilStateCreateInfo —— 深度、模板状态
- VkPipelineColorBlendStateCreateInfo —— 颜色融混状态
- VkPipelineDynamicStateCreateInfo —— 动态状态
- 销毁流水线 —— vkDestroyPipeline
- 创建计算流水线 —— vkCreateComputePipelines
- 流水线状态对象
- 创建流水线布局 —— vkCreatePipelineLayout
Vulkan
Vulkan 官网
Vulkan 参考手册 1.3
参考书
Vulkan学习指南 源码
教程
Vulkan::0.0::开始于VulKanSDK(Getting Started with the Vulkan SDK)
Vulkan Programming Guide::Chapter1::Overview of VulKan(纵观VulKan)
学习摘要
VkImage 、VkBuffer
VkImage 相关
完整的图像资源创建工作流如下图:
- vkCreateImage 函数创建 VkImage 图像资源
VKAPI_ATTR VkResult VKAPI_CALL vkCreateImage(
VkDevice device,
const VkImageCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkImage* pImage);
- vkAllocateMemory 函数分配内存 VkDeviceMemory
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory);
- vkBindImageMemory 函数把分配的内存 VkDeviceMemory 绑定给 VkImage 使用
VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(
VkDevice device,
VkImage image,
VkDeviceMemory memory,
VkDeviceSize memoryOffset);
- 主机端要使用 VkImageView 来操作 VkImage,使用 vkCreateImageView 对两者进行关联
VKAPI_ATTR VkResult VKAPI_CALL vkCreateImageView(
VkDevice device,
const VkImageViewCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkImageView* pView);
VkBuffer 相关
完整的缓存资源创建工作流如下图:
- vkCreateBuffer 函数创建 VkBuffer 缓存资源
VKAPI_ATTR VkResult VKAPI_CALL vkCreateBuffer(
VkDevice device,
const VkBufferCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkBuffer* pBuffer);
- vkAllocateMemory 函数分配内存 VkDeviceMemory
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateMemory(
VkDevice device,
const VkMemoryAllocateInfo* pAllocateInfo,
const VkAllocationCallbacks* pAllocator,
VkDeviceMemory* pMemory);
- vkBindBufferMemory 函数把分配的内存 VkDeviceMemory 绑定给 VkBuffer 使用
VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(
VkDevice device,
VkBuffer buffer,
VkDeviceMemory memory,
VkDeviceSize memoryOffset);
- 可选择使用 vkCreateBufferView 对 VkBuffer 和 VkBufferView 进行关联
VKAPI_ATTR VkResult VKAPI_CALL vkCreateBufferView(
VkDevice device,
const VkBufferViewCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkBufferView* pView);
VkDeviceMemory 映射
- 映射到主机空间
VKAPI_ATTR VkResult VKAPI_CALL vkMapMemory(
VkDevice device,
VkDeviceMemory memory,
VkDeviceSize offset,
VkDeviceSize size,
VkMemoryMapFlags flags,
void** ppData);
- 解除映射
VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(
VkDevice device,
VkDeviceMemory memory);
理解代码流线
我们现在详细地理解一下之前的实现过程。首先创建一个 VkCreateBufferInfo 结构体,用顶点缓存的元数据填充它的内容。我们将缓存的用途类型保存在这里,用来设置顶点的信息(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT)。其他用途类型可以是针对索引缓存、uniform 缓存、纹理缓存,等等。我们需要设置顶点缓存的大小(按字节)。因为并没有设置针对多队列的需求,我们可以设置共享模式为 VK_SHARING_MODE_EXCLUSIVE 。将结构体传递给 API 函数 vkCreateBuffer() ,创建顶点缓存对象(VertexBuffer::buf)。
我们将创建的缓存对象(VertexBuffer::buf)作为参数传递给函数vkGetBufferMemoryRequirements() ,从而获取缓存分配的内存需求信息(memRqrmnt)。这个信息可以帮助系统按照合适的内存大小来分配缓存资源所需的空间。这个函数还需要用到结构体 VkCreateBufferInfo 。
下一步,我们准备进行空间分配,根据之前的需求信息创建一个 VkMemoryAllocateInfo 对象(allocinfo)。我们设置分配的字节大小并且获取兼容的内存类型。内存的分配需要用到 vkAllocateMemory 函数,输入参数为 allocinfo,获得的设备内存类型为 VkDeviceMemory,保存在 VertexBuffer.mem 变量中。
完成物理内存的分配之后,使用 vkMapMemory() 将它映射到宿主机本地内存,这样我们就可以直接将几何体数据复制到物理设备内存当中。我们将数据复制到物理设备内存之后,别忘了使用 vkUnmapMemory() 执行解除映射的操作。
最后我们通过 vkBindBufferMemory() 函数将设备内存(VkDeviceMemory)和缓存对象(VkBuffer)相互绑定在一起。
渲染通道
理解渲染通道
渲染通道(Render Pass)设置了准备在渲染时用到的帧缓存附件和子通道。附件,例如颜色和深度,设置了当前颜色和深度图像的数量。它设置了渲染过程中每幅图像所需使用的采样位数,以及图像内容的使用方法。它还设置了每个渲染通道实例的开始和结束部分如何处理图像数据。在指令缓存中使用的渲染通道被称作渲染通道实例。它负责管理子通道之间的依赖关系,定义附件与子通道之间的协议关系。
渲染通道中主要包括两大部分:附件和子通道。以下针对附件和子通道进行进一步的讲解。
- 附件
附件表示执行渲染指令时用到的一块表面区域(例如颜色、深度/模板,或者执行解析操作的解析附件)。附件的类型主要有以下五种:
- 颜色附件(color attachment):颜色附件表示渲染图元数据时用到的绘制目标图像。
- 深度附件(depth attachment):深度附件负责保存深度信息,并执行深度/模板测试操作。
- 解析附件(resolve attachment):解析附件在子通道的末尾会自动从一个多重采样的附件降维到一个单一采样的附件。解析附件与多重采用的颜色附件对应,并且在子通道的末尾从颜色附件转换到对应的解析附件,即 vkCmdResolveImage。有一个例外情况是,有时候驱动程序可能会采用更优化的工作方式,例如同时执行溢出和解析操作。
- 输入附件(input attachment):这里包含了一组附件并与着色器对象共享使用。输入附件有点类似一个严格定义的纹理,而着色器中执行的唯一操作就是纹素的获取(texture(tex,uv))——即按照着色器当前像素位置去读取相应的纹素数据。这里有一个理所当然的应用就是在经典的延迟渲染过程中,从 G-buffer 读取数据并进行后处理的滤波算法(无模糊等),以及光照处理等操作。
- 保留附件(preserve attachment):在一个给定的子通道中,保留附件中的内容会始终保持不变。保留附件并不会在其他 API 中使用,它们唯一的作用是暂时保持某些附件对应的内容在当前子通道中不变(之后可能会使用)。对于桌面系统 GPU 来说这个功能可能没有什么用,因为渲染目标是直接写入到内存的。但是,对于其他系统来说,某一部分保存在芯片内存上的附件数据可能需要在某个子通道中被其他附件复用,此时不需要将附件内容重新放回到内存中。
- 子通道
渲染通道中的子通道负责读取和写入到对应的附件中。当前渲染通道中的子通道的执行可以通过下面的渲染指令来完成:
- 子通道可以从之前写入的附件(必须是保留附件)读取,然后写入到当前关联的附件。
- 在渲染通道的实例中,子通道的附件也写入到颜色、深度和模板缓存。
- 如果要在后续的通道中使用当前的子通道附件,应用程序需要负责确保子通道信息在使用过程中始终有效。
- 保留附件在子通道的生命周期当中可以始终保持附件内容不变。此时子通道不会影响到被保护的附件的读写操作。换句话说,在子通道的生命周期当中,附件无法被读取或者写入。
创建渲染通道
- vkCreateRenderPass
VKAPI_ATTR VkResult VKAPI_CALL vkCreateRenderPass(
VkDevice device,
const VkRenderPassCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkRenderPass* pRenderPass);
- VkRenderPassCreateInfo
typedef struct VkRenderPassCreateInfo {
VkStructureType sType;
const void* pNext;
VkRenderPassCreateFlags flags;
uint32_t attachmentCount;
const VkAttachmentDescription* pAttachments;
uint32_t subpassCount;
const VkSubpassDescription* pSubpasses;
uint32_t dependencyCount;
const VkSubpassDependency* pDependencies;
} VkRenderPassCreateInfo;
- VkAttachmentDescription
typedef struct VkAttachmentDescription {
VkAttachmentDescriptionFlags flags;
VkFormat format;
VkSampleCountFlagBits samples;
VkAttachmentLoadOp loadOp;
VkAttachmentStoreOp storeOp;
VkAttachmentLoadOp stencilLoadOp;
VkAttachmentStoreOp stencilStoreOp;
VkImageLayout initialLayout;
VkImageLayout finalLayout;
} VkAttachmentDescription;
- VkSubpassDescription
typedef struct VkSubpassDescription {
VkSubpassDescriptionFlags flags;
VkPipelineBindPoint pipelineBindPoint;
uint32_t inputAttachmentCount;
const VkAttachmentReference* pInputAttachments;
uint32_t colorAttachmentCount;
const VkAttachmentReference* pColorAttachments;
const VkAttachmentReference* pResolveAttachments;
const VkAttachmentReference* pDepthStencilAttachment;
uint32_t preserveAttachmentCount;
const uint32_t* pPreserveAttachments;
} VkSubpassDescription;
- VkSubpassDependency
typedef struct VkSubpassDependency {
uint32_t srcSubpass;
uint32_t dstSubpass;
VkPipelineStageFlags srcStageMask;
VkPipelineStageFlags dstStageMask;
VkAccessFlags srcAccessMask;
VkAccessFlags dstAccessMask;
VkDependencyFlags dependencyFlags;
} VkSubpassDependency;
- VkAttachmentReference
typedef struct VkAttachmentReference {
uint32_t attachment;
VkImageLayout layout;
} VkAttachmentReference;
VkFramebuffer 帧缓存
- vkCreateFramebuffer
VKAPI_ATTR VkResult VKAPI_CALL vkCreateFramebuffer(
VkDevice device,
const VkFramebufferCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkFramebuffer* pFramebuffer);
- VkFramebufferCreateInfo
typedef struct VkFramebufferCreateInfo {
VkStructureType sType;
const void* pNext;
VkFramebufferCreateFlags flags;
VkRenderPass renderPass;
uint32_t attachmentCount;
const VkImageView* pAttachments;
uint32_t width;
uint32_t height;
uint32_t layers;
} VkFramebufferCreateInfo;
流水线
流水线指的是由一系列固定阶段组成,数据流输入之后,每一个阶段对数据进行处理之后,将它传递给下一个阶段。最终的成果可以是2D的光栅化之后的绘制图形(图形流水线),也可以是通过某种计算逻辑(计算流水线)完成更新的资源信息(缓存或者图像)。
Vulkan 支持两种类型的流水线——图形流水线和计算流水线。
- 图形流水线(graphics pipeline):这个流水线会使用指令缓存中的一组 Vulkan 指令,将 2D/3D 场景绘制到 2D 光栅化图像上。
- 计算流水线(compute pipeline):这个流水线使用指令缓存中的一组 Vulkan 指令,来处理计算性的工作。
整个流水线的执行是从输入装配开始,此时输入的顶点数据会被装配成点、线、或者三角形形式的图元拓扑结构。通过可编程的顶点着色器阶段,输入的顶点数据被转换到剪切空间。几何体通过细分控制着色器和细分计算着色器两个装配阶段进行细分,而几何着色器是唯一一个可以从单一的输入图元产生多个输出图元的阶段。
然后,我们通过图元装配环节获取前面阶段中变换坐标后的所有顶点,并且将它们按照之前输入的指定绘制/图元类型(点、线、三角形)进行排列。如果输入的顶点坐标已经在当前视口区域之外,那么对应的图元会被裁切掉,此时被裁切的片元(视口之外)也会被直接丢弃。
光栅化即变换到屏幕坐标空间的图元(点、线、三角形)转换为离散元素(即片元)的过程。片元会交由下一个阶段进行操作,即片元着色器。片元着色器对每个单独的片元执行运算。这些片元最终会成为帧缓存的一部分,并且会再度经历一系列可能的数据更新操作,比如深度测试、模板测试,以及片元融混。
缓存和图像内存可以放在一个独立的流水线中以 1D/2D/3D 工作组的形式进行处理,即计算流水线。计算流水线对于各种并行计算的需求来说是非常强大的。在计算流水线中可以同时修改(读/写)缓存和图像的内存数据。
流水线中通常包括了三大基本概念:流水线状态对象、流水线缓冲对象、流水线布局。它们可以高效地控制底层流水线的操作:
-
流水线状态对象(Pipeline State Object,PSO):物理设备或者 GPU 端可以直接在硬件层面执行一些特定类型的操作。这些操作包括光栅化和条件更新,比如融混、深度测试、模板化等。 Vulkan 允许我们通过 PSO 自由控制这些硬件属性设置。其他一些硬件端直接控制的操作还包括根据图元拓扑类型(点、线、三角形)进行给定几何体形状装配、视口的控制,等等。
-
流水线缓冲对象(Pipeline Cache Object,PCO):流水线缓冲的机制可以帮助我们快速获取合复用之前的流水线。应用程序可以因此更好地避免反复创建相同或者相似的流水线对象。
-
流水线布局(Pipeline layout):缓存和图像数据都是间接关联到着色器上的,可以通过着色器的资源变量进行访问。资源变量被关联到缓存和图像的视图对象。这些资源变量可以通过描述符和描述符的集合布局来进行管理。在流水线当中,流水线布局可以管理一系列的描述符集合布局。
vkCreatePipelineLayout,vkCreateGraphicsPipelines,vkCreateComputePipelines,vkCreatePipelineCache,vkMergePipelineCaches
创建流水线缓冲对象(PCO) —— vkCreatePipelineCache
VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineCache(
VkDevice device,
const VkPipelineCacheCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkPipelineCache* pPipelineCache);
- VkPipelineCacheCreateInfo
typedef struct VkPipelineCacheCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineCacheCreateFlags flags;
size_t initialDataSize;
const void* pInitialData;
} VkPipelineCacheCreateInfo;
合并流水线缓冲 —— vkMergePipelineCaches
VKAPI_ATTR VkResult VKAPI_CALL vkMergePipelineCaches(
VkDevice device,
VkPipelineCache dstCache,
uint32_t srcCacheCount,
const VkPipelineCache* pSrcCaches);
从流水线缓冲获取数据 —— vkGetPipelineCacheData
VKAPI_ATTR VkResult VKAPI_CALL vkGetPipelineCacheData(
VkDevice device,
VkPipelineCache pipelineCache,
size_t* pDataSize,
void* pData);
创建图形流水线 —— 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;
VkPipelineVertexInputStateCreateInfo —— 顶点输入状态
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 —— 输入的图元装配状态
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;
VkPipelineViewportStateCreateInfo —— 视口状态
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;
VkPipelineRasterizationStateCreateInfo —— 光栅化状态
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;
VkPipelineMultisampleStateCreateInfo —— 多重采样状态
typedef struct VkPipelineMultisampleStateCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineMultisampleStateCreateFlags flags;
VkSampleCountFlagBits rasterizationSamples;
VkBool32 sampleShadingEnable;
float minSampleShading;
const VkSampleMask* pSampleMask;
VkBool32 alphaToCoverageEnable;
VkBool32 alphaToOneEnable;
} VkPipelineMultisampleStateCreateInfo;
VkPipelineDepthStencilStateCreateInfo —— 深度、模板状态
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;
VkPipelineColorBlendStateCreateInfo —— 颜色融混状态
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;
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;
销毁流水线 —— vkDestroyPipeline
VKAPI_ATTR void VKAPI_CALL vkDestroyPipeline(
VkDevice device,
VkPipeline pipeline,
const VkAllocationCallbacks* pAllocator);
创建计算流水线 —— vkCreateComputePipelines
计算流水线中包括了一个独立的静态计算着色器阶段,以及流水线布局。计算着色器阶段可以实现大量的并行计算操作。另外,它的流水线布局可以将计算流水线与描述符连接在一起。
VKAPI_ATTR VkResult VKAPI_CALL vkCreateComputePipelines(
VkDevice device,
VkPipelineCache pipelineCache,
uint32_t createInfoCount,
const VkComputePipelineCreateInfo* pCreateInfos,
const VkAllocationCallbacks* pAllocator,
VkPipeline* pPipelines);
- VkComputePipelineCreateInfo
typedef struct VkComputePipelineCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineCreateFlags flags;
VkPipelineShaderStageCreateInfo stage;
VkPipelineLayout layout;
VkPipeline basePipelineHandle;
int32_t basePipelineIndex;
} VkComputePipelineCreateInfo;
流水线状态对象
流水线中的流水线状态对象指的是控制物理设备的硬件设置接口的方法。流水线状态对象有很多种不同的类型,采用预定义的多个阶段的顺序来执行工作。各个阶段的输入数据和资源都可以按照用户自定义的方式进行修改。每个阶段都会处理自己的输入数据并将它传递给下一个阶段。根据应用程序需求的不同,某个流水线状态阶段可以按照用户需要直接略过。
- 动态状态:设置流水线中用到的动态状态。
- 顶点输入状态:设置数据输入的频率和解析方法。
- 输入装配状态:将顶点数据装配成为不同的几何图元拓扑结构(线、点、各种三角形)。
- 光栅化状态:有关光栅化的操作,例如多边形填充的模式、面的朝向设置、裁减模式,等等。
- 颜色融混状态:设置源片元和目标片元之间的融混因子和操作方式。
- 视口状态:定义视口的裁切方式和维度。
- 深度/模板状态:定义深度/模板的操作方式。
- 多重采样状态:控制光栅化过程中的像素采样方式,实现抗锯齿的需求。
创建流水线布局 —— vkCreatePipelineLayout
VKAPI_ATTR VkResult VKAPI_CALL vkCreatePipelineLayout(
VkDevice device,
const VkPipelineLayoutCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkPipelineLayout* pPipelineLayout);
☆