闭关之 Vulkan 应用开发指南笔记(三): 着色器和管线、图形管线
目录
- 第6章 着色器和管线
- 6.1 GLSL 概述
- 6.2 SPIR-V 概述
- 6.2.1 如何表示 SPIR-V
- 把 SPIR-V 传递给 Vulkan
- 6.3 管线
- 6.3.1 计算管线
- 6.3.2 创建管线
- 6.3.3 特化常量
- 6.3.4 加速管线的创建
- 6.3.5 绑定管线
- 6.4 执行工作
- 6.5 在着色器中访问资源
- 6.5.1 描述符集
- 6.5.2 绑定资源到描述符集
- 6.5.3 绑定描述符集
- 6.5.4 uniform、纹素和存储缓冲区
- uniform 和着色器块
- 纹素缓冲区
- 6.5.5 推送常量
- 6.5.6 采样图像
- 第7章 图形管线
- 7.1 逻辑图形管线
- 7.2 渲染通道
- 7.3 帧缓冲区
- 7.4 创建一个简单的图形管线
- 7.4.1 图形着色器阶段
- 7.4.2 顶点输入状态
- 7.4.3 输入组装
- 7.4.4 细分状态
- 7.4.5 视口状态
- 7.4.6 光栅化状态
- 7.4.7 多重采样状态
- 7.4.8 深度和模板状态
- 7.4.9 颜色混合状态
- 7.5 动态状态
第6章 着色器和管线
6.1 GLSL 概述
- 对 GLSL 的修改允许它用来产生 Vulkan 可用的 SPIR-V 着色器,这些修改记录在 GL_KHR_ vulkan_glsl 扩展的文档中
- 内置函数
any()
和all()
分别用来判断数组中是否有一个为 true 以及是否所有的元素都是 true
6.2 SPIR-V 概述
6.2.1 如何表示 SPIR-V
- 略
把 SPIR-V 传递给 Vulkan
- 创建着色器模块对象
VkResult vkCreateShaderModule (VkDevice device,const VkShaderModuleCreateInfo* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkShaderModule* pShaderModule );
VkShaderModuleCreateInfo
typedef struct VkShaderModuleCreateInfo {//为 VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//为 0VkShaderModuleCreateFlags flags;//SPIR-V 模块的大小size_t codeSize;const uint32_t* pCode; } VkShaderModuleCreateInfo;
- 销毁并释放资源
void vkDestroyShaderModule (VkDevice device,VkShaderModule shaderModule,const VkAllocationCallbacks* pAllocator );
6.3 管线
- 在 Vulkan 中有两种管线
- 计算
- 图形
6.3.1 计算管线
- 本地工作组和全局工作组都是三维的。
- 本地工作组的尺寸在计算着色器内部设置。在 GLSL 中,使用 layout 限定符
layout (local_size_x = 4, local_size_y = 5, local_size_z 6) in;
- 计算着色器的本地工作组的最大尺寸一般来说比较小,仅仅要求 x 和 y 维度上至少有 128 次 调用,z 维度上至少有 64 次调用
- 工作组的总“体积” (在 x、y 和 z 三个方向上的上限的乘积) 有额外的限制,仅仅要求至少有 128 次调用。尽管许多实现支持更高的上限,当想要超出最小值时,你需要总是查询这些上限
- 查询工作组的最大尺寸
vkGetPhysicalDeviceProperties()
VkPhysicalDeviceLimits
maxComputeWorkGroupSize
- 本地工作组里的最大调用次数
maxComputeWorkGroupInvocations
6.3.2 创建管线
- 创建一个或多个管线
VkResult vkCreateComputePipelines (VkDevice device,//用来加速管线创建的一个对象的句柄VkPipelineCache pipelineCache,uint32_t createInfoCount,//个新管线的参数信息const VkComputePipelineCreateInfo* pCreateInfos,const VkAllocationCallbacks* pAllocator,VkPipeline* pPipelines );
VkComputePipelineCreateInfo
typedef struct VkComputePipelineCreateInfo {//VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineCreateFlags flags;//包含着色器本身的信息VkPipelineShaderStageCreateInfo stage;VkPipelineLayout layout;VkPipeline basePipelineHandle;int32_t basePipelineIndex; } VkComputePipelineCreateInfo;
VkPipelineShaderStageCreateInfo
typedef struct VkPipelineShaderStageCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineShaderStageCreateFlags flags;//管线创建的阶段//VK_SHADER_STAGE_COMPUTE_BIT VkShaderStageFlagBits stage;//着色器模块的句柄VkShaderModule module;//表示这个特别的管线的入口点const char* pName;//包含特化一个着色器所需的信息const VkSpecializationInfo* pSpecializationInfo; } VkPipelineShaderStageCreateInfo;
6.3.3 特化常量
- “特化”是指构建着色器时将一些常量编译进去
- Vulkan 实现会延迟管线代码的最终生成时间
- 直到调用
vkCreateComputePipelines()
函数
- 直到调用
- 这允许特化常量的值在着色器优化的最后通道中才考虑
- 特化常量的典型应用包括 (详细解释 Page 146)
- 通过分支产生特殊执行路径
- 通过 switch 语句产生的特殊情形
- 循环展开
- 常量折叠
- 运算符简化
- 常量可以被创建管线时传递的新值覆盖
typedef struct VkSpecializationInfo {//需要设置新值的特化常量的个数uint32_t mapEntryCount;//表示特化常量const VkSpecializationMapEntry* pMapEntries;//数据大小size_t dataSize;//原生数据const void* pData; } VkSpecializationInfo;
VkSpecializationMapEntry
typedef struct VkSpecializationMapEntry {//特化常量的 ID, 使用 constant_id 布局限定符来设置值uint32_t constantID;//原生数据偏移量uint32_t offset;原生数据大小size_t size; } VkSpecializationMapEntry;
- 销毁管线对象
void vkDestroyPipeline (VkDevice device,VkPipeline pipeline,const VkAllocationCallbacks* pAllocator );
6.3.4 加速管线的创建
- 创建管线可能是应用程序开销最大的操作之一
- 管线缓存
VkResult vkCreatePipelineCache (VkDevice device,const VkPipelineCacheCreateInfo* pCreateInfo,const VkAllocationCallbacks * pAllocator,VkPipelineCache* pPipelineCache );
VkPipelineCacheCreateInfo
typedef struct VkPipelineCacheCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFOVkStructureType sType;//nullptrconst void * pNext;//0VkPipelineCacheCreateFlags flags;size_t initialDataSize;//存在程序上一次运行产生的数据的地址const void * pInitialData; } VkPipelineCacheCreateInfo;
- 从缓存中取出数据
VkResult vkGetPipelineCacheData (VkDevice device,VkPipelineCache pipelineCache,//内存区域的大小size_t* pDataSize,//缓存数据的内存区域void* pData );
- 可以调用
vkGetPipelineCacheData()
两次来存储所有的缓存数据 - 将管线缓存数据保存到文件中
- Page 149
- 缓存数据文件头的定义
- Page 149
- 合并两个缓存对象
- 在多个线程中创建管线时,特别有用
VkResult vkMergePipelineCaches (VkDevice device,//目标缓存的句柄VkPipelineCache dstCache,//待融合缓存的个数uint32_t srcCacheCount,const VkPipelineCache* pSrcCaches );
- 销毁管线缓存对象
void vkDestroyPipelineCache (VkDevice device,VkPipelineCache pipelineCache,const VkAllocationCallbacks* pAllocator );
6.3.5 绑定管线
- 把管线绑定到一个命令缓冲区
void vkCmdBindPipeline (VkCommandBuffer commandBuffer,VkPipelineBindPoint pipelineBindPoint,VkPipeline pipeline );
- 每一个命令缓冲区上有两个管线绑定点
- 图形绑定点
- VK_PIPELINE_BIND_POINT_GRAPHICS
- 计算绑定点
- VK_PIPELINE_BIND_POINT_COMPUTE
- 图形绑定点
6.4 执行工作
- 使用计算管线分发全局工作组
void vkCmdDispatch (VkCommandBuffer commandBuffer,uint32_t x,uint32_t y,uint32_t z );
- 间接分发
- 在工作组中分发的个数来自缓冲区对象
- 允许分发大小在命令缓冲区构建之后计算
- 使用一个缓冲区来间接分发,然后用主机重写缓冲区里的内容
void vkCmdDispatchIndirect (VkCommandBuffer commandBuffer,//工作组存储在 3 个连续的 uint32_t 类型的变量VkBuffer buffer,//偏移量VkDeviceSize offset );
- 缓冲区中的参数实质上代表了一个结构体
typedef struct VkDispatchIndirectCommand {uint32_t x;uint32_t y;uint32_t z; } VkDispatchIndirectCommand;
6.5 在着色器中访问资源
- 应用程序中的着色器以两种方式来使用和产生数据
- 通过和固定功能的硬件进行交互
- 直接读取和写入资源
6.5.1 描述符集
- 描述符集是作为整体绑定到管线的资源的集合
- 可以同时将多个集合绑定到一个管线
- 每一个集合都有一个布局
- 布局描述了集合中资源的排列顺序和类型
- 两个拥有相同布局的集合被视为兼容的和可相互交换的
- 管线布局
- 可被管线访问的集合的集合组成的对象
- 管线通过参照这个管线布局对象来创建
- 对于描述符集兼容的两个管线布局,它们必须符合如下两点
- 使用相同的推送常量范围
- 按照相同顺序使用相同的描述符集布局 (或等同的布局)
- 符集布局和管线布局之间的关系
- Page 153
- 创建描述符集布局对象
VkResult vkCreateDescriptorSetLayout (VkDevice device,const VkDescriptorSetLayoutCreateInfo* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkDescriptorSetLayout* pSetLayout );
VkDescriptorSetLayoutCreateInfo
typedef struct VkDescriptorSetLayoutCreateInfo {//VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkDescriptorSetLayoutCreateFlags flags;uint32_t bindingCount;//把资源绑定到描述符集里的绑定点const VkDescriptorSetLayoutBinding* pBindings; } VkDescriptorSetLayoutCreateInfo;
VkDescriptorSetLayoutBinding
typedef struct VkDescriptorSetLayoutBinding {//每个着色器可访问的资源都具有一个绑定序号//uint32_t binding;//绑定点的描述符的类型VkDescriptorType descriptorType;uint32_t descriptorCount;VkShaderStageFlags stageFlags;const VkSampler* pImmutableSamplers; } VkDescriptorSetLayoutBinding;
VkDescriptorType
- VK_DESCRIPTOR_TYPE_SAMPLER
- 采样器是一个可以用来在从图像读入数据时执行诸如过滤、采样坐标转换等操作的对象
- VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
- 被采样的图像是一种图像,可用来和采样器连接,为着色器提供过滤过的数据
- VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
- 图像-采样器联合对象是采样器与图像的一个配对
- 总是使用同一个采样器来对这个图像做采样,在一些架构上会更加高效
- VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
- 存储图像是不可以被采样器使用却可以写入的图像
- VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
- uniform 纹素缓冲区是一种缓冲区,里面填充了同构格式化数据
- 不能被着色器写入
- 如果知道该缓冲区的内容是不变的,那么某些 Vulkan 实现可以优化对该缓冲区的访问
- uniform 纹素缓冲区是一种缓冲区,里面填充了同构格式化数据
- VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
- 存储纹素缓冲区是一种包含格式化数据的缓冲区
- 与 uniform 纹素缓冲区非常像,但是可以写入该存储缓冲区
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER 和 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
- 数据是未格式化的,通过着色器里声明的结构体来描述
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC和VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
- 包含了起始偏移量和大小,把描述符集绑定到管线时传入,而不是当把描述符绑定到集时传入
- 这允许单个集合中的单个缓冲区高频地更新
- VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
- 输入附件是一种特殊类型的图像
- 它的内容是由图形管线里同一个图像上的早期操作所生成的
- VK_DESCRIPTOR_TYPE_SAMPLER
- 建议你不要创建稀疏填充的集合,因为这会浪费设备资源
- 把两个或多个描述符集打包成管线可以使用的形式
VkResult vkCreatePipelineLayout (VkDevice device,const VkPipelineLayoutCreateInfo* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkPipelineLayout* pPipelineLayout );
VkPipelineLayoutCreateInfo
typedef struct VkPipelineLayoutCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_ LAYOUT_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineLayoutCreateFlags flags;//描述符集布局的数量uint32_t setLayoutCount;const VkDescriptorSetLayout* pSetLayouts;//推送常量uint32_t pushConstantRangeCount;//推送常量const VkPushConstantRange* pPushConstantRanges; } VkPipelineLayoutCreateInfo;
- 一次可绑定的描述符集的最大数至少为 4
vkGetPhysicalDeviceProperties()
VkPhysicalDeviceLimits
maxBoundDescriptorSets
- 管线资源限制表格
- Page 158
- 如果两个管线布局对于前面几个集合使用相同(或者等同的)的集合布局,而对于后面的集合使用不相同的集合布局,那么认为这两个管线布局是部分兼容的
- 在两个部分兼容的管线之间切换时,无须重新绑定任何集合,直到管线共享布局的地方
- 如果你有一系列的资源并想在全局范围内访问
- 比如包含每帧所需常量的 uniform 块
- 或者在每个着色器都需要访问的纹理
- 就把这些资源放在第一个集合里
- 频繁改变的资源可以放到高序号的集合里
- 销毁管线布局
void vkDestroyPipelineLayout (VkDevice device,VkPipelineLayout pipelineLayout,const VkAllocationCallbacks* pAllocator );
- 销毁描述符集布局对象
void vkDestroyDescriptorSetLayout (VkDevice device,VkDescriptorSetLayout descriptorSetLayout,const VkAllocationCallbacks* pAllocator );
6.5.2 绑定资源到描述符集
- 资源是通过描述符表示的,绑定到管线上的顺序是
- 先把描述符绑定到集合上
- 然后把描述符集绑定到管线
- 创建描述符缓存池
VkResult vkCreateDescriptorPool (VkDevice device,const VkDescriptorPoolCreateInfo* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkDescriptorPool* pDescriptorPool );
VkDescriptorPoolCreateInfo
typedef struct VkDescriptorPoolCreateInfo {//VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//唯一定义VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT//应用程序可以释放从池中获取的单个描述符//如果不打算把单个描述符归还给缓存池,把 flags 设置为 0 即可VkDescriptorPoolCreateFlags flags;//可从池中分配的集合数量的最大值uint32_t maxSets;//可以存储在集合中的每种类型资源可用的描述符个数uint32_t poolSizeCount;const VkDescriptorPoolSize* pPoolSizes; } VkDescriptorPoolCreateInfo;
VkDescriptorPoolSize
typedef struct VkDescriptorPoolSize {//资源的类型VkDescriptorType type;//池中该种类型资源的个数uint32_t descriptorCount; } VkDescriptorPoolSize;
- 创建描述符集对象
VkResult vkAllocateDescriptorSets (VkDevice device,const VkDescriptorSetAllocateInfo* pAllocateInfo,VkDescriptorSet* pDescriptorSets );
VkDescriptorSetAllocateInfo
typedef struct VkDescriptorSetAllocateInfo {//VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFOVkStructureType sType;//nullptrconst void* pNext;//可以从中分配集合的描述符缓存池的句柄//在外部保持同步VkDescriptorPool descriptorPool;//创建的集合的个数uint32_t descriptorSetCount;//每一个集合的布局const VkDescriptorSetLayout* pSetLayouts; } VkDescriptorSetAllocateInfo;
- 释放一个或者多个描述符集
VkResult vkFreeDescriptorSets (VkDevice device,VkDescriptorPool descriptorPool,uint32_t descriptorSetCount,const VkDescriptorSet* pDescriptorSets );
- 重置缓存池
VkResult vkResetDescriptorPool (VkDevice device,VkDescriptorPool descriptorPool,//为 0VkDescriptorPoolResetFlags flags );
- 销毁缓冲池对象
void vkDestroyDescriptorPool(VkDevice device,VkDescriptorPool descriptorPool,const VkAllocationCallbacks* pAllocator );
- 直接写入描述符集或者从另一个描述符集复制绑定,来把资源绑定到描述符集
void vkUpdateDescriptorSets (VkDevice device,uint32_t descriptorWriteCount,const VkWriteDescriptorSet* pDescriptorWrites,//描述符复制的次数uint32_t descriptorCopyCount,const VkCopyDescriptorSet* pDescriptorCopies );
VkWriteDescriptorSet
typedef struct VkWriteDescriptorSet {//VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET VkStructureType sType;//nullptrconst void* pNext;//目标描述符集VkDescriptorSet dstSet;//绑定索引uint32_t dstBinding;//绑定资源类型的数组,更新起始的索引uint32_t dstArrayElement;//需要更新的连续描述符个数uint32_t descriptorCount;//更新的资源的类型VkDescriptorType descriptorType;//图像资源const VkDescriptorImageInfo* pImageInfo;//缓冲区资源const VkDescriptorBufferInfo* pBufferInfo;const VkBufferView* pTexelBufferView; } VkWriteDescriptorSet;
VkDescriptorImageInfo
typedef struct VkDescriptorImageInfo {VkSampler sampler;//视图VkImageView imageView;//所期望的布局VkImageLayout imageLayout; } VkDescriptorImageInfo;
VkDescriptorBufferInfo
typedef struct VkDescriptorBufferInfo {VkBuffer buffer;VkDeviceSize offset;//如果是 uniform, 需要小于或者等于 maxUniformBufferRange VkDeviceSize range; } VkDescriptorBufferInfo;
maxUniformBufferRange
和maxStorageBufferRange
上限分别保证至少是 16384 与 2272^{27}227minUniformBufferOffsetAlignment
和minStorageBufferOffsetAlignment
要保证最多是 256 字节VkCopyDescriptorSet
typedef struct VkCopyDescriptorSet {//VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET VkStructureType sType;//nullptrconst void* pNext;//源的描述符集的句柄VkDescriptorSet srcSet;//绑定索引uint32_t srcBinding;//描述符数组uint32_t srcArrayElement;//源的描述符集的句柄VkDescriptorSet dstSet;//绑定索引uint32_t dstBinding;//描述符数组uint32_t dstArrayElement;uint32_t descriptorCount; } VkCopyDescriptorSet;
6.5.3 绑定描述符集
- 把描述符集绑定到命令缓冲区
void vkCmdBindDescriptorSets (VkCommandBuffer commandBuffer,//VK_PIPELINE_BIND_POINT_COMPUTE//or//VK_PIPELINE_BIND_POINT_GRAPHICSVkPipelineBindPoint pipelineBindPoint,//使用的管线布局VkPipelineLayout layout,//管线布局可访问的集合的一个子集uint32_t firstSet,uint32_t descriptorSetCount,const VkDescriptorSet* pDescriptorSets,//动态 uniform 或着色器存储绑定的偏移量//动态偏移量的个数uint32_t dynamicOffsetCount,//类型为 32 位偏移量的数组const uint32_t* pDynamicOffsets );
6.5.4 uniform、纹素和存储缓冲区
- 着色器可以直接通过 3 种资源访问缓冲区内存的内容
- uniform 块提供了对存储在缓冲区对象中常量(只读)数据的快速访问
- 着色器块提供了对缓冲区对象的读写访问, 支持原子操作
- 纹素缓冲区提供了对存储格式化纹素数据的长线性数组的访问能力
uniform 和着色器块
- 默认情况下
- uniform 块使用 std140 规则
- 着色器块使用 std430 规则
layout (set = 0, binding = 1) uniform my_uniform_buffer_t {float foo;vec4 bar;int baz[42]; } my_uniform_buffer;layout (set = 0, binding = 2) buffer my_storage_buffer_t {int peas;float carrots;vec3 potatoes[99]; } my_storage_buffer;
纹素缓冲区
- 在数据读取时可进行格式转换
- 纹素缓冲区是只读的
layout (set = 0, binding = 3) uniform samplerBuffer my_float_texel_buffer; layout (set = 0, binding = 4) uniform isamplerBuffer my_signed_texel_buffer; layout (set = 0, binding = 5) uniform usamplerBuffer my_unsigned_texel_buffer;
- 中纹素缓冲区要求的最小上限是 65535 个元素
- 1D 纹素要求的最小尺寸是 4096 纹素
6.5.5 推送常量
- 不需要存储在内存里
- 由 Vulkan 自身持有和更新
- 的新值可以被直接从命令缓冲区推送到管线
- 推送常量
VkPipelineLayoutCreateInfo
VkPushConstantRange
typedef struct VkPushConstantRange {//能看到常量的管线阶段VkShaderStageFlags stageFlags;uint32_t offset;uint32_t size; } VkPushConstantRange;
- 向多个着色阶段传递一个常量也许要求广播它,并会消耗很多资源
- GLSL 里声明推送常量
layout (push_constant) uniform my_push_constants_t {int bourbon;int scotch;int beer; } my_push_constants;
- 要更新一个或者多个推送常量
void vkCmdPushConstants (VkCommandBuffer commandBuffer,VkPipelineLayout layout,//不更新没有包含的阶段来提升性能VkShaderStageFlags stageFlags,//第一个常量在虚拟块内的偏移量uint32_t offset,//更新的量的大小uint32_t size,//数据const void* pValues );
- 推送常量在逻辑上按照 std430 布局规则在内存中存储
- 推送常量总共可用的空间至少是 128 字节
- 对于两个 4×4 矩阵来说足够
- 把推送常量当作稀缺资源
- 优先使用正常的 uniform 块来存储大数据结构
- 将推送常量用作整数或者更新非常频繁的数据
6.5.6 采样图像
- 当着色器从图像中读数据时,它们可以使用两种方式
- 执行原始加载,从图像的指定位置直接读取格式化的或非格式化的数据
- 使用采样器对图像采样
- 采样可以包括如下操作
- 在图像坐标上做基础变换,
- 过滤纹素来向着色器返回光滑的图像数据
- 采样可以包括如下操作
- 创建采样器对象
VkResult vkCreateSampler (VkDevice device,const VkSamplerCreateInfo* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkSampler* pSampler );
VkSamplerCreateInfo
typedef struct VkSamplerCreateInfo {//VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkSamplerCreateFlags flags;//过滤模式//VK_FILTER_NEAREST//VK_FILTER_LINEARVkFilter magFilter;VkFilter minFilter;//多重细节层//VK_SAMPLER_MIPMAP_MODE_NEAREST//VK_SAMPLER_MIPMAP_MODE_LINEARVkSamplerMipmapMode mipmapMode;//纹理坐标的变换方式//VK_SAMPLER_ADDRESS_MODE_REPEAT//VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT//VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE//VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER//VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGEVkSamplerAddressMode addressModeU;VkSamplerAddressMode addressModeV;VkSamplerAddressMode addressModeW;//浮点型偏移量, 作用于 mipmapfloat mipLodBias;//各向异性过滤//各向异性过滤通常在投影范围内做采样,而不是在固定的 2×2 范围内VkBool32 anisotropyEnable;//范围是 1.0 到设备允许的最大值//maxSamplerAnisotropyfloat maxAnisotropy;//比较模式VkBool32 compareEnable;//ALWAYS//NEVER//LESS//LESS_OR_EQUAL//EQUAL//NOT_EQUAL//GREATER//GREATER_OR_EQUAL//Page 179VkCompareOp compareOp;//在带有 mipmap 的图像中,采样器可配置成只在一个层级子集中采样//被限制的 mipmap 范围通过 minLod 和 maxLod 指定//要在整个 mipmap 链上做采样,设置 minLod 为 0.0,并设置 maxLod 为最高层float minLod;float maxLod;//VkBorderColor borderColor;//当设置为 VK_TRUE 时,表示图像用于采样的坐标以原生纹素为单位,而不是 uv//使用限制//minFilter 和 magFilter 必须是相同的//mipmapMode 必须是 VK_SAMPLER_MIPMAP_MODE_NEAREST//anisotropyEnable 和 compareEnable 必须是 VK_FALSEVkBool32 unnormalizedCoordinates; } VkSamplerCreateInfo;
- 一个设备上可以创建的采样器个数的上限取决于 Vulkan 实现。保证的是至少有 4000 个
VkPhysicalDeviceLimits
maxSamplerAllocationCount
- 销毁采样器
void vkDestroySampler (VkDevice device,VkSampler sampler,const VkAllocationCallbacks* pAllocator );
第7章 图形管线
7.1 逻辑图形管线
- 管线 (Page 181)
- 绘制
- 输入装配
- 顶点着色器
- 细分控制着色器
- 产生细分因子和其他逐图片元(patch)数 据(被固定功能细分引擎使用)
- 细分图元生成
- 固定功能阶段使用在细分控制着色器中产生的 细分因子,来把图片元分解成许多更小的、更简单的图元,以供细分评估着色器使用
- 细分评估着色器
- 这个着色阶段运行在细分图元生成器产生的每一个顶点上。它和顶点着 色器的操作类似——除了输入顶点是生成的之外,而非从内存读取的
- 几何着色器
- 图元组装
- 裁剪和剔除
- 光栅器
- 前置片段操作
- 包括深度和模板测试(当开启了这两个测试时)。
- 片段装配
- 片段装配阶段接受光栅器的输出,以及任何逐片段数 据,将这些信息作为一组,发送给片段着色阶段
- 片段着色器
- 后置片段操作
- 片段着色器会修改本应该在前置片段操作中使用的数据。 在这种情况下,这些前置片段操作转移到后置片段阶段中执行
- 颜色混合
- 颜色操作接受片段着色器和后置片段操作的结果,并使用它们更新帧缓冲区。 颜色操作包括混合与逻辑操作
- 绘制命令
void vkCmdDraw (VkCommandBuffer commandBuffer,//附加到管线的顶点的数量uint32_t vertexCount,//1, 或实例绘制物体uint32_t instanceCount,//可以从非零个顶点或者实例开始绘制uint32_t firstVertex,uint32_t firstInstance );
7.2 渲染通道
- 创建渲染通道对象
VkResult vkCreateRenderPass (VkDevice device,const VkRenderPassCreateInfo* pCreateInfo,const VkAllocationCallbacks* pAllocator,VkRenderPass* pRenderPass );
VkRenderPassCreateInfo
typedef struct VkRenderPassCreateInfo {//VK_STRUCTURE_TYPE_RENDERPASS_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkRenderPassCreateFlags flags;uint32_t attachmentCount;//组定义和渲染通道关联的多个附件const VkAttachmentDescription* pAttachments;uint32_t subpassCount;const VkSubpassDescription* pSubpasses;uint32_t dependencyCount;//依赖信息//当在一个渲染通道中有多个子通道时//Vulkan 可推算出一个附件依赖了哪些附件//这需要通过跟踪附件引用,并查找输入和输出完成//当无法自动跟踪时,使用该字段定义依赖信息const VkSubpassDependency* pDependencies; } VkRenderPassCreateInfo;
VkAttachmentDescription
typedef struct VkAttachmentDescription {//VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT 附件可能和同一个渲染通道引用的其他附件使用相同的内存//这告诉 Vulkan 不要做任何可能导致附件的数据不一致的事情//一般情况为 0VkAttachmentDescriptionFlags flags;VkFormat format;//图像中采样的次数//不使用多次采用:VK_SAMPLE_COUNT_1_BIT。VkSampleCountFlagBits samples;//下面 4 个指定了在渲染通道的开始与结束时如何处理附件//VK_ATTACHMENT_LOAD_OP_LOAD 表示附件里已经有数据了,仍想继续对它进行渲染//VK_ATTACHMENT_LOAD_OP_CLEAR 在渲染通道开始时清除附件的内容//VK_ATTACHMENT_LOAD_OP_DONT_CARE 渲染通道开始时不关心附件的内容VkAttachmentLoadOp loadOp;//VK_ATTACHMENT_STORE_OP_STORE 让 Vulkan 保留附件的内容以供稍后使用//VK_ATTACHMENT_STORE_OP_DONT_CARE 在渲染通道结束后不需要附件的内容VkAttachmentStoreOp storeOp;VkAttachmentLoadOp stencilLoadOp;VkAttachmentStoreOp stencilStoreOp;//渲染通道开始期望图像是什么布局VkImageLayout initialLayout;//在渲染通道结束时期望图像是什么布局VkImageLayout finalLayout; } VkAttachmentDescription;
- 定义子通道
typedef struct VkSubpassDescription {//0VkSubpassDescriptionFlags flags;//现阶段为 VK_PIPELINE_BIND_POINT_GRAPHICSVkPipelineBindPoint pipelineBindPoint;//个、输入附件,可以从中读出数据uint32_t inputAttachmentCount;const VkAttachmentReference* pInputAttachments;uint32_t colorAttachmentCount;//颜色附件是写入输出数据的附件const VkAttachmentReference* pColorAttachments;//解析附件是对多重采样图像数据进行解析后存储的附件const VkAttachmentReference* pResolveAttachments;const VkAttachmentReference* pDepthStencilAttachment;uint32_t preserveAttachmentCount;//如果希望附件的生存周期跨越一个子通道但并不被子通道直接引用//该引用将阻止 Vulkan 进行任何可能改动这些附件内容的优化const uint32_t* pPreserveAttachments; } VkSubpassDescription;
VkAttachmentReference
typedef struct VkAttachmentReference {//附件数组的索引uint32_t attachment;//图像布局VkImageLayout layout; } VkAttachmentReference;
- 单个子通道可以渲染输出的颜色附件的最大个数
maxColorAttachments
- 保证最少支持 4 个
VkSubpassDependency
typedef struct VkSubpassDependency {//源子通道uint32_t srcSubpass;//目标子通道uint32_t dstSubpass;//指定了源子通道的哪些管线阶段产生数据VkPipelineStageFlags srcStageMask;//指定了目标子通道的哪些管线阶段使用数据VkPipelineStageFlags dstStageMask;//如何访问数据VkAccessFlags srcAccessMask;VkAccessFlags dstAccessMask;VkDependencyFlags dependencyFlags; } VkSubpassDependency;
- 销毁渲染通道
void vkDestroyRenderPass (VkDevice device,VkRenderPass renderPass,const VkAllocationCallbacks* pAllocator );
7.3 帧缓冲区
- 帧缓冲区影响管线的最后几个阶段
- 深度和模板测试
- 混合
- 逻辑操作
- 多采样
- 等
- 帧缓冲区对象通过使用渲染通道的引用来创建
- 可以和任何有类似的附件排布方式的渲染通道一同使用
- 创建
VkResult vkCreateFramebuffer (VkDevice device,const VkFramebufferCreateInfo* pCreateInfo,//如果要求使用主机内存,就将会用到 pAllocator 所指向的分配器const VkAllocationCallbacks* pAllocator,VkFramebuffer* pFramebuffer );
VkFramebufferCreateInfo
typedef struct VkFramebufferCreateInfo {//VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//0VkFramebufferCreateFlags flags;VkRenderPass renderPass;//数组的长度uint32_t attachmentCount;const VkImageView* pAttachments;//必须指定帧缓冲区的维度uint32_t width;uint32_t height;uint32_t layers; } VkFramebufferCreateInfo;
- 支持的帧缓冲区最大尺寸依赖于设备
VkPhysicalDeviceLimits
maxFramebufferWidth
maxFramebufferHeight
maxFramebufferLayers
- vulkan 标准保证最小支持的宽度和高度是 4096 像素
- 层数至少为 256
- 大多数桌面级硬件支持 16384 像素的宽度和高度
- 2048 层
- 无附件帧缓冲区
- 存储图像
- 遮挡查询
- 无须在任何地方存储渲染结果
- 销毁帧缓冲
void vkDestroyFramebuffer (VkDevice device,VkFramebuffer framebuffer,const VkAllocationCallbacks* pAllocator );
- 销毁帧缓冲区对象并不影响附着到它上面的图像
- 图像可以同时附着到多个帧缓冲区上
7.4 创建一个简单的图形管线
- 创建图形管线
VkResult vkCreateGraphicsPipelines (VkDevice device,//管线缓存VkPipelineCache pipelineCache,uint32_t createInfoCount,const VkGraphicsPipelineCreateInfo* pCreateInfos,const VkAllocationCallbacks* pAllocator,VkPipeline* pPipelines );
VkGraphicsPipelineCreateInfo
typedef struct VkGraphicsPipelineCreateInfo {//VK_GRAPHICS_PIPELINE_CREATE_INFOVkStructureType sType;//nullptr,可以使用扩展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;
VkPipelineCreateFlags
- VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT
- 管线将不会在性能严苛的程序中使用
- VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT 和 VK_PIPELINE_CREATE_DERIVATIVE_BIT
- 衍生管线
- 可把类似的管线分为一组, 告诉 Vulakn 你将在它们之间快速切换
- VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
- 为这个新管线创建衍生管线
- VK_PIPELINE_CREATE_DERIVATIVE_ BIT
- 告诉 Vulkan 这个管线就是一个管线
- VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT
7.4.1 图形着色器阶段
VkPipelineShaderStageCreateInfo
typedef struct VkPipelineShaderStageCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//0VkPipelineShaderStageCreateFlags flags;VkShaderStageFlagBits stage;VkShaderModule module;const char* pName;const VkSpecializationInfo* pSpecializationInfo; } VkPipelineShaderStageCreateInfo;
- 管线最多由 5 个着色器阶段组成
- 顶点着色器
- VK_SHADER_STAGE_VERTEX_BIT
- 细分控制着色器
- VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT
- 细分评估着色器
- VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT
- 几何着色器
- VK_SHADER_STAGE_GEOMETRY_BIT
- 片段着色器
- VK_SHADER_STAGE_FRAGMENT_BIT
- 顶点着色器
7.4.2 顶点输入状态
VertexInputStateCreateInfo
typedef struct VkPipelineVertexInputStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//0VkPipelineVertexInputStateCreateFlags flags;//是管线使用的顶点绑定的个数uint32_t vertexBindingDescriptionCount;const VkVertexInputBindingDescription* pVertexBindingDescriptions;uint32_t vertexAttributeDescriptionCount;//顶点属性都const VkVertexInputAttributeDescription* pVertexAttributeDescriptions; } VkPipelineVertexInputStateCreateInfo;
VkVertexInputBindingDescription
typedef struct VkVertexInputBindingDescription {//结构体描述的绑定的索引uint32_t binding;//数组的步长uint32_t stride;//遍历数组的方式//实例索引 VK_VERTEX_INPUT_RATE_VERTEX//顶点索引 VK_VERTEX_INPUT_RATE_INSTANCE。VkVertexInputRate inputRate; } VkVertexInputBindingDescription;
VkVertexInputBindingDescription
数组声明的最后一个绑定索引必须比设备支持的最大绑定数要小- Vulkan 标准保证最少支持 16 个
VkPhysicalDeviceLimits
maxVertexInputBindings
- stride 的最大值都是由 Vulkan 实现决定的,
- Vulkan 标准保证至少是 2048 字节
VkPhysicalDeviceLimits
maxVertexInputBindingStride
VkVertexInputAttributeDescription
typedef struct VkVertexInputAttributeDescription {//属性的位置uint32_t location;//绑定缓冲区的位置uint32_t binding;//顶点数据的格式VkFormat format;//每个数据的偏移量uint32_t offset; } VkVertexInputAttributeDescription;
- 每一个属性在数据结构内的偏移量也有上限
- Vulkan 标准保证至少是 2047 字节
VkPhysicalDeviceLimits
maxVertexInput
7.4.3 输入组装
VkPipelineInputAssemblyStateCreateInfo
typedef struct VkPipelineInputAssemblyStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//0VkPipelineInputAssemblyStateCreateFlags flags;//图元拓扑类型VkPrimitiveTopology topology;//允许条带与扇形被切除和重启VkBool32 primitiveRestartEnable; } VkPipelineInputAssemblyStateCreateInfo;
VkPrimitiveTopology
- VK_PRIMITIVE_TOPOLOGY_POINT_LIST
- 每一个顶点用来构造一个独立的点
- VK_PRIMITIVE_TOPOLOGY_LINE_LIST
- 顶点以成对的形式分组,每一对形成一条线段
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
- 把每 3 个顶点分为一组,组成一个三角形
- VK_PRIMITIVE_TOPOLOGY_LINE_STRIP
- 前两个顶点构成一条线段
- 每一个新的顶点连接前一个处理的顶点构成一条新的线段
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
- 前 3 个顶点构成一个三角形
- 每一个接下来的顶点和前面处理的两个顶点构成一个新的三角形
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
- 前 3 个顶点构成一个三角形
- 每个接下来的顶点和上一个顶点、本次绘制的第一个顶点构成新的三角形
- VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY
- 一次绘制中每 4 个顶点构成单个图元
- 中间两个顶点构成线段
- 把第一个和最后一个顶点传递给几何着色器
- VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY
- 一次绘制中 4 个顶点构成单个图元
- 中间的两个顶点构成线段
- 第一个和最后一个顶点被当作邻接信息传递给几何着色器
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY
- 每组 6 个顶点构成单个图元
- 每组的第 1 个、第 3 个、第 5 个构成一个三角形
- 第 2 个、第 4 个、第 6 个作为邻接信息传递给几何着色器
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
- 以前 6 个顶点作为开始的条带构成了一个带有邻接信息的三角形
- 每两个新顶点构成一个新的三角形
- 奇数序号的顶点构成三角形,偶数序号的顶点提供邻接信息
- VK_PRIMITIVE_TOPOLOGY_POINT_LIST
7.4.4 细分状态
VkPipelineTessellationStateCreateInfo
typedef struct VkPipelineTessellationStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//0VkPipelineTessellationStateCreateFlags flags;//设置了将分组到一个图元的控制点的个数uint32_t patchControlPoints; } VkPipelineTessellationStateCreateInfo;
7.4.5 视口状态
VkPipelineViewportStateCreateInfo
typedef struct VkPipelineViewportStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//0VkPipelineViewportStateCreateFlags flags;//视口的个数uint32_t viewportCount;//每一个视口的尺寸const VkViewport* pViewports;uint32_t scissorCount;//设置裁剪矩形const VkRect2D* pScissors; } VkPipelineViewportStateCreateInfo;
- 视口变换是 Vulkan 管线中在栅格化之前的最后一个坐标变换
- 如果支持多视口,下限是 16 个
VkPhysicalDeviceLimits
maxViewports
7.4.6 光栅化状态
VkPipelineRasterizationStateCreateInfo
typedef struct VkPipelineRasterizationStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineRasterizationStateCreateFlags flags;//开启或关闭深度夹持(哈哈)//本该被远近平面裁剪掉的片段投射到这些平面上//可用来填充因为裁剪造成的空洞VkBool32 depthClampEnable;//关闭光栅化,光栅器将不会运行,将不会产生图元VkBool32 rasterizerDiscardEnable;//自动地把三角形转化为点或者直线VkPolygonMode polygonMode;//剔除//VK_CULL_MODE_FRONT_BIT//VK_CULL_MODE_BACK_BITVkCullModeFlags cullMode;//三角形的朝向由顶点的绕序//VK_FRONT_FACE_COUNTER_CLOCKWISE//VK_FRONT_FACE_CLOCKWISEVkFrontFace frontFace;//下面四个参数控制了深度偏移这一特性VkBool32 depthBiasEnable;float depthBiasConstantFactor;float depthBiasClamp;float depthBiasSlopeFactor;//置线段图元的宽度//一些 Vulkan 实现并不支持宽线段,会忽略这个字段//设置为 1.0 以外的值时也许会运行得相当缓慢//建议设置为 1 不变//线段的最大宽度,Vulkan 标准保证至少支持 8 像素float lineWidth; } VkPipelineRasterizationStateCreateInfo;
VkPolygonMode
VK_POLYGON_MODE_FILL
- 三角形将会被绘制为实心的,内部的每一个点都会创建一个片段
VK_POLYGON_MODE_LINE
- 每一个三角形的每一条边都变为线段
- 绘制几何物体的线框模式时这个模式很有用
VK_POLYGON_MODE_POINT
- 每一个顶点绘制为一个点
7.4.7 多重采样状态
VkPipelineMultisampleStateCreateInfo
typedef struct VkPipelineMultisampleStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineMultisampleStateCreateFlags flags;VkSampleCountFlagBits rasterizationSamples;VkBool32 sampleShadingEnable;float minSampleShading;const VkSampleMask* pSampleMask;VkBool32 alphaToCoverageEnable;VkBool32 alphaToOneEnable; } VkPipelineMultisampleStateCreateInfo;
- 当进行多重采样时,颜色和深度-模板附件必须是多重采样图像
7.4.8 深度和模板状态
深度测试在片段着色器运行之后发生
要在深度测试之前运行片段着色器,可以在片段着色器入口设置 SPIR-V EarlyFragmentTests 执行模式
VkPipelineDepthStencilStateCreateInfo
typedef struct VkPipelineDepthStencilStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineDepthStencilStateCreateFlags flags;//深度测试启用 第 10 章VkBool32 depthTestEnable;VkBool32 depthWriteEnable;VkCompareOp depthCompareOp;VkBool32 depthBoundsTestEnable;VkBool32 stencilTestEnable;VkStencilOpState front;VkStencilOpState back;float minDepthBounds;float maxDepthBounds; } VkPipelineDepthStencilStateCreateInfo;
深度和模板测试可以在片段着色器运行之前或之后进行。默认情况下,深度测试在片段着 色器运行之后发生
7.4.9 颜色混合状态
- 这个阶段负责把片段写入颜色附件
VkPipelineColorBlendStateCreateInfo
typedef struct VkPipelineColorBlendStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO VkStructureType sType;//nullptrconst void* pNext;//0VkPipelineColorBlendStateCreateFlags flags;//色器的输出和颜色附件的内容之间是否进行逻辑操作 第十章VkBool32 clogicOpEnable;VkLogicOp logicOp;uint32_t attachmentCount;const VkPipelineColorBlendAttachmentState* pAttachments;float blendConstants[4]; } VkPipelineColorBlendStateCreateInfo;
VkPipelineColorBlendAttachmentState
//第 10 章 typedef struct VkPipelineColorBlendAttachmentState {VkBool32 blendEnable;VkBlendFactor srcColorBlendFactor;VkBlendFactor dstColorBlendFactor;VkBlendOp colorBlendOp;VkBlendFactor srcAlphaBlendFactor;VkBlendFactor dstAlphaBlendFactor;VkBlendOp alphaBlendOp;//控制了把输出图像的哪个通道写入附件中VkColorComponentFlags colorWriteMask; } VkPipelineColorBlendAttachmentState;
7.5 动态状态
VkPipelineDynamicStateCreateInfo
typedef struct VkPipelineDynamicStateCreateInfo {//VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFOVkStructureType sType;//nullptrconst void* pNext;//为 0VkPipelineDynamicStateCreateFlags flags;//动态状态的个数uint32_t dynamicStateCount;//想要使用对应的动态状态设置命令来改变状态const VkDynamicState* pDynamicStates; } VkPipelineDynamicStateCreateInfo;
VkDynamicState
VK_DYNAMIC_STATE_VIEWPOR
- 视口矩形是动态的
- 使用
vkCmdSetViewport()
更新
VK_DYNAMIC_STATE_SCISSOR
- 裁剪矩形是动态的
vkCmdSetScissor()
VK_DYNAMIC_STATE_LINE_WIDTH
- 线段宽度是动态的
vkCmdSetLineWidth()
VK_DYNAMIC_STATE_DEPTH_BIAS
- 深度偏移参数是动态的
vkCmdSetDepthBias()
- VK_DYNAMIC_STATE_BLEND_CONSTANTS
- 颜色混合常量是动态的
vkCmdSetBlendConstants()
- VK_DYNAMIC_STATE_DEPTH_BOUNDS
- 深度界限参数是动态的
vkCmdSetDepthBounds()
- VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK、VK_DYNAMIC_STATE_STENCIL_WRITE_MASK 和 VK_DYNAMIC_STATE_STENCIL_REFERENCE
- 对应的模板参数是动态的
vkCmdSetStencilCompareMask()
vkCmdSetStencilWriteMask()
vkCmdSetStencilReference()
- 动态和静态状态的有效性
- Page 211
- 最佳实践是,首先绑定管线,然后绑定任何相关状态,以避免潜在的未定义行为发生
闭关之 Vulkan 应用开发指南笔记(三): 着色器和管线、图形管线相关推荐
- 开发指南专题三:JEECG微云快速开发平台项目编码规范
开发指南专题三:JEECG微云快速开发平台项目编码规范 4. 项目编码规范 4.1. 项目编码规范 1. 项目编码格式为UTF-8(包括:java,jsp,css,js) 2. sevice接口命名: ...
- 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现
本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9313239 作者:七十一雾央 新浪微博:http:// ...
- Elasticsearch6.8开发指南-第三章-设置Elasticsearch
Elasticsearch6.8开发指南-第三章-设置Elasticsearch 本章简介 安装Elasticsearch 使用.zip或安装Elasticsearch.tar.gz 在Windows ...
- 【SQL Server】数据库开发指南(三)面向数据分析的 T-SQL 编程技巧与实践
本系列博文还在更新中,收录在专栏:#MS-SQL Server 专栏中. 本系列文章列表如下: [SQL Server] Linux 运维下对 SQL Server 进行安装.升级.回滚.卸载操作 [ ...
- Polyworks脚本开发学习笔记(三)-TREEVIEW进阶操作
Polyworks脚本开发学习笔记(三)-TREEVIEW进阶操作 移动/交换对象的顺序 移动对象的顺序 TREEVIEW FEATURE MOVE ( 1,2 ) 将索引号为1和2的特征交换位置 T ...
- 3D可视化开发(基于顶点着色器和片元着色器)
3D可视化开发(基于顶点着色器和片元着色器) 背景:最近在做大屏的3d地图可视化开发,技术采用three.js+glsl这样的是一种实现方式,其中使用glsl实现顶点着色器和片元着色器. GLSL G ...
- Android BLE 蓝牙开发指南(三)外围设备端开发详解
Android BLE开发指南(一)入门基础 Android BLE开发指南(二)中心设备端程序开发详解 这篇文章将会详细讲解低功耗蓝牙外围设备端程序开发的主要流程.对于Android开发者而言,或许 ...
- OpenGL超级宝典学习笔记:着色器存储区块、原子内存操作、内存屏障
前言 本篇在讲什么 本篇为蓝宝书学习笔记 着色器存储区块 原子内存操作 内存屏障 本篇适合什么 适合初学Open的小白 本篇需要什么 对 C++语法有简单认知 对 OpenGL有简单认知 最好是有 O ...
- LearnOpenGL学习笔记——几何着色器
几何着色器 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点.几何着色器可以在顶点发送到下一着色器阶段之前对它们随意 ...
- 【TDA2x学习】番外篇三、VisionSDK开发指南笔记
1.介绍 Vision Software Development Kit (SDK)是一种多处理器.多通道的用于TI家族ADAS SoCs的软件开发平台.该软件框架允许用户创建不同的ADAS应用程序数 ...
最新文章
- python中random模块中包含了随机数相关的功能函数_Python中random模块生成随机数详解...
- R语言导入SPSS文件实战
- Oracle从零开始04——SQL语句03——单行函数
- 网络服务器安全协议,ipsec 网络安全协议
- php boolean 全大写还是全小写,【PHP培训】PHP为什么大小写规则是如此不规则?
- 前端学习(1272):路由的基本概念和说明
- 10034 - Freckles 克鲁斯克尔最小生成树!~
- 一文快速探索视频用户网络画像与应用
- JavaScript 3D实时散点图
- 冒险岛进去计算机丢失,找不到队伍怎么办?《冒险岛2》打杂攻略
- apa引用要在文中吗_英文论文格式要求玩转APA
- matlab画站点降雨分布,matlab 怎样做整个中国各个气象站点上的温度变化趋势
- 浏览器 播放音频(IE,谷歌)
- 耗时两天,Html实现小米官网
- 计算机网络处理延时是什么原因,电脑网络延迟的解决方法是什么
- 从人工智能到物联网……这些公司如何改变农业与食品工业
- 条件极值(拉格朗日乘数法)_Simplelife_新浪博客
- AltiumDesigner覆铜挖空技巧总结
- Java实现各种视频格式下载
- python股权变动监控系统_每天5分钟玩转Python(12) - 生成器(下)
热门文章
- 洛谷 P4704 太极剑
- Python--pyaudio声卡录音
- vba模拟鼠标点击_这些掌握了,你才敢说自己懂VBA
- 如何创建unity的菜单栏和窗口
- 2019年春节抢红包最全攻略,最多可领取10000元红包!
- 深度学习第一次作业 - 波士顿房价预测
- html代码入门书记,“seo优化”学习基本的html代码知识(入门级)
- broker可以禁用吗 time_【pximouse可以禁用吗】pximouse是什么程序_pximouse是什么
- 关于注意力的自上而下和自下而上(top-down attention and bottom-up attention)
- Unity与iOS相互调用