目录

  • 第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 实现可以优化对该缓冲区的访问
    • 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
      • 输入附件是一种特殊类型的图像
      • 它的内容是由图形管线里同一个图像上的早期操作所生成的
  • 建议你不要创建稀疏填充的集合,因为这会浪费设备资源
  • 把两个或多个描述符集打包成管线可以使用的形式
    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;
    
  • maxUniformBufferRangemaxStorageBufferRange 上限分别保证至少是 16384 与 2272^{27}227
  • minUniformBufferOffsetAlignmentminStorageBufferOffsetAlignment 要保证最多是 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 这个管线就是一个管线

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 个顶点作为开始的条带构成了一个带有邻接信息的三角形
      • 每两个新顶点构成一个新的三角形
      • 奇数序号的顶点构成三角形,偶数序号的顶点提供邻接信息

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 应用开发指南笔记(三): 着色器和管线、图形管线相关推荐

  1. 开发指南专题三:JEECG微云快速开发平台项目编码规范

    开发指南专题三:JEECG微云快速开发平台项目编码规范 4. 项目编码规范 4.1. 项目编码规范 1. 项目编码格式为UTF-8(包括:java,jsp,css,js) 2. sevice接口命名: ...

  2. 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9313239 作者:七十一雾央 新浪微博:http:// ...

  3. Elasticsearch6.8开发指南-第三章-设置Elasticsearch

    Elasticsearch6.8开发指南-第三章-设置Elasticsearch 本章简介 安装Elasticsearch 使用.zip或安装Elasticsearch.tar.gz 在Windows ...

  4. 【SQL Server】数据库开发指南(三)面向数据分析的 T-SQL 编程技巧与实践

    本系列博文还在更新中,收录在专栏:#MS-SQL Server 专栏中. 本系列文章列表如下: [SQL Server] Linux 运维下对 SQL Server 进行安装.升级.回滚.卸载操作 [ ...

  5. Polyworks脚本开发学习笔记(三)-TREEVIEW进阶操作

    Polyworks脚本开发学习笔记(三)-TREEVIEW进阶操作 移动/交换对象的顺序 移动对象的顺序 TREEVIEW FEATURE MOVE ( 1,2 ) 将索引号为1和2的特征交换位置 T ...

  6. 3D可视化开发(基于顶点着色器和片元着色器)

    3D可视化开发(基于顶点着色器和片元着色器) 背景:最近在做大屏的3d地图可视化开发,技术采用three.js+glsl这样的是一种实现方式,其中使用glsl实现顶点着色器和片元着色器. GLSL G ...

  7. Android BLE 蓝牙开发指南(三)外围设备端开发详解

    Android BLE开发指南(一)入门基础 Android BLE开发指南(二)中心设备端程序开发详解 这篇文章将会详细讲解低功耗蓝牙外围设备端程序开发的主要流程.对于Android开发者而言,或许 ...

  8. OpenGL超级宝典学习笔记:着色器存储区块、原子内存操作、内存屏障

    前言 本篇在讲什么 本篇为蓝宝书学习笔记 着色器存储区块 原子内存操作 内存屏障 本篇适合什么 适合初学Open的小白 本篇需要什么 对 C++语法有简单认知 对 OpenGL有简单认知 最好是有 O ...

  9. LearnOpenGL学习笔记——几何着色器

    几何着色器 在顶点和片段着色器之间有一个可选的几何着色器(Geometry Shader),几何着色器的输入是一个图元(如点或三角形)的一组顶点.几何着色器可以在顶点发送到下一着色器阶段之前对它们随意 ...

  10. 【TDA2x学习】番外篇三、VisionSDK开发指南笔记

    1.介绍 Vision Software Development Kit (SDK)是一种多处理器.多通道的用于TI家族ADAS SoCs的软件开发平台.该软件框架允许用户创建不同的ADAS应用程序数 ...

最新文章

  1. python中random模块中包含了随机数相关的功能函数_Python中random模块生成随机数详解...
  2. R语言导入SPSS文件实战
  3. Oracle从零开始04——SQL语句03——单行函数
  4. 网络服务器安全协议,ipsec 网络安全协议
  5. php boolean 全大写还是全小写,【PHP培训】PHP为什么大小写规则是如此不规则?
  6. 前端学习(1272):路由的基本概念和说明
  7. 10034 - Freckles 克鲁斯克尔最小生成树!~
  8. 一文快速探索视频用户网络画像与应用
  9. JavaScript 3D实时散点图
  10. 冒险岛进去计算机丢失,找不到队伍怎么办?《冒险岛2》打杂攻略
  11. apa引用要在文中吗_英文论文格式要求玩转APA
  12. matlab画站点降雨分布,matlab 怎样做整个中国各个气象站点上的温度变化趋势
  13. 浏览器 播放音频(IE,谷歌)
  14. 耗时两天,Html实现小米官网
  15. 计算机网络处理延时是什么原因,电脑网络延迟的解决方法是什么
  16. 从人工智能到物联网……这些公司如何改变农业与食品工业
  17. 条件极值(拉格朗日乘数法)_Simplelife_新浪博客
  18. AltiumDesigner覆铜挖空技巧总结
  19. Java实现各种视频格式下载
  20. python股权变动监控系统_每天5分钟玩转Python(12) - 生成器(下)

热门文章

  1. 洛谷 P4704 太极剑
  2. Python--pyaudio声卡录音
  3. vba模拟鼠标点击_这些掌握了,你才敢说自己懂VBA
  4. 如何创建unity的菜单栏和窗口
  5. 2019年春节抢红包最全攻略,最多可领取10000元红包!
  6. 深度学习第一次作业 - 波士顿房价预测
  7. html代码入门书记,“seo优化”学习基本的html代码知识(入门级)
  8. broker可以禁用吗 time_【pximouse可以禁用吗】pximouse是什么程序_pximouse是什么
  9. 关于注意力的自上而下和自下而上(top-down attention and bottom-up attention)
  10. Unity与iOS相互调用