设备生成的命令
本章讨论在设备上生成命令缓冲区内容,为此需要采取以下主要步骤
-
定义描述应生成的命令序列的布局。
-
(可选)设置设备可绑定的着色器。
-
通过 vkGetBufferDeviceAddressEXT 检索设备地址,以便在设备上设置缓冲区。
-
使用由命令布局解释的适当内容填充一个或多个
VkBuffer
。 -
使用设备查询的分配信息创建
preprocess
VkBuffer
。 -
(可选)在单独的操作中预处理输入数据。
-
生成并执行实际命令。
预处理步骤在与图形或计算不同的单独逻辑管道中执行。当在单独的步骤中预处理命令时,必须 显式地与命令执行同步。当不在单独的步骤中预处理时,预处理会自动与命令执行同步。
间接命令布局
设备端命令生成通过原子序列的迭代处理发生,原子序列由命令令牌组成,命令令牌由
// Provided by VK_EXT_device_generated_commands
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutEXT)
或
// Provided by VK_NV_device_generated_commands
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNV)
每个间接命令布局必须恰好有一个操作命令令牌,并且它必须是序列中的最后一个令牌。
如果间接命令布局仅包含 1 个令牌,它将是一个操作命令令牌,并且间接缓冲区的内容将是一个间接命令结构序列,类似于用于间接绘制和分派的那些。在某些实现中,对于这些情况使用间接绘制和分派将比使用设备生成的命令产生更高的性能,因为后者会导致开销。 |
创建和删除
用于 VK_EXT_device_generated_commands
的间接命令布局是通过
// Provided by VK_EXT_device_generated_commands
VkResult vkCreateIndirectCommandsLayoutEXT(
VkDevice device,
const VkIndirectCommandsLayoutCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkIndirectCommandsLayoutEXT* pIndirectCommandsLayout);
-
device
是创建间接命令布局的逻辑设备。 -
pCreateInfo
是指向 VkIndirectCommandsLayoutCreateInfoEXT 结构的指针,该结构包含影响间接命令布局创建的参数。 -
pAllocator
控制主机内存分配,如 内存分配 章节所述。 -
pIndirectCommandsLayout
是指向VkIndirectCommandsLayoutEXT
句柄的指针,在该句柄中返回生成的间接命令布局。
VkIndirectCommandsLayoutCreateInfoEXT
结构定义为
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectCommandsLayoutCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkIndirectCommandsLayoutUsageFlagsEXT flags;
VkShaderStageFlags shaderStages;
uint32_t indirectStride;
VkPipelineLayout pipelineLayout;
uint32_t tokenCount;
const VkIndirectCommandsLayoutTokenEXT* pTokens;
} VkIndirectCommandsLayoutCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是一个 VkIndirectCommandsLayoutUsageFlagBitsEXT 的位掩码,指定此布局的使用规则。 -
shaderStages
是此布局支持的 VkShaderStageFlags。 -
indirectStride
是间接缓冲区中序列之间的距离(以字节为单位) -
pipelineLayout
是一个可选的 VkPipelineLayout,此布局中的 token 会使用它。如果启用了dynamicGeneratedPipelineLayout
功能,则pipelineLayout
可以是 VK_NULL_HANDLE,并且布局必须通过将 VkPipelineLayoutCreateInfo 结构体链接到pNext
来指定。 -
tokenCount
是单个命令序列的长度。 -
pTokens
是一个指向 VkIndirectCommandsLayoutTokenEXT 数组的指针,该数组详细描述了每个命令 token。
以下代码说明了一些标志
void cmdProcessAllSequences(cmd, indirectExecutionSet, indirectCommandsLayout, indirectAddress, sequencesCount)
{
for (s = 0; s < sequencesCount; s++)
{
sUsed = s;
if (indirectCommandsLayout.flags & VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT) {
sUsed = incoherent_implementation_dependent_permutation[ sUsed ];
}
cmdProcessSequence( cmd, indirectExecutionSet, indirectCommandsLayout, indirectAddress, sUsed );
}
}
当 token 被使用时,会基于 token 偏移量和流步长计算一个偏移量。计算出的偏移量必须是对齐的。特定 token 的对齐方式等于 对齐要求中定义的数据类型的标量对齐方式,或者 4
,取两者中较小的值。
在 VkIndirectCommandsLayoutCreateInfoEXT::flags
中**可以**设置的位,用于指定间接命令布局的使用提示,包括:
// Provided by VK_EXT_device_generated_commands
typedef enum VkIndirectCommandsLayoutUsageFlagBitsEXT {
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_EXT = 0x00000001,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT = 0x00000002,
} VkIndirectCommandsLayoutUsageFlagBitsEXT;
-
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_EXT
指定该布局始终与通过调用 vkCmdPreprocessGeneratedCommandsEXT 手动预处理步骤一起使用,并通过 vkCmdExecuteGeneratedCommandsEXT 执行,且isPreprocessed
设置为VK_TRUE
。 -
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT
指定序列的处理将以依赖于实现的顺序进行,该顺序不能保证在使用相同输入数据时是确定性的。当shaderStages
为VK_SHADER_STAGE_COMPUTE_BIT
时,此标志将被忽略,因为它暗示调度序列始终是无序的。
// Provided by VK_EXT_device_generated_commands
typedef VkFlags VkIndirectCommandsLayoutUsageFlagsEXT;
VkIndirectCommandsLayoutUsageFlagsEXT
是一个位掩码类型,用于设置零个或多个 VkIndirectCommandsLayoutUsageFlagBitsEXT 的掩码。
VK_EXT_device_generated_commands
的间接命令布局通过以下方式销毁:
// Provided by VK_EXT_device_generated_commands
void vkDestroyIndirectCommandsLayoutEXT(
VkDevice device,
VkIndirectCommandsLayoutEXT indirectCommandsLayout,
const VkAllocationCallbacks* pAllocator);
-
device
是销毁布局的逻辑设备。 -
indirectCommandsLayout
是要销毁的布局。 -
pAllocator
控制主机内存分配,如 内存分配 章节所述。
VK_NV_device_generated_commands
的间接命令布局通过以下方式创建:
// Provided by VK_NV_device_generated_commands
VkResult vkCreateIndirectCommandsLayoutNV(
VkDevice device,
const VkIndirectCommandsLayoutCreateInfoNV* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkIndirectCommandsLayoutNV* pIndirectCommandsLayout);
-
device
是创建间接命令布局的逻辑设备。 -
pCreateInfo
是指向 VkIndirectCommandsLayoutCreateInfoNV 结构的指针,其中包含影响间接命令布局创建的参数。 -
pAllocator
控制主机内存分配,如 内存分配 章节所述。 -
pIndirectCommandsLayout
是指向VkIndirectCommandsLayoutNV
句柄的指针,其中返回生成的间接命令布局。
VkIndirectCommandsLayoutCreateInfoNV
结构定义如下:
// Provided by VK_NV_device_generated_commands
typedef struct VkIndirectCommandsLayoutCreateInfoNV {
VkStructureType sType;
const void* pNext;
VkIndirectCommandsLayoutUsageFlagsNV flags;
VkPipelineBindPoint pipelineBindPoint;
uint32_t tokenCount;
const VkIndirectCommandsLayoutTokenNV* pTokens;
uint32_t streamCount;
const uint32_t* pStreamStrides;
} VkIndirectCommandsLayoutCreateInfoNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pipelineBindPoint
是此布局所针对的 VkPipelineBindPoint。 -
flags
是一个 VkIndirectCommandsLayoutUsageFlagBitsNV 的位掩码,指定此布局的用法提示。 -
tokenCount
是单个命令序列的长度。 -
pTokens
是一个数组,详细描述每个命令标记。有关详细信息,请参见下面的 VkIndirectCommandsTokenTypeNV 和 VkIndirectCommandsLayoutTokenNV。 -
streamCount
是用于提供令牌输入的流的数量。 -
pStreamStrides
是一个数组,定义每个输入流的字节步幅。
以下代码说明了一些标志
void cmdProcessAllSequences(cmd, pipeline, indirectCommandsLayout, pIndirectCommandsTokens, sequencesCount, indexbuffer, indexbufferOffset)
{
for (s = 0; s < sequencesCount; s++)
{
sUsed = s;
if (indirectCommandsLayout.flags & VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV) {
sUsed = indexbuffer.load_uint32( sUsed * sizeof(uint32_t) + indexbufferOffset);
}
if (indirectCommandsLayout.flags & VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV) {
sUsed = incoherent_implementation_dependent_permutation[ sUsed ];
}
cmdProcessSequence( cmd, pipeline, indirectCommandsLayout, pIndirectCommandsTokens, sUsed );
}
}
当令牌被消耗时,会基于令牌偏移和流步幅计算偏移量。生成的偏移量必须是对齐的。特定令牌的对齐方式等于 对齐要求 中定义的数据类型的标量对齐,或 VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV
::minIndirectCommandsBufferOffsetAlignment
,以较小者为准。
|
在 VkIndirectCommandsLayoutCreateInfoNV::flags
中可以设置的位,指定间接命令布局的使用提示,包括:
// Provided by VK_NV_device_generated_commands
typedef enum VkIndirectCommandsLayoutUsageFlagBitsNV {
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV = 0x00000001,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV = 0x00000002,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV = 0x00000004,
} VkIndirectCommandsLayoutUsageFlagBitsNV;
-
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EXPLICIT_PREPROCESS_BIT_NV
指定该布局始终通过调用 vkCmdPreprocessGeneratedCommandsNV 进行手动预处理步骤,并通过 vkCmdExecuteGeneratedCommandsNV 执行,且isPreprocessed
设置为VK_TRUE
。 -
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NV
指定序列的输入数据不是从 0..sequencesUsed 隐式索引,而是提供应用程序提供的VkBuffer
来编码索引。 -
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV
指定序列的处理可以以依赖于实现的顺序发生,不能保证使用相同输入数据时的一致性。当pipelineBindPoint
为VK_PIPELINE_BIND_POINT_COMPUTE
时,此标志将被忽略,因为这意味着调度序列始终是无序的。
// Provided by VK_NV_device_generated_commands
typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNV;
VkIndirectCommandsLayoutUsageFlagsNV
是一种位掩码类型,用于设置零个或多个 VkIndirectCommandsLayoutUsageFlagBitsNV 的掩码。
用于 VK_NV_device_generated_commands
的间接命令布局通过以下方式销毁:
// Provided by VK_NV_device_generated_commands
void vkDestroyIndirectCommandsLayoutNV(
VkDevice device,
VkIndirectCommandsLayoutNV indirectCommandsLayout,
const VkAllocationCallbacks* pAllocator);
-
device
是销毁布局的逻辑设备。 -
indirectCommandsLayout
是要销毁的布局。 -
pAllocator
控制主机内存分配,如 内存分配 章节所述。
令牌输入流
对于 VK_EXT_device_generated_commands
,输入流可以包含原始 uint32_t
值,现有的间接命令,例如:
或如下所列的其他命令。数据如何使用将在下一节中描述。
VkBindIndexBufferIndirectCommandEXT
结构体指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT
令牌的输入数据。
// Provided by VK_EXT_device_generated_commands
typedef struct VkBindIndexBufferIndirectCommandEXT {
VkDeviceAddress bufferAddress;
uint32_t size;
VkIndexType indexType;
} VkBindIndexBufferIndirectCommandEXT;
-
bufferAddress
指定用作索引缓冲区的 VkBuffer 的物理地址。 -
size
是从此地址可用于此操作的字节大小范围。 -
indexType
是一个 VkIndexType 值,指定如何处理索引。
VkBindVertexBufferIndirectCommandEXT
结构体指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT
令牌的输入数据。
// Provided by VK_EXT_device_generated_commands
typedef struct VkBindVertexBufferIndirectCommandEXT {
VkDeviceAddress bufferAddress;
uint32_t size;
uint32_t stride;
} VkBindVertexBufferIndirectCommandEXT;
-
bufferAddress
指定用作顶点输入绑定的 VkBuffer 的物理地址。 -
size
是从此地址可用于此操作的字节大小范围。 -
stride
是此顶点输入绑定的字节大小步幅,与VkVertexInputBindingDescription
::stride
中的步幅相同。
VkDrawIndirectCountIndirectCommandEXT
结构体指定所有绘制类型令牌的输入数据。
// Provided by VK_EXT_device_generated_commands
typedef struct VkDrawIndirectCountIndirectCommandEXT {
VkDeviceAddress bufferAddress;
uint32_t stride;
uint32_t commandCount;
} VkDrawIndirectCountIndirectCommandEXT;
-
bufferAddress
指定用于绘制命令的 VkBuffer 的物理地址。 -
stride
是命令参数的字节大小步幅。 -
commandCount
是要执行的命令数。
相应的间接绘制结构数据将从缓冲区地址读取。
VkIndirectCommandsStreamNV
结构体在处理时指定一个或多个令牌的输入数据。
// Provided by VK_NV_device_generated_commands
typedef struct VkIndirectCommandsStreamNV {
VkBuffer buffer;
VkDeviceSize offset;
} VkIndirectCommandsStreamNV;
-
buffer
指定存储每个序列的功能参数的 VkBuffer。这些参数可以由设备写入。 -
offset
指定buffer
中参数开始处的偏移量。
对于 VK_NV_device_generated_commands
,输入流**可以**包含原始的 uint32_t
值,以及现有的间接命令,例如
或如下所列的其他命令。数据如何使用将在下一节中描述。
VkBindShaderGroupIndirectCommandNV
结构指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV
令牌的输入数据。
// Provided by VK_NV_device_generated_commands
typedef struct VkBindShaderGroupIndirectCommandNV {
uint32_t groupIndex;
} VkBindShaderGroupIndirectCommandNV;
-
groupIndex
指定当前绑定的图形管线的哪个着色器组被使用。
VkBindIndexBufferIndirectCommandNV
结构指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV
令牌的输入数据。
// Provided by VK_NV_device_generated_commands
typedef struct VkBindIndexBufferIndirectCommandNV {
VkDeviceAddress bufferAddress;
uint32_t size;
VkIndexType indexType;
} VkBindIndexBufferIndirectCommandNV;
-
bufferAddress
指定用作索引缓冲区的 VkBuffer 的物理地址。 -
size
是从此地址可用于此操作的字节大小范围。 -
indexType
是一个 VkIndexType 值,指定如何处理索引。 可以通过指定VkIndirectCommandsLayoutTokenNV
::pIndexTypes
和VkIndirectCommandsLayoutTokenNV
::pIndexTypeValues
数组,将自定义的uint32_t
值映射到 VkIndexType,而不是 Vulkan 枚举值。
VkBindVertexBufferIndirectCommandNV
结构指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV
令牌的输入数据。
// Provided by VK_NV_device_generated_commands
typedef struct VkBindVertexBufferIndirectCommandNV {
VkDeviceAddress bufferAddress;
uint32_t size;
uint32_t stride;
} VkBindVertexBufferIndirectCommandNV;
-
bufferAddress
指定用作顶点输入绑定的 VkBuffer 的物理地址。 -
size
是从此地址可用于此操作的字节大小范围。 -
stride
是此顶点输入绑定的字节大小步幅,如VkVertexInputBindingDescription
::stride
中所示。只有当设置了VkIndirectCommandsLayoutTokenNV
::vertexDynamicStride
时才使用它,否则步幅将从当前绑定的图形管线继承。
VkSetStateFlagsIndirectCommandNV
结构指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV
令牌的输入数据。更改哪个状态取决于在创建 VkIndirectCommandsLayoutNV
时指定的 VkIndirectStateFlagBitsNV。
// Provided by VK_NV_device_generated_commands
typedef struct VkSetStateFlagsIndirectCommandNV {
uint32_t data;
} VkSetStateFlagsIndirectCommandNV;
-
data
编码此命令更改的打包状态。-
位
0
:如果设置,则表示VK_FRONT_FACE_CLOCKWISE
,否则表示VK_FRONT_FACE_COUNTER_CLOCKWISE
-
可以使用间接状态标志更改图形管线状态的子集。
// Provided by VK_NV_device_generated_commands
typedef enum VkIndirectStateFlagBitsNV {
VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV = 0x00000001,
} VkIndirectStateFlagBitsNV;
-
VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV
允许为后续的绘图命令切换 VkFrontFace 光栅化状态。
// Provided by VK_NV_device_generated_commands
typedef VkFlags VkIndirectStateFlagsNV;
VkIndirectStateFlagsNV
是一种位掩码类型,用于设置零个或多个 VkIndirectStateFlagBitsNV 的掩码。
VkBindPipelineIndirectCommandNV
结构指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV
令牌的输入数据。
// Provided by VK_NV_device_generated_commands_compute
typedef struct VkBindPipelineIndirectCommandNV {
VkDeviceAddress pipelineAddress;
} VkBindPipelineIndirectCommandNV;
-
pipelineAddress
指定设备生成渲染中将使用的计算管线的管线地址。
标记化命令处理
原则上,下面说明了 VK_EXT_device_generated_commands
的处理过程
void cmdProcessSequence(cmd, indirectExecutionSet, indirectCommandsLayout, indirectAddress, s)
{
for (t = 0; t < indirectCommandsLayout.tokenCount; t++)
{
uint32_t offset = indirectCommandsLayout.pTokens[t].offset;
uint32_t stride = indirectCommandsLayout.indirectStride;
VkDeviceAddress streamData = indirectAddress;
const void* input = streamData + stride * s + offset;
// further details later
indirectCommandsLayout.pTokens[t].command (cmd, indirectExecutionSet, input, s);
}
}
void cmdProcessAllSequences(cmd, indirectExecutionSet, indirectCommandsLayout, indirectAddress, sequencesCount)
{
for (s = 0; s < sequencesCount; s++)
{
sUsed = s;
if (indirectCommandsLayout.flags & VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT) {
sUsed = incoherent_implementation_dependent_permutation[ sUsed ];
}
cmdProcessSequence( cmd, indirectExecutionSet, indirectCommandsLayout, indirectAddress, sUsed );
}
}
每个序列的处理都被认为是无状态的,因此所有状态更改**必须**在序列中的操作命令之前发生。单个序列严格针对创建时使用的 VkShaderStageFlags。
每个令牌的主要输入数据是通过 VkBuffer
内容提供的,在预处理时使用 vkCmdPreprocessGeneratedCommandsEXT 或在执行时使用 vkCmdExecuteGeneratedCommandsEXT,但是某些功能参数(例如推送常量布局)是在布局创建时指定的。 每个令牌的输入大小都不同。
指定命令令牌的 VkIndirectCommandsLayoutCreateInfoEXT::pTokens
数组中的元素的可能值(数组的其他元素指定命令参数)为
// Provided by VK_EXT_device_generated_commands
typedef enum VkIndirectCommandsTokenTypeEXT {
VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT = 0,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT = 1,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT = 2,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT = 3,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT = 4,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT = 5,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT = 6,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT = 7,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT = 8,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT = 9,
// Provided by VK_EXT_device_generated_commands with VK_NV_mesh_shader
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT = 1000202002,
// Provided by VK_EXT_device_generated_commands with VK_NV_mesh_shader
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT = 1000202003,
// Provided by VK_EXT_device_generated_commands with VK_EXT_mesh_shader
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT = 1000328000,
// Provided by VK_EXT_device_generated_commands with VK_EXT_mesh_shader
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT = 1000328001,
// Provided by VK_KHR_ray_tracing_maintenance1 with VK_EXT_device_generated_commands
VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT = 1000386004,
} VkIndirectCommandsTokenTypeEXT;
通用令牌 | 命令数据 |
---|---|
|
|
|
|
|
|
计算令牌 |
|
|
|
光线追踪令牌 |
|
|
|
图形状态令牌 |
|
|
|
|
|
图形绘制令牌 |
|
|
|
|
|
|
|
|
|
图形绘制计数令牌 |
|
|
VkDrawIndirectCountIndirectCommandEXT 与 VkDrawIndexedIndirectCommand |
|
VkDrawIndirectCountIndirectCommandEXT 与 VkDrawIndirectCommand |
|
VkDrawIndirectCountIndirectCommandEXT 与 VkDrawMeshTasksIndirectCommandEXT |
|
VkDrawIndirectCountIndirectCommandEXT 与 VkDrawMeshTasksIndirectCommandNV |
VkIndirectCommandsLayoutTokenEXT
结构体指定了在布局创建时需要知道的函数参数的详细信息。
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectCommandsLayoutTokenEXT {
VkStructureType sType;
const void* pNext;
VkIndirectCommandsTokenTypeEXT type;
VkIndirectCommandsTokenDataEXT data;
uint32_t offset;
} VkIndirectCommandsLayoutTokenEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
type
指定了data
的 VkIndirectCommandsTokenTypeEXT。 -
data
指定了一个 VkIndirectCommandsTokenDataEXT,其中包含用于命令执行的特定于标记的详细信息。 如果type
与 VkIndirectCommandsTokenDataEXT 联合体的任何成员都不匹配,则忽略该信息。 -
offset
是间接缓冲区内一个序列中标记的相对字节偏移量。 存储在该偏移量处的数据是标记的命令数据,例如VkDispatchIndirectCommand
。
VkIndirectCommandsTokenDataEXT
结构体提供了用于生成间接执行布局的特定于标记的详细信息。
// Provided by VK_EXT_device_generated_commands
typedef union VkIndirectCommandsTokenDataEXT {
const VkIndirectCommandsPushConstantTokenEXT* pPushConstant;
const VkIndirectCommandsVertexBufferTokenEXT* pVertexBuffer;
const VkIndirectCommandsIndexBufferTokenEXT* pIndexBuffer;
const VkIndirectCommandsExecutionSetTokenEXT* pExecutionSet;
} VkIndirectCommandsTokenDataEXT;
-
pPushConstant
是指向VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT
和VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT
标记所需的 VkIndirectCommandsPushConstantTokenEXT 结构的指针。 -
pVertexBuffer
是指向VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT
标记所需的 VkIndirectCommandsVertexBufferTokenEXT 结构的指针。 -
pIndexBuffer
是指向VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT
标记所需的 VkIndirectCommandsIndexBufferTokenEXT 结构的指针。 -
pExecutionSet
是指向VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT
标记所需的 VkIndirectCommandsExecutionSetTokenEXT 结构的指针。
必须为每个标记设置联合体的相应成员。
以下代码提供了关于如何处理单个序列的详细信息。 对于有效使用,所有来自常规命令的限制都适用。
void cmdProcessSequence(cmd, indirectExecutionSet, indirectCommandsLayout, indirectAddress, s)
{
for (uint32_t t = 0; t < indirectCommandsLayout.tokenCount; t++) {
VkIndirectCommandsLayoutTokenEXT *token = &indirectCommandsLayout.pTokens[t];
uint32_t offset = token->offset;
uint32_t stride = indirectCommandsLayout.indirectStride;
VkDeviceAddress streamData = indirectAddress;
const void* input = streamData + stride * s + offset;
switch (token->tokenType) {
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT:
uint32_t *bind = input;
VkIndirectCommandsExecutionSetTokenEXT *info = token->data.pExecutionSet;
if (info->type == VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT) {
vkCmdBindPipeline(cmd, indirectExecutionSet.pipelineBindPoint, indirectExecutionSet.pipelines[*bind]);
} else {
VkShaderStageFlagBits stages[];
VkShaderEXT shaders[];
uint32_t i = 0;
IterateBitmaskLSBToMSB(iter, info->shaderStages) {
stages[i] = iter;
shaders[i] = indirectExecutionSet.shaders[bind[i]].shaderObject;
i++;
}
vkCmdBindShadersEXT(cmd, i, stages, shaders);
}
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT:
uint32_t* data = input;
VkPushConstantsInfoKHR info = {
VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO_KHR,
// this can also use `dynamicGeneratedPipelineLayout' to pass a VkPipelineLayoutCreateInfo from pNext
indirectCommandsLayout.pipelineLayout,
token->token.pushConstant.updateRange.shaderStages,
token->token.pushConstant.updateRange.offset,
token->token.pushConstant.updateRange.size,
data
};
vkCmdPushConstants2KHR(cmd, &info);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT:
VkPushConstantsInfoKHR info = {
VK_STRUCTURE_TYPE_PUSH_CONSTANTS_INFO_KHR,
// this can also use `dynamicGeneratedPipelineLayout' to pass a VkPipelineLayoutCreateInfo from pNext
indirectCommandsLayout.pipelineLayout,
token->token.pushConstant.updateRange.shaderStages,
token->token.pushConstant.updateRange.offset,
// this must be 4
token->token.pushConstant.updateRange.size,
// this just updates the sequence index
&s
};
vkCmdPushConstants2KHR(cmd, &info);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT:
VkBindIndexBufferIndirectCommandEXT* data = input;
vkCmdBindIndexBuffer(cmd, deriveBuffer(data->bufferAddress), deriveOffset(data->bufferAddress), data->indexType);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT:
VkBindVertexBufferIndirectCommandEXT* data = input;
vkCmdBindVertexBuffers2(cmd, token->token.vertexBuffer->vertexBindingUnit, 1, &deriveBuffer(data->bufferAddress),
&deriveOffset(data->bufferAddress), data->size, data->stride);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_EXT:
VkDrawIndexedIndirectCommand *data = input;
vkCmdDrawIndexed(cmd, data->indexCount, data->instanceCount, data->firstIndex, data->vertexOffset, data->firstInstance);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_COUNT_EXT:
VkDrawIndirectCountIndirectCommandEXT* data = input;
vkCmdDrawIndexedIndirect(cmd, deriveBuffer(data->bufferAddress), deriveoffset(data->bufferAddress), min(data->commandCount, indirectCommandsLayout.maxDrawCount), data->stride);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_EXT:
VkDrawIndirectCommand* data = input;
vkCmdDraw(cmd, data->vertex_count, data->instanceCount, data->firstVertex, data->firstIndex);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_COUNT_EXT:
VkDrawIndirectCountIndirectCommandEXT* data = input;
vkCmdDrawIndirect(cmd, deriveBuffer(data->bufferAddress), deriveoffset(data->bufferAddress), min(data->commandCount, indirectCommandsLayout.maxDrawCount), data->stride);
break;
// only available if VK_NV_mesh_shader is enabled
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV_EXT:
VkDrawMeshTasksIndirectCommandNV *data = input;
vkCmdDrawMeshTasksNV(cmd, data->taskCount, data->firstTask);
break;
// only available if VK_NV_mesh_shader is enabled
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_NV_EXT:
VkDrawIndirectCountIndirectCommandEXT* data = input;
vkCmdDrawMeshTasksIndirectCountNV(cmd, deriveBuffer(data->bufferAddress), deriveoffset(data->bufferAddress), min(data->commandCount, indirectCommandsLayout.maxDrawCount), data->stride);
break;
// only available if VK_EXT_mesh_shader is enabled
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_EXT:
VkDrawMeshTasksIndirectCommandEXT *data = input;
vkCmdDrawMeshTasksEXT(cmd, data->groupCountX, data->groupCountY, data->groupCountZ);
break;
// only available if VK_EXT_mesh_shader is enabled
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_COUNT_EXT:
VkDrawIndirectCountIndirectCommandEXT* data = input;
vkCmdDrawMeshTasksIndirectCountEXT(cmd, deriveBuffer(data->bufferAddress), deriveoffset(data->bufferAddress), min(data->commandCount, indirectCommandsLayout.maxDrawCount), data->stride);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT:
VkDispatchIndirectCommand *data = input;
vkCmdDispatch(cmd, data->x, data->y, data->z);
break;
// only available if VK_KHR_ray_tracing_maintenance1 is enabled
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_TRACE_RAYS2_EXT:
vkCmdTraceRaysIndirect2KHR(cmd, deriveBuffer(input));
break;
}
}
}
原则上,下面说明了 VK_NV_device_generated_commands
的处理过程
void cmdProcessSequence(cmd, pipeline, indirectCommandsLayout, pIndirectCommandsStreams, s)
{
for (t = 0; t < indirectCommandsLayout.tokenCount; t++)
{
uint32_t stream = indirectCommandsLayout.pTokens[t].stream;
uint32_t offset = indirectCommandsLayout.pTokens[t].offset;
uint32_t stride = indirectCommandsLayout.pStreamStrides[stream];
stream = pIndirectCommandsStreams[stream];
const void* input = stream.buffer.pointer( stream.offset + stride * s + offset )
// further details later
indirectCommandsLayout.pTokens[t].command (cmd, pipeline, input, s);
}
}
void cmdProcessAllSequences(cmd, pipeline, indirectCommandsLayout, pIndirectCommandsStreams, sequencesCount)
{
for (s = 0; s < sequencesCount; s++)
{
cmdProcessSequence(cmd, pipeline, indirectCommandsLayout, pIndirectCommandsStreams, s);
}
}
每个序列的处理都被认为是无状态的,因此所有状态更改必须在序列内的任何操作命令标记之前发生。单个序列严格地针对创建它时使用的 VkPipelineBindPoint。
每个标记的主要输入数据是通过使用 vkCmdPreprocessGeneratedCommandsNV 在预处理期间或使用 vkCmdExecuteGeneratedCommandsNV 在执行时,通过 VkBuffer
内容提供的,但是一些功能参数,例如绑定集,是在布局创建时指定的。每个标记的输入大小都不同。
VkIndirectCommandsPushConstantTokenEXT
结构体指定了 VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT
和 VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT
标记的布局标记信息。
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectCommandsPushConstantTokenEXT {
VkPushConstantRange updateRange;
} VkIndirectCommandsPushConstantTokenEXT;
-
updateRange
是将由标记更新的推送常量范围。
将忽略 updateRange
的 stageFlags
成员。
VkIndirectCommandsVertexBufferTokenEXT
结构体指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_EXT
令牌的布局令牌信息。
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectCommandsVertexBufferTokenEXT {
uint32_t vertexBindingUnit;
} VkIndirectCommandsVertexBufferTokenEXT;
-
vertexBindingUnit
是要绑定的顶点输入绑定编号。
VkIndirectCommandsIndexBufferTokenEXT
结构体指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_EXT
令牌的布局令牌信息。
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectCommandsIndexBufferTokenEXT {
VkIndirectCommandsInputModeFlagBitsEXT mode;
} VkIndirectCommandsIndexBufferTokenEXT;
-
mode
指定此令牌使用的模式。
这允许在其他 API 之上轻松分层 Vulkan。当指定 VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT
时,间接缓冲区可以包含 D3D12_INDEX_BUFFER_VIEW
而不是 VkBindIndexBufferIndirectCommandEXT,因为 D3D 的 DXGI 格式值映射到 VkIndexType。它的工作原理与两种结构体在其他方面都是二进制兼容的。
在 VkIndirectCommandsIndexBufferTokenEXT::mode
中设置的位,指定索引缓冲区的使用方式,为
// Provided by VK_EXT_device_generated_commands
typedef enum VkIndirectCommandsInputModeFlagBitsEXT {
VK_INDIRECT_COMMANDS_INPUT_MODE_VULKAN_INDEX_BUFFER_EXT = 0x00000001,
VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT = 0x00000002,
} VkIndirectCommandsInputModeFlagBitsEXT;
-
VK_INDIRECT_COMMANDS_INPUT_MODE_VULKAN_INDEX_BUFFER_EXT
指定间接缓冲区包含 VkBindIndexBufferIndirectCommandEXT。 -
VK_INDIRECT_COMMANDS_INPUT_MODE_DXGI_INDEX_BUFFER_EXT
指定间接缓冲区包含D3D12_INDEX_BUFFER_VIEW
。
// Provided by VK_EXT_device_generated_commands
typedef VkFlags VkIndirectCommandsInputModeFlagsEXT;
VkIndirectCommandsInputModeFlagsEXT
是一个位掩码类型,用于设置零个或多个 VkIndirectCommandsInputModeFlagBitsEXT 的掩码。
VkIndirectCommandsExecutionSetTokenEXT
结构体指定 VK_INDIRECT_COMMANDS_TOKEN_TYPE_EXECUTION_SET_EXT
令牌的输入数据。
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectCommandsExecutionSetTokenEXT {
VkIndirectExecutionSetInfoTypeEXT type;
VkShaderStageFlags shaderStages;
} VkIndirectCommandsExecutionSetTokenEXT;
-
type
描述正在使用的间接执行集的类型。 -
shaderStages
指定将由此令牌更改的着色器。
指定命令令牌的 VkIndirectCommandsLayoutCreateInfoNV::pTokens
数组的这些元素的可能值(数组的其他元素指定命令参数)为
// Provided by VK_NV_device_generated_commands
typedef enum VkIndirectCommandsTokenTypeNV {
VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV = 0,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV = 1,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV = 2,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV = 3,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV = 4,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV = 5,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV = 6,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV = 7,
// Provided by VK_EXT_mesh_shader with VK_NV_device_generated_commands
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV = 1000328000,
// Provided by VK_NV_device_generated_commands_compute
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV = 1000428003,
// Provided by VK_NV_device_generated_commands_compute
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NV = 1000428004,
} VkIndirectCommandsTokenTypeNV;
令牌类型 | 等效命令 |
---|---|
|
|
|
- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VkIndirectCommandsLayoutTokenNV
结构体指定布局创建时需要知道的函数参数的详细信息
// Provided by VK_NV_device_generated_commands
typedef struct VkIndirectCommandsLayoutTokenNV {
VkStructureType sType;
const void* pNext;
VkIndirectCommandsTokenTypeNV tokenType;
uint32_t stream;
uint32_t offset;
uint32_t vertexBindingUnit;
VkBool32 vertexDynamicStride;
VkPipelineLayout pushconstantPipelineLayout;
VkShaderStageFlags pushconstantShaderStageFlags;
uint32_t pushconstantOffset;
uint32_t pushconstantSize;
VkIndirectStateFlagsNV indirectStateFlags;
uint32_t indexTypeCount;
const VkIndexType* pIndexTypes;
const uint32_t* pIndexTypeValues;
} VkIndirectCommandsLayoutTokenNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
tokenType
是一个 VkIndirectCommandsTokenTypeNV,指定令牌命令类型。 -
stream
是包含令牌参数数据的输入流的索引。 -
offset
是令牌参数数据在输入流内存中的相对起始偏移量。 -
vertexBindingUnit
用于顶点缓冲区绑定命令。 -
vertexDynamicStride
设置顶点缓冲区步幅是否由绑定命令提供,而不是由当前绑定的图形管线状态提供。 -
pushconstantPipelineLayout
是用于推送常量命令的VkPipelineLayout
。 -
pushconstantShaderStageFlags
是用于推送常量命令的着色器阶段标志。 -
pushconstantOffset
是用于推送常量命令的偏移量。 -
pushconstantSize
是用于推送常量命令的大小。 -
indirectStateFlags
是一个 VkIndirectStateFlagsNV 位字段,指示状态标志命令的活动状态。 -
indexTypeCount
是pIndexTypes
和pIndexTypeValues
数组配对的可选大小。如果非零,则允许注册一个自定义的uint32_t
值,并将其视为特定的 VkIndexType。 -
pIndexTypes
是pIndexTypeValues
中相应uint32_t
值条目使用的 VkIndexType。
以下代码提供了关于如何处理单个序列的详细信息。 对于有效使用,所有来自常规命令的限制都适用。
void cmdProcessSequence(cmd, pipeline, indirectCommandsLayout, pIndirectCommandsStreams, s)
{
for (uint32_t t = 0; t < indirectCommandsLayout.tokenCount; t++){
token = indirectCommandsLayout.pTokens[t];
uint32_t stride = indirectCommandsLayout.pStreamStrides[token.stream];
stream = pIndirectCommandsStreams[token.stream];
uint32_t offset = stream.offset + stride * s + token.offset;
const void* input = stream.buffer.pointer( offset )
switch(input.type){
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_SHADER_GROUP_NV:
VkBindShaderGroupIndirectCommandNV* bind = input;
vkCmdBindPipelineShaderGroupNV(cmd, indirectCommandsLayout.pipelineBindPoint,
pipeline, bind->groupIndex);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_STATE_FLAGS_NV:
VkSetStateFlagsIndirectCommandNV* state = input;
if (token.indirectStateFlags & VK_INDIRECT_STATE_FLAG_FRONTFACE_BIT_NV){
if (state.data & (1 << 0)){
set VK_FRONT_FACE_CLOCKWISE;
} else {
set VK_FRONT_FACE_COUNTER_CLOCKWISE;
}
}
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV:
uint32_t* data = input;
vkCmdPushConstants(cmd,
token.pushconstantPipelineLayout
token.pushconstantStageFlags,
token.pushconstantOffset,
token.pushconstantSize, data);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NV:
VkBindIndexBufferIndirectCommandNV* data = input;
// the indexType may optionally be remapped
// from a custom uint32_t value, via
// VkIndirectCommandsLayoutTokenNV::pIndexTypeValues
vkCmdBindIndexBuffer(cmd,
deriveBuffer(data->bufferAddress),
deriveOffset(data->bufferAddress),
data->indexType);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NV:
VkBindVertexBufferIndirectCommandNV* data = input;
// if token.vertexDynamicStride is VK_TRUE
// then the stride for this binding is set
// using data->stride as well
vkCmdBindVertexBuffers(cmd,
token.vertexBindingUnit, 1,
&deriveBuffer(data->bufferAddress),
&deriveOffset(data->bufferAddress));
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NV:
vkCmdDrawIndexedIndirect(cmd,
stream.buffer, offset, 1, 0);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NV:
vkCmdDrawIndirect(cmd,
stream.buffer,
offset, 1, 0);
break;
// only available if VK_NV_mesh_shader is supported
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_TASKS_NV:
vkCmdDrawMeshTasksIndirectNV(cmd,
stream.buffer, offset, 1, 0);
break;
// only available if VK_EXT_mesh_shader is supported
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_MESH_TASKS_NV:
vkCmdDrawMeshTasksIndirectEXT(cmd,
stream.buffer, offset, 1, 0);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NV:
VkBindPipelineIndirectCommandNV *data = input;
VkPipeline computePipeline = deriveFromDeviceAddress(data->pipelineAddress);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_COMPUTE, computePipeline);
break;
case VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NV:
vkCmdDispatchIndirect(cmd, stream.buffer, offset);
break;
}
}
}
间接命令生成和执行
在设备上生成命令需要一个 preprocess
缓冲区。
使用 VK_EXT_device_generated_commands
,要检索特定执行状态的内存大小和对齐要求,请调用
// Provided by VK_EXT_device_generated_commands
void vkGetGeneratedCommandsMemoryRequirementsEXT(
VkDevice device,
const VkGeneratedCommandsMemoryRequirementsInfoEXT* pInfo,
VkMemoryRequirements2* pMemoryRequirements);
-
device
是拥有缓冲区的逻辑设备。 -
pInfo
是指向 VkGeneratedCommandsMemoryRequirementsInfoEXT 结构的指针,其中包含内存需求查询所需的参数。 -
pMemoryRequirements
是指向 VkMemoryRequirements2 结构的指针,该结构中返回缓冲区对象的内存需求。
如果返回的大小为零,则可以跳过此布局的预处理步骤。
// Provided by VK_EXT_device_generated_commands
typedef struct VkGeneratedCommandsMemoryRequirementsInfoEXT {
VkStructureType sType;
const void* pNext;
VkIndirectExecutionSetEXT indirectExecutionSet;
VkIndirectCommandsLayoutEXT indirectCommandsLayout;
uint32_t maxSequenceCount;
uint32_t maxDrawCount;
} VkGeneratedCommandsMemoryRequirementsInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
indirectExecutionSet
是用于绑定着色器的间接执行集。 -
indirectCommandsLayout
是此缓冲区内存计划使用的 VkIndirectCommandsLayoutEXT。 -
maxSequenceCount
是此缓冲区内存可使用的最大序列数。 -
maxDrawCount
是任何 COUNT 类型多重间接绘制令牌可以执行的最大间接绘制次数。对于这些令牌类型,间接缓冲区中的绘制计数将被钳制为此值。
如果布局的操作命令令牌不是 COUNT 类型多重间接绘制令牌,则 maxDrawCount
将被忽略。
// Provided by VK_EXT_device_generated_commands
typedef struct VkGeneratedCommandsPipelineInfoEXT {
VkStructureType sType;
void* pNext;
VkPipeline pipeline;
} VkGeneratedCommandsPipelineInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pipeline
是一个有效的管道对象。
// Provided by VK_EXT_device_generated_commands
typedef struct VkGeneratedCommandsShaderInfoEXT {
VkStructureType sType;
void* pNext;
uint32_t shaderCount;
const VkShaderEXT* pShaders;
} VkGeneratedCommandsShaderInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
shaderCount
是pShaders
数组的大小。 -
pShaders
是指向着色器对象数组的指针。
使用 VK_NV_device_generated_commands
,要检索特定执行状态的内存大小和对齐要求,请调用
// Provided by VK_NV_device_generated_commands
void vkGetGeneratedCommandsMemoryRequirementsNV(
VkDevice device,
const VkGeneratedCommandsMemoryRequirementsInfoNV* pInfo,
VkMemoryRequirements2* pMemoryRequirements);
-
device
是拥有缓冲区的逻辑设备。 -
pInfo
是指向 VkGeneratedCommandsMemoryRequirementsInfoNV 结构的指针,该结构包含内存需求查询所需的参数。 -
pMemoryRequirements
是指向 VkMemoryRequirements2 结构的指针,该结构中返回缓冲区对象的内存需求。
// Provided by VK_NV_device_generated_commands
typedef struct VkGeneratedCommandsMemoryRequirementsInfoNV {
VkStructureType sType;
const void* pNext;
VkPipelineBindPoint pipelineBindPoint;
VkPipeline pipeline;
VkIndirectCommandsLayoutNV indirectCommandsLayout;
uint32_t maxSequencesCount;
} VkGeneratedCommandsMemoryRequirementsInfoNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pipelineBindPoint
是 VkPipelineBindPoint,此缓冲区内存计划在执行期间与pipeline
一起使用。 -
pipeline
是 VkPipeline,此缓冲区内存计划在执行期间与此管道一起使用。 -
indirectCommandsLayout
是此缓冲区内存计划使用的 VkIndirectCommandsLayoutNV。 -
maxSequencesCount
是此缓冲区内存与其他提供的状态组合后可以使用的最大序列数。
使用 VK_NV_device_generated_commands
,要在设备生成的命令中绑定计算管线,应用程序必须查询该管线的设备地址。
要查询计算管线的 64 位设备地址,请调用
// Provided by VK_NV_device_generated_commands_compute
VkDeviceAddress vkGetPipelineIndirectDeviceAddressNV(
VkDevice device,
const VkPipelineIndirectDeviceAddressInfoNV* pInfo);
-
device
是创建管线的逻辑设备。 -
pInfo
是指向 VkPipelineIndirectDeviceAddressInfoNV 结构的指针,该结构指定要检索其地址的管线。
VkPipelineIndirectDeviceAddressInfoNV
结构的定义如下:
// Provided by VK_NV_device_generated_commands_compute
typedef struct VkPipelineIndirectDeviceAddressInfoNV {
VkStructureType sType;
const void* pNext;
VkPipelineBindPoint pipelineBindPoint;
VkPipeline pipeline;
} VkPipelineIndirectDeviceAddressInfoNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pipelineBindPoint
是一个 VkPipelineBindPoint 值,指定要查询其设备地址的管线类型。 -
pipeline
指定要查询其设备地址的管线。
要确定计算管线元数据的内存要求,请调用
// Provided by VK_NV_device_generated_commands_compute
void vkGetPipelineIndirectMemoryRequirementsNV(
VkDevice device,
const VkComputePipelineCreateInfo* pCreateInfo,
VkMemoryRequirements2* pMemoryRequirements);
-
device
是拥有缓冲区的逻辑设备。 -
pCreateInfo
是一个 VkComputePipelineCreateInfo 结构,用于指定要查询其内存要求的计算管线的创建参数。 -
pMemoryRequirements
是指向 VkMemoryRequirements2 结构的指针,其中返回所请求管线的内存要求。
如果 pCreateInfo->pNext
链包含指向 VkComputePipelineIndirectBufferInfoNV 结构的指针,则忽略该结构的内容。
间接执行集
间接执行集包含可以单独绑定的管线或着色器对象集合。
// Provided by VK_EXT_device_generated_commands
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectExecutionSetEXT)
间接执行集允许设备使用设备生成的命令绑定不同的着色器和管线状态。
间接执行集通过调用以下函数创建:
// Provided by VK_EXT_device_generated_commands
VkResult vkCreateIndirectExecutionSetEXT(
VkDevice device,
const VkIndirectExecutionSetCreateInfoEXT* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkIndirectExecutionSetEXT* pIndirectExecutionSet);
-
device
是创建间接执行集的逻辑设备。 -
pCreateInfo
是指向 VkIndirectExecutionSetCreateInfoEXT 结构的指针,该结构包含影响间接执行集创建的参数。 -
pAllocator
控制主机内存分配,如 内存分配 章节所述。 -
pIndirectExecutionSet
是指向 VkIndirectExecutionSetEXT 句柄的指针,其中返回生成的间接执行集。
VkIndirectExecutionSetCreateInfoEXT
结构定义如下:
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectExecutionSetCreateInfoEXT {
VkStructureType sType;
const void* pNext;
VkIndirectExecutionSetInfoTypeEXT type;
VkIndirectExecutionSetInfoEXT info;
} VkIndirectExecutionSetCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
type
是一个 VkIndirectExecutionSetInfoTypeEXT,描述正在创建的集合的类型,并确定将使用info
联合体的哪个字段。 -
info
是一个 VkIndirectExecutionSetInfoEXT 联合体,包含集合的布局信息。
可以在 VkIndirectExecutionSetCreateInfoEXT::type
中设置的值,指定间接执行集的内容为:
// Provided by VK_EXT_device_generated_commands
typedef enum VkIndirectExecutionSetInfoTypeEXT {
VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT = 0,
VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT = 1,
} VkIndirectExecutionSetInfoTypeEXT;
-
VK_INDIRECT_EXECUTION_SET_INFO_TYPE_PIPELINES_EXT
指定间接执行集包含 VkPipeline 对象。 -
VK_INDIRECT_EXECUTION_SET_INFO_TYPE_SHADER_OBJECTS_EXT
指定间接执行集包含 VkShaderEXT 对象。
VkIndirectExecutionSetInfoEXT
联合体定义如下:
// Provided by VK_EXT_device_generated_commands
typedef union VkIndirectExecutionSetInfoEXT {
const VkIndirectExecutionSetPipelineInfoEXT* pPipelineInfo;
const VkIndirectExecutionSetShaderInfoEXT* pShaderInfo;
} VkIndirectExecutionSetInfoEXT;
-
pPipelineInfo
是指向 VkIndirectExecutionSetPipelineInfoEXT 结构的指针,该结构包含集合的管线布局信息。 -
pShaderInfo
是指向 VkIndirectExecutionSetShaderInfoEXT 结构的指针,该结构包含集合的着色器对象布局信息。
VkIndirectExecutionSetPipelineInfoEXT
结构定义如下:
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectExecutionSetPipelineInfoEXT {
VkStructureType sType;
const void* pNext;
VkPipeline initialPipeline;
uint32_t maxPipelineCount;
} VkIndirectExecutionSetPipelineInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
initialPipeline
是该集合的初始管线。此管线将自动添加到集合的索引0
。 -
maxPipelineCount
是集合中存储的最大管线数。
即使 initialPipeline
从集合中删除或销毁,其特性也将用于验证添加到集合的所有管线。
当使用使用管线创建的间接执行集时,initialPipeline
构成初始着色器状态。
VkIndirectExecutionSetShaderInfoEXT
结构定义如下:
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectExecutionSetShaderInfoEXT {
VkStructureType sType;
const void* pNext;
uint32_t shaderCount;
const VkShaderEXT* pInitialShaders;
const VkIndirectExecutionSetShaderLayoutInfoEXT* pSetLayoutInfos;
uint32_t maxShaderCount;
uint32_t pushConstantRangeCount;
const VkPushConstantRange* pPushConstantRanges;
} VkIndirectExecutionSetShaderInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
shaderCount
是pInitialShaders
和pSetLayoutInfos
数组中的成员数量。 -
pInitialShaders
是一个指针,指向一个数组,该数组包含集合中将使用的每个着色器阶段的 VkShaderEXT 对象。这些着色器将自动添加到集合中,从索引0
开始。 -
pSetLayoutInfos
是一个指针,指向一个数组,该数组包含集合中每个对应的pInitialShaders
着色器阶段使用的 VkIndirectExecutionSetShaderLayoutInfoEXT。 -
maxShaderCount
是集合中存储的最大着色器对象数量。 -
pushConstantRangeCount
是pPushConstantRanges
数组中的成员数量。 -
pPushConstantRanges
是一个指针,指向集合中所有着色器使用的 VkPushConstantRange 范围的数组。
即使从集合中删除或销毁 pInitialShaders
,其特征也将用于验证添加到集合中的所有着色器。
当使用着色器对象创建的间接执行集时,pInitialShaders
构成初始着色器状态。
VkIndirectExecutionSetShaderLayoutInfoEXT
结构定义如下:
// Provided by VK_EXT_device_generated_commands
typedef struct VkIndirectExecutionSetShaderLayoutInfoEXT {
VkStructureType sType;
const void* pNext;
uint32_t setLayoutCount;
const VkDescriptorSetLayout* pSetLayouts;
} VkIndirectExecutionSetShaderLayoutInfoEXT;
-
setLayoutCount
是pSetLayouts
数组中的成员数量。 -
pSetLayouts
是一个指针,指向一个数组,该数组包含着色器阶段使用的 VkDescriptorSetLayout 对象。
通过调用以下函数销毁间接执行集:
// Provided by VK_EXT_device_generated_commands
void vkDestroyIndirectExecutionSetEXT(
VkDevice device,
VkIndirectExecutionSetEXT indirectExecutionSet,
const VkAllocationCallbacks* pAllocator);
-
device
是拥有间接执行集的逻辑设备。 -
indirectExecutionSet
是要销毁的间接执行集。 -
pAllocator
控制主机内存分配,如 内存分配 章节所述。
VkWriteIndirectExecutionSetPipelineEXT
结构定义如下:
// Provided by VK_EXT_device_generated_commands
typedef struct VkWriteIndirectExecutionSetPipelineEXT {
VkStructureType sType;
const void* pNext;
uint32_t index;
VkPipeline pipeline;
} VkWriteIndirectExecutionSetPipelineEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
index
是要更新的集合的元素。 -
pipeline
是要存储在间接执行集中的管线。
VkWriteIndirectExecutionSetShaderEXT
结构体定义如下:
// Provided by VK_EXT_device_generated_commands with VK_EXT_shader_object
typedef struct VkWriteIndirectExecutionSetShaderEXT {
VkStructureType sType;
const void* pNext;
uint32_t index;
VkShaderEXT shader;
} VkWriteIndirectExecutionSetShaderEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
index
是要更新的集合的元素。 -
shader
是要存储在间接执行集中的着色器。
着色器不需要按照其阶段存储在间接执行集中。对于集合内的着色器索引,唯一的限制是索引的值必须小于集合中着色器的最大数量。
可以通过调用以下方法更新间接执行集中的管线元素:
// Provided by VK_EXT_device_generated_commands
void vkUpdateIndirectExecutionSetPipelineEXT(
VkDevice device,
VkIndirectExecutionSetEXT indirectExecutionSet,
uint32_t executionSetWriteCount,
const VkWriteIndirectExecutionSetPipelineEXT* pExecutionSetWrites);
-
device
是拥有间接执行集的逻辑设备。 -
indirectExecutionSet
是正在更新的间接执行集。 -
executionSetWriteCount
是pExecutionSetWrites
数组中的元素数量。 -
pExecutionSetWrites
是指向 VkWriteIndirectExecutionSetPipelineEXT 结构体数组的指针,这些结构体描述了要更新的元素。
可以通过调用来更新间接执行集中的着色器对象元素
// Provided by VK_EXT_device_generated_commands
void vkUpdateIndirectExecutionSetShaderEXT(
VkDevice device,
VkIndirectExecutionSetEXT indirectExecutionSet,
uint32_t executionSetWriteCount,
const VkWriteIndirectExecutionSetShaderEXT* pExecutionSetWrites);
-
device
是拥有间接执行集的逻辑设备。 -
indirectExecutionSet
是正在更新的间接执行集。 -
executionSetWriteCount
是pExecutionSetWrites
数组中的元素数量。 -
pExecutionSetWrites
是指向 VkWriteIndirectExecutionSetShaderEXT 结构体数组的指针,描述要更新的元素。
更新正在使用中的间接执行集是合法的,只要 pExecutionSetWrites
中的元素索引没有被使用即可。 对间接执行集的任何更改都需要通过调用 vkGetGeneratedCommandsMemoryRequirementsEXT 重新计算使用该修改状态的命令的内存需求。 正在使用中的命令或那些不使用更新元素的命令不需要更改。
集合中包含的管线和着色器对象的生命周期必须与集合的生命周期匹配或超过集合的生命周期。
使用 VK_NV_device_generated_commands
,命令的实际生成以及它们在设备上的执行被作为单个操作处理,使用
// Provided by VK_NV_device_generated_commands
void vkCmdExecuteGeneratedCommandsNV(
VkCommandBuffer commandBuffer,
VkBool32 isPreprocessed,
const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo);
-
commandBuffer
是将命令记录到的命令缓冲区。 -
isPreprocessed
表示输入数据是否已在设备上预处理。 如果为VK_FALSE
,此命令将隐式触发预处理步骤,否则不会。 -
pGeneratedCommandsInfo
是指向 VkGeneratedCommandsInfoNV 结构的指针,该结构包含影响命令生成的参数。
如果使用 VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NV
标志来创建 VkGeneratedCommandsInfoNV::indirectCommandsLayout
,则通过此命令执行的各个绘制操作的顺序可能以任何顺序执行,并且可能不一定与 VkGeneratedCommandsInfoNV::pStreams
中指定的顺序相同。
通过此命令执行的各个分派操作的顺序可能以任何顺序执行,并且可能不一定与 VkGeneratedCommandsInfoNV::pStreams
中指定的顺序相同。
VkGeneratedCommandsInfoNV
定义如下
// Provided by VK_NV_device_generated_commands
typedef struct VkGeneratedCommandsInfoNV {
VkStructureType sType;
const void* pNext;
VkPipelineBindPoint pipelineBindPoint;
VkPipeline pipeline;
VkIndirectCommandsLayoutNV indirectCommandsLayout;
uint32_t streamCount;
const VkIndirectCommandsStreamNV* pStreams;
uint32_t sequencesCount;
VkBuffer preprocessBuffer;
VkDeviceSize preprocessOffset;
VkDeviceSize preprocessSize;
VkBuffer sequencesCountBuffer;
VkDeviceSize sequencesCountOffset;
VkBuffer sequencesIndexBuffer;
VkDeviceSize sequencesIndexOffset;
} VkGeneratedCommandsInfoNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
pipelineBindPoint
是用于pipeline
的 VkPipelineBindPoint。 -
pipeline
是在生成和执行过程中使用的 VkPipeline。 -
indirectCommandsLayout
是提供要生成的命令序列的 VkIndirectCommandsLayoutNV。 -
streamCount
定义输入流的数量 -
pStreams
是指向streamCount
个 VkIndirectCommandsStreamNV 结构数组的指针,该数组提供indirectCommandsLayout
中使用的令牌的输入数据。 -
sequencesCount
是要保留的最大序列数。如果sequencesCountBuffer
是 VK_NULL_HANDLE,则这也是生成的实际序列数。 -
preprocessBuffer
是用于预处理执行输入数据的 VkBuffer。如果此结构与 vkCmdExecuteGeneratedCommandsNV 一起使用,并且其isPreprocessed
设置为VK_TRUE
,则会跳过预处理步骤,并且此缓冲区中的数据不会被修改。此缓冲区的内容和布局对于应用程序是不透明的,并且必须不在与设备生成的命令相关的函数之外进行修改,或复制到另一个缓冲区以供重用。 -
preprocessOffset
是存储预处理数据的preprocessBuffer
中的字节偏移量。 -
preprocessSize
是preprocessOffset
之后preprocessBuffer
中可用于预处理的最大字节大小。 -
sequencesCountBuffer
是一个VkBuffer
,其中实际序列数作为单个uint32_t
值提供。 -
sequencesCountOffset
是sequencesCountBuffer
中存储计数值的字节偏移量。 -
sequencesIndexBuffer
是一个VkBuffer
,它将使用的序列索引编码为uint32_t
数组。 -
sequencesIndexOffset
是sequencesIndexBuffer
中索引值开始处的字节偏移量。
参考间接命令布局中定义的函数,vkCmdExecuteGeneratedCommandsNV
的行为如下:
uint32_t sequencesCount = sequencesCountBuffer ?
min(maxSequencesCount, sequencesCountBuffer.load_uint32(sequencesCountOffset) :
maxSequencesCount;
cmdProcessAllSequences(commandBuffer, pipeline,
indirectCommandsLayout, pIndirectCommandsStreams,
sequencesCount,
sequencesIndexBuffer, sequencesIndexOffset);
// The stateful commands within indirectCommandsLayout will not
// affect the state of subsequent commands in the target
// command buffer (cmd)
请务必注意,此命令之后,与所使用的 |
可以使用以下命令在执行之前预处理命令
// Provided by VK_NV_device_generated_commands
void vkCmdPreprocessGeneratedCommandsNV(
VkCommandBuffer commandBuffer,
const VkGeneratedCommandsInfoNV* pGeneratedCommandsInfo);
-
commandBuffer
是执行预处理的命令缓冲区。 -
pGeneratedCommandsInfo
是一个指向 VkGeneratedCommandsInfoNV 结构的指针,该结构包含影响预处理步骤的参数。
在通过 vkCmdPreprocessGeneratedCommandsNV 预处理命令时,用于计算管线的间接命令生成的已绑定描述符集和推送常量必须已指定。它们必须在通过 vkCmdExecuteGeneratedCommandsNV 提交间接命令执行之前保持不变。
如果计算管线的推送常量也在 VkGeneratedCommandsInfoNV::indirectCommandsLayout
中使用 VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NV
标记指定,则这些值将覆盖先前为计算管线推送的推送常量。
使用 VK_EXT_device_generated_commands
,命令的实际生成及其在设备上的执行被视为一个单一的操作,使用
// Provided by VK_EXT_device_generated_commands
void vkCmdExecuteGeneratedCommandsEXT(
VkCommandBuffer commandBuffer,
VkBool32 isPreprocessed,
const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo);
-
commandBuffer
是将命令记录到的命令缓冲区。 -
isPreprocessed
表示输入数据是否已在设备上预处理。 如果为VK_FALSE
,此命令将隐式触发预处理步骤,否则不会。 -
pGeneratedCommandsInfo
是一个指向 VkGeneratedCommandsInfoEXT 结构的指针,该结构包含影响命令生成的参数。
如果使用 VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_EXT
标志创建 VkGeneratedCommandsInfoEXT::indirectCommandsLayout
,那么通过此命令执行序列可能会使用实现定义的排序,该排序不能保证在使用相同输入数据时是一致的。这不会影响序列中标记处理的顺序。这是使用 VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_EXT
的隐含排序。
在调用 vkCmdExecuteGeneratedCommandsEXT
之后,命令缓冲区状态将根据执行的标记变为未定义。下表指定了所使用的标记与状态失效之间的关系。
通用令牌 | 失效的状态 |
---|---|
|
绑定的着色器和管线 |
|
推送常量数据 |
|
推送常量数据 |
|
索引缓冲区 |
|
顶点缓冲区 |
VkGeneratedCommandsInfoEXT
定义为:
// Provided by VK_EXT_device_generated_commands
typedef struct VkGeneratedCommandsInfoEXT {
VkStructureType sType;
const void* pNext;
VkShaderStageFlags shaderStages;
VkIndirectExecutionSetEXT indirectExecutionSet;
VkIndirectCommandsLayoutEXT indirectCommandsLayout;
VkDeviceAddress indirectAddress;
VkDeviceSize indirectAddressSize;
VkDeviceAddress preprocessAddress;
VkDeviceSize preprocessSize;
uint32_t maxSequenceCount;
VkDeviceAddress sequenceCountAddress;
uint32_t maxDrawCount;
} VkGeneratedCommandsInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
shaderStages
是命令使用的着色器阶段的掩码。 -
indirectExecutionSet
是用于绑定着色器的间接执行集。 -
indirectCommandsLayout
是指定命令序列数据的 VkIndirectCommandsLayoutEXT。 -
indirectAddress
是保存间接缓冲区数据的地址。 -
indirectAddressSize
是从indirectAddress
开始的间接缓冲区数据的大小(以字节为单位)。 -
preprocessAddress
指定用于预处理执行的输入数据的VkBuffer
的物理地址。如果此结构与 vkCmdExecuteGeneratedCommandsEXT 一起使用,并且其isPreprocessed
设置为VK_TRUE
,则会跳过预处理步骤,但此地址中的数据可能仍然会被修改。此地址的内容和布局对应用程序是不透明的,并且必须不在与设备生成的命令相关的函数之外进行修改,也不得复制到另一个缓冲区以供重用。 -
preprocessSize
是preprocessAddress
中可用于预处理的最大字节大小。 -
maxSequenceCount
用于确定要执行的序列数。 -
sequenceCountAddress
指定一个可选的uint32_t
值的物理地址,该值包含请求的要执行的序列数。 -
maxDrawCount
是任何 COUNT 类型多重间接绘制令牌可以执行的最大间接绘制次数。对于这些令牌类型,间接缓冲区中的绘制计数将被钳制为此值。
如果 sequenceCountAddress
不为 NULL
,则 maxSequenceCount
是可以执行的最大序列数。实际数字为 min(maxSequenceCount, *sequenceCountAddress)
。如果 sequenceCountAddress
为 NULL
,则 maxSequenceCount
是要执行的确切序列数。
如果布局的操作命令令牌不是 COUNT 类型多重间接绘制令牌,则 maxDrawCount
将被忽略。
参考间接命令布局中定义的函数,vkCmdExecuteGeneratedCommandsEXT
的行为如下:
uint32_t sequencesCount = sequenceCountAddress ?
min(maxSequenceCount, sequenceCountAddress.load_uint32()) :
maxSequenceCount;
cmdProcessAllSequences(commandBuffer, indirectExecutionSet,
indirectCommandsLayout, indirectAddress,
sequencesCount);
// The stateful commands within indirectCommandsLayout will not
// affect the state of subsequent commands in the target
// command buffer (cmd)
注意
需要注意的是,所有与使用的 |
可以使用以下命令在执行之前预处理命令
// Provided by VK_EXT_device_generated_commands
void vkCmdPreprocessGeneratedCommandsEXT(
VkCommandBuffer commandBuffer,
const VkGeneratedCommandsInfoEXT* pGeneratedCommandsInfo,
VkCommandBuffer stateCommandBuffer);
-
commandBuffer
是执行预处理的命令缓冲区。 -
pGeneratedCommandsInfo
是指向包含影响预处理步骤的参数的 VkGeneratedCommandsInfoEXT 结构的指针。 -
stateCommandBuffer
是一个命令缓冲区,用于从中快照影响预处理步骤的当前状态。当使用图形命令动作令牌时,将快照图形状态。当使用计算动作命令令牌时,将快照计算状态。当使用光线追踪动作命令令牌时,将快照光线追踪状态。此命令记录后,可以随时将其删除。
注意
驱动程序不会同步 |
在 vkCmdPreprocessGeneratedCommandsEXT 预处理命令时,用于间接命令生成绑定的描述符集和推送常量必须已在 stateCommandBuffer
上指定。它们必须与通过 vkCmdExecuteGeneratedCommandsEXT 执行间接命令时使用的绑定描述符集和推送常量匹配。
如果着色器阶段的推送常量也在 VkGeneratedCommandsInfoEXT::indirectCommandsLayout
中使用 VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_EXT
或 VK_INDIRECT_COMMANDS_TOKEN_TYPE_SEQUENCE_INDEX_EXT
令牌指定,那么这些值将覆盖先前推送的推送常量。
将使用在 stateCommandBuffer
上绑定的所有状态。在 stateCommandBuffer
上绑定的所有状态必须与记录 vkCmdExecuteGeneratedCommandsEXT 时绑定的状态相同。stateCommandBuffer
分配的队列族索引必须与 vkCmdExecuteGeneratedCommandsEXT 中使用的命令缓冲区的队列族索引相同。
在某些实现中,预处理可能不会对性能产生影响。
vkCmdExecuteGeneratedCommandsEXT 可能会写入预处理缓冲区,无论 isPreprocess 参数如何。在这种情况下,实现必须自动插入适当的同步,这对应于以下伪代码
-
屏障
-
srcStageMask = DRAW_INDIRECT
-
srcAccesMask = 0
-
dstStageMask = COMMAND_PREPROCESS_BIT
-
dstAccessMask = COMMAND_PREPROCESS_WRITE_BIT | COMMAND_PREPROCESS_READ_BIT
-
-
执行内部写入
-
屏障
-
srcStageMask = COMMAND_PREPROCESS_BIT
-
srcAccesMask = COMMAND_PREPROCESS_WRITE_BIT
-
dstStageMask = DRAW_INDIRECT
-
dstAccessMask = INDIRECT_COMMAND_READ_BIT
-
-
执行