Vulkan规范:第九章 9.7

9.7. 特化常量(Specialization Constants)

特化常量是一种机制,在SPIR-V模块中保有VkPipeline被创建时指定的常量。 这允许SPIR-V模块保有应用程序运行过程中通过Vulkan API可更改的常量。

注意

计算着色器需要在运行时改变本地工作组大小时,特化常量很有用。

VkPipelineShaderStageCreateInfo的每一个实例包含一个参数pSpecializationInfo, 可以是 NULL ,表示没有特化常量,或者指向VkSpecializationInfo

VkSpecializationInfo 类型数据结构定义如下:

typedef struct VkSpecializationInfo {
    uint32_t                           mapEntryCount;
    const VkSpecializationMapEntry*    pMapEntries;
    size_t                             dataSize;
    const void*                        pData;
} VkSpecializationInfo;
  • mapEntryCount 是 pMapEntries 数组的元素个数。

  • pMapEntries是一个 VkSpecializationMapEntry 数组,每一个元素存储了 constant IDs 和对应的pData偏移值。

  • dataSize 是pData buffer 的字节大小。

  • pData 包含了真实的需要特化的constant值。

pMapEntries 指向一个类型为VkSpecializationMapEntry 的数据。

正确使用
  • The offset member of any given element of pMapEntries must be less than dataSize

  • For any given element of pMapEntriessize must be less than or equal to dataSize minus offset

  • If mapEntryCount is not 0pMapEntries must be a pointer to an array of mapEntryCount valid VkSpecializationMapEntry structures

Valid Usage (Implicit)
  • If dataSize is not 0pData must be a pointer to an array of dataSize bytes

VkSpecializationMapEntry 类型数据结构定义如下:

typedef struct VkSpecializationMapEntry {
    uint32_t    constantID;
    uint32_t    offset;
    size_t      size;
} VkSpecializationMapEntry;
  • constantID 是SPIR-V中特化常量的ID。

  • offset 是提供的数据buffer中特化常量值的起始便宜量(字节单位)。

  • size 是提供的数据buffer中特化常量值的大小(字节单位)。

若 constantID 的值并不是在着色器中使用的特化常量ID,这个map entry将不会影响管线的行为。

正确使用
  • For a constantID specialization constant declared in a shader, size must match the byte size of the constantID. If the specialization constant is of type booleansize must be the byte size of VkBool32

In human readable SPIR-V:

OpDecorate %x SpecId 13 ; decorate .x component of WorkgroupSize with ID 13
OpDecorate %y SpecId 42 ; decorate .y component of WorkgroupSize with ID 42
OpDecorate %z SpecId 3  ; decorate .z component of WorkgroupSize with ID 3
OpDecorate %wgsize BuiltIn WorkgroupSize ; decorate WorkgroupSize onto constant
%i32 = OpTypeInt 32 0 ; declare an unsigned 32-bit type
%uvec3 = OpTypeVector %i32 3 ; declare a 3 element vector type of unsigned 32-bit
%x = OpSpecConstant %i32 1 ; declare the .x component of WorkgroupSize
%y = OpSpecConstant %i32 1 ; declare the .y component of WorkgroupSize
%z = OpSpecConstant %i32 1 ; declare the .z component of WorkgroupSize
%wgsize = OpSpecConstantComposite %uvec3 %x %y %z ; declare WorkgroupSize

From the above we have three specialization constants, one for each of the x, y & z elements of the WorkgroupSize vector.

Now to specialize the above via the specialization constants mechanism:

const VkSpecializationMapEntry entries[] =
{
    {
        13,                             // constantID
        0 * sizeof(uint32_t),           // offset
        sizeof(uint32_t)                // size
    },
    {
        42,                             // constantID
        1 * sizeof(uint32_t),           // offset
        sizeof(uint32_t)                // size
    },
    {
        3,                              // constantID
        2 * sizeof(uint32_t),           // offset
        sizeof(uint32_t)                // size
    }
};

const uint32_t data[] = { 16, 8, 4 }; // our workgroup size is 16x8x4

const VkSpecializationInfo info =
{
    3,                                  // mapEntryCount
    entries,                            // pMapEntries
    3 * sizeof(uint32_t),               // dataSize
    data,                               // pData
};

Then when calling vkCreateComputePipelines, and passing the VkSpecializationInfo we defined as the pSpecializationInfo parameter of VkPipelineShaderStageCreateInfo, we will create a compute pipeline with the runtime specified local workgroup size.

Another example would be that an application has a SPIR-V module that has some platform-dependent constants they wish to use.

In human readable SPIR-V:

OpDecorate %1 SpecId 0  ; decorate our signed 32-bit integer constant
OpDecorate %2 SpecId 12 ; decorate our 32-bit floating-point constant
%i32 = OpTypeInt 32 1   ; declare a signed 32-bit type
%float = OpTypeFloat 32 ; declare a 32-bit floating-point type
%1 = OpSpecConstant %i32 -1 ; some signed 32-bit integer constant
%2 = OpSpecConstant %float 0.5 ; some 32-bit floating-point constant

From the above we have two specialization constants, one is a signed 32-bit integer and the second is a 32-bit floating-point.

Now to specialize the above via the specialization constants mechanism:

struct SpecializationData {
    int32_t data0;
    float data1;
};

const VkSpecializationMapEntry entries[] =
{
    {
        0,                                    // constantID
        offsetof(SpecializationData, data0),  // offset
        sizeof(SpecializationData::data0)     // size
    },
    {
        12,                                   // constantID
        offsetof(SpecializationData, data1),  // offset
        sizeof(SpecializationData::data1)     // size
    }
};

SpecializationData data;
data.data0 = -42;    // set the data for the 32-bit integer
data.data1 = 42.0f;  // set the data for the 32-bit floating-point

const VkSpecializationInfo info =
{
    2,                                  // mapEntryCount
    entries,                            // pMapEntries
    sizeof(data),                       // dataSize
    &data,                              // pData
};

It is legal for a SPIR-V module with specializations to be compiled into a pipeline where no specialization info was provided. SPIR-V specialization constants contain default values such that if a specialization is not provided, the default value will be used. In the examples above, it would be valid for an application to only specialize some of the specialization constants within the SPIR-V module, and let the other constants use their default values encoded within the OpSpecConstant declarations.

9.8. 管线的绑定

一旦管线被创建完成,可以使用一个命令把它绑定到命令缓冲区:

void vkCmdBindPipeline(
    VkCommandBuffer                             commandBuffer,
    VkPipelineBindPoint                         pipelineBindPoint,
    VkPipeline                                  pipeline);
  • commandBuffer 是管线将要绑定的命令缓冲区。

  • pipelineBindPoint 指定了绑定点,必须是如下的值之一。

    typedef enum VkPipelineBindPoint {
        VK_PIPELINE_BIND_POINT_GRAPHICS = 0,
        VK_PIPELINE_BIND_POINT_COMPUTE = 1,
    } VkPipelineBindPoint;

    specifying whether pipeline will be bound as a compute (VK_PIPELINE_BIND_POINT_COMPUTE) or graphics (VK_PIPELINE_BIND_POINT_GRAPHICS) pipeline. There are separate bind points for each of graphics and compute, so binding one does not disturb the other.

  • pipeline 是将被绑定的管线。

绑定完成后,该绑定影响命令缓冲区中稍后的图形和计算命令,直到新的管线被绑定到绑定点。 绑定到VK_PIPELINE_BIND_POINT_COMPUTE的管线控制了vkCmdDispatch and vkCmdDispatchIndirect的行为。 绑定到VK_PIPELINE_BIND_POINT_GRAPHICS的管线控制了vkCmdDrawvkCmdDrawIndexedvkCmdDrawIndirect, and vkCmdDrawIndexedIndirect的行为。 其他的命令不受管线状态的影响。

正确使用
  • 若 pipelineBindPoint 是 VK_PIPELINE_BIND_POINT_COMPUTE,分配出commandBuffer 的VkCommandPool 必须支持计算操作。

  • 若 pipelineBindPoint 是 VK_PIPELINE_BIND_POINT_GRAPHICS,分配出commandBufferVkCommandPool 必须支持图像操作。

  • 若 pipelineBindPoint 是 VK_PIPELINE_BIND_POINT_COMPUTEpipeline 必须是计算管线。

  • 若 pipelineBindPoint 是 VK_PIPELINE_BIND_POINT_GRAPHICSpipeline 必须是图形管线。

  • variable multisample rate 特征不受支持,pipeline 就是图形管线,当前subpass没有附件,当转移到当前subpass后 这并不是第一次对图形管线调用这个函数,由此管线指定的采样数必须和前一个管线匹配。

Valid Usage (Implicit)
  • commandBuffer must be a valid VkCommandBuffer handle

  • pipelineBindPoint must be a valid VkPipelineBindPoint value

  • pipeline must be a valid VkPipeline handle

  • commandBuffer must be in the recording state

  • The VkCommandPool that commandBuffer was allocated from must support graphics, or compute operations

  • Both of commandBuffer, and pipeline must have been created, allocated, or retrieved from the same VkDevice

Host Synchronization
  • Host access to commandBuffer must be externally synchronized

  • Host access to the VkCommandPool that commandBuffer was allocated from must be externally synchronized

Command Properties

Command Buffer Levels Render Pass Scope Supported Queue Types Pipeline Type

Primary
Secondary

Both

Graphics
compute

猜你喜欢

转载自blog.csdn.net/cloudqiu/article/details/78585970
9.7