VK_KHR_vertex_attribute_divisor

此扩展从 VK_EXT_vertex_attribute_divisor 提升而来,允许在启用实例渲染时,实例速率顶点属性对于一定数量的实例重复使用,而不是每个实例都前进。

1. 问题陈述

在其他 API(如 OpenGL)中,可以在启用实例渲染时,将相同的顶点属性值用于多个连续的实例。这通常被称为“顶点属性除数”。例如,如果除数为 N,则相同的顶点属性将应用于 N 个连续的实例,然后再移动到下一个顶点属性。值为 0 允许将相同的顶点属性应用于所有实例。

此功能最初在 Vulkan 中通过 VK_EXT_vertex_attribute_divisor 扩展引入。

2. 提案

VK_EXT_vertex_attribute_divisor 中的 API 提升为 KHR,但以下情况除外:

VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT 相比,VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR 结构包含一个额外的属性 supportsNonZeroFirstInstance

顶点属性除数可以使用以下方式指定:

typedef struct VkVertexInputBindingDivisorDescriptionKHR {
    uint32_t    binding;
    uint32_t    divisor;
} VkVertexInputBindingDivisorDescriptionKHR;

该方式指定给定顶点绑定的除数值。当启用实例渲染时,divisor 是将使用相同顶点属性值的连续实例的数量。例如,如果除数为 N,则相同的顶点属性将应用于 N 个连续的实例,然后再移动到下一个顶点属性。

以上内容在以下位置为每个顶点绑定指定一次:

typedef struct VkPipelineVertexInputDivisorStateCreateInfoKHR {
    VkStructureType                                     sType;
    const void*                                         pNext;
    uint32_t                                            vertexBindingDivisorCount;
    const VkVertexInputBindingDivisorDescriptionKHR*    pVertexBindingDivisors;
} VkPipelineVertexInputDivisorStateCreateInfoKHR;

当链接到 VkPhysicalDeviceProperties2 时,可以使用以下结构查询允许的最大除数值:

typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR {
    VkStructureType    sType;
    void*              pNext;
    uint32_t           maxVertexAttribDivisor;
    VkBool32           supportsNonZeroFirstInstance;
} VkPhysicalDeviceVertexAttributeDivisorPropertiesKHR;

在上述内容中,supportsNonZeroFirstInstance 指定当 VkVertexInputBindingDivisorDescriptionKHR::divisor(或等效的动态设置状态)不为 1 时,是否支持绘制命令的 firstInstance 参数的非零值。请注意,与 VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT 相比,此属性是新增的。

VK_EXT_vertex_input_dynamic_stateVK_EXT_shader_object 扩展提供了 vkCmdSetVertexInputEXT 函数,允许动态设置顶点属性除数状态。

此扩展的功能由以下特性控制:

typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR {
    VkStructureType    sType;
    void*              pNext;
    VkBool32           vertexAttributeInstanceRateDivisor;
    VkBool32           vertexAttributeInstanceRateZeroDivisor;
} VkPhysicalDeviceVertexAttributeDivisorFeaturesKHR;
  • vertexAttributeInstanceRateDivisor 指定是否支持扩展中的功能。

  • vertexAttributeInstanceRateZeroDivisor 指定是否支持 VkVertexInputBindingDivisorDescriptionKHR::divisor 的零值。

3. 示例

可以在创建图形管线时指定顶点属性除数,如下所示:

const VkVertexInputBindingDivisorDescriptionKHR divisorDesc =
{
    .binding = 0,
    .divisor = 4,
};

const VkPipelineVertexInputDivisorStateCreateInfoKHR divisorInfo =
{
    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_KHR,
    .vertexBindingDivisorCount = 1,
    .pVertexBindingDivisors = &divisorDesc,
}

const VkVertexInputBindingDescription binding =
{
    .binding = 0,
    .stride = sizeof(Vertex),
    .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE,
};

const VkPipelineVertexInputStateCreateInfo viInfo =
{
    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO,
    .pNext = &divisorInfo,
    ...
};

4. 问题

1) firstInstance 的非零值有什么影响?

已解决:Vulkan API 应遵循 OpenGL 约定,在计算顶点属性偏移量时,将属性获取偏移 firstInstance