30. Device-Generated Commands
This chapter discusses the generation of command buffer content on the device. These principle steps are to be taken to generate commands on the device:
-
Make resource bindings accessible for the device via registering in a
VkObjectTableNVX. -
Define via
VkIndirectCommandsLayoutNVXthe sequence of commands which should be generated. -
Fill one or more
VkBufferwith the appropriate content that gets interpreted byVkIndirectCommandsLayoutNVX. -
Reserve command space via vkCmdReserveSpaceForCommandsNVX in a secondary
VkCommandBufferwhere the generated commands should be recorded. -
Generate the actual commands via vkCmdProcessCommandsNVX passing all required data.
Execution of such generated commands can either be triggered directly with
the generation process, or by executing the secondary VkCommandBuffer
that was chosen as optional target.
The latter allows re-using generated commands as well.
Similar to VkDescriptorSet, special care should be taken for the
lifetime of resources referenced in VkObjectTableNVX, which may be
accessed at either generation or execution time.
vkCmdProcessCommandsNVX executes in a separate logical pipeline from either graphics or compute. When generating commands into a secondary command buffer, the command generation must be explicitly synchronized against the secondary command buffer’s execution. When not using a secondary command buffer, the command generation is automatically synchronized against the command execution.
30.1. Features and Limitations
To query the support of related features and limitations, call:
void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
VkPhysicalDevice physicalDevice,
VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
VkDeviceGeneratedCommandsLimitsNVX* pLimits);
-
physicalDeviceis the handle to the physical device whose properties will be queried. -
pFeaturespoints to an instance of the VkDeviceGeneratedCommandsFeaturesNVX structure, that will be filled with returned information. -
pLimitspoints to an instance of the VkDeviceGeneratedCommandsLimitsNVX structure, that will be filled with returned information.
The VkDeviceGeneratedCommandsFeaturesNVX structure is defined as:
typedef struct VkDeviceGeneratedCommandsFeaturesNVX {
VkStructureType sType;
const void* pNext;
VkBool32 computeBindingPointSupport;
} VkDeviceGeneratedCommandsFeaturesNVX;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
computeBindingPointSupportspecifies whether theVkObjectTableNVXsupports entries withVK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVXbit set andVkIndirectCommandsLayoutNVXsupportsVK_PIPELINE_BIND_POINT_COMPUTE.
The VkDeviceGeneratedCommandsLimitsNVX structure is defined as:
typedef struct VkDeviceGeneratedCommandsLimitsNVX {
VkStructureType sType;
const void* pNext;
uint32_t maxIndirectCommandsLayoutTokenCount;
uint32_t maxObjectEntryCounts;
uint32_t minSequenceCountBufferOffsetAlignment;
uint32_t minSequenceIndexBufferOffsetAlignment;
uint32_t minCommandsTokenBufferOffsetAlignment;
} VkDeviceGeneratedCommandsLimitsNVX;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
maxIndirectCommandsLayoutTokenCountthe maximum number of tokens inVkIndirectCommandsLayoutNVX. -
maxObjectEntryCountsthe maximum number of entries per resource type inVkObjectTableNVX. -
minSequenceCountBufferOffsetAlignmentthe minimum alignment for memory addresses optionally used invkCmdProcessCommandsNVX. -
minSequenceIndexBufferOffsetAlignmentthe minimum alignment for memory addresses optionally used invkCmdProcessCommandsNVX. -
minCommandsTokenBufferOffsetAlignmentthe minimum alignment for memory addresses optionally used invkCmdProcessCommandsNVX.
30.2. Binding Object Table
The device-side bindings are registered inside a table:
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkObjectTableNVX)
This is required as the CPU-side object pointers, for example when binding a
VkPipeline or VkDescriptorSet, cannot be used by the device.
The combination of VkObjectTableNVX and uint32_t table indices
stored inside a VkBuffer serve that purpose during device command
generation.
At creation time the table is defined with a fixed amount of registration
slots for the individual resource types.
A detailed resource binding can then later be registered via
vkRegisterObjectsNVX at any uint32_t index below the allocated
maximum.
30.2.1. Table Creation
To create object tables, call:
VkResult vkCreateObjectTableNVX(
VkDevice device,
const VkObjectTableCreateInfoNVX* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkObjectTableNVX* pObjectTable);
-
deviceis the logical device that creates the object table. -
pCreateInfois a pointer to an instance of theVkObjectTableCreateInfoNVXstructure containing parameters affecting creation of the table. -
pAllocatorcontrols host memory allocation as described in the Memory Allocation chapter. -
pObjectTablepoints to a VkObjectTableNVX handle in which the resulting object table is returned.
The VkObjectTableCreateInfoNVX structure is defined as:
typedef struct VkObjectTableCreateInfoNVX {
VkStructureType sType;
const void* pNext;
uint32_t objectCount;
const VkObjectEntryTypeNVX* pObjectEntryTypes;
const uint32_t* pObjectEntryCounts;
const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags;
uint32_t maxUniformBuffersPerDescriptor;
uint32_t maxStorageBuffersPerDescriptor;
uint32_t maxStorageImagesPerDescriptor;
uint32_t maxSampledImagesPerDescriptor;
uint32_t maxPipelineLayouts;
} VkObjectTableCreateInfoNVX;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
objectCountis the number of entry configurations that the object table supports. -
pObjectEntryTypesis an array of VkObjectEntryTypeNVX values providing the entry type of a given configuration. -
pObjectEntryCountsis an array of counts of how many objects can be registered in the table. -
pObjectEntryUsageFlagsis an array of bitmasks of VkObjectEntryUsageFlagBitsNVX specifying the binding usage of the entry. -
maxUniformBuffersPerDescriptoris the maximum number ofVK_DESCRIPTOR_TYPE_UNIFORM_BUFFERorVK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMICused by any single registeredVkDescriptorSetin this table. -
maxStorageBuffersPerDescriptoris the maximum number ofVK_DESCRIPTOR_TYPE_STORAGE_BUFFERorVK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMICused by any single registeredVkDescriptorSetin this table. -
maxStorageImagesPerDescriptoris the maximum number ofVK_DESCRIPTOR_TYPE_STORAGE_IMAGEorVK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFERused by any single registeredVkDescriptorSetin this table. -
maxSampledImagesPerDescriptoris the maximum number ofVK_DESCRIPTOR_TYPE_SAMPLER,VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFERorVK_DESCRIPTOR_TYPE_INPUT_ATTACHMENTused by any single registeredVkDescriptorSetin this table. -
maxPipelineLayoutsis the maximum number of uniqueVkPipelineLayoutused by any registeredVkDescriptorSetorVkPipelinein this table.
Possible values of elements of the
VkObjectTableCreateInfoNVX::pObjectEntryTypes array, specifying
the entry type of a configuration, are:
typedef enum VkObjectEntryTypeNVX {
VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0,
VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1,
VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2,
VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3,
VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4,
VK_OBJECT_ENTRY_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
} VkObjectEntryTypeNVX;
-
VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVXspecifies aVkDescriptorSetresource entry that is registered viaVkObjectTableDescriptorSetEntryNVX. -
VK_OBJECT_ENTRY_TYPE_PIPELINE_NVXspecifies aVkPipelineresource entry that is registered viaVkObjectTablePipelineEntryNVX. -
VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVXspecifies aVkBufferresource entry that is registered viaVkObjectTableIndexBufferEntryNVX. -
VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVXspecifies aVkBufferresource entry that is registered viaVkObjectTableVertexBufferEntryNVX. -
VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVXspecifies the resource entry is registered viaVkObjectTablePushConstantEntryNVX.
Bits which can be set in elements of the
VkObjectTableCreateInfoNVX::pObjectEntryUsageFlags array,
specifying binding usage of an entry, are:
typedef enum VkObjectEntryUsageFlagBitsNVX {
VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
VK_OBJECT_ENTRY_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
} VkObjectEntryUsageFlagBitsNVX;
-
VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVXspecifies that the resource is bound toVK_PIPELINE_BIND_POINT_GRAPHICS -
VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVXspecifies that the resource is bound toVK_PIPELINE_BIND_POINT_COMPUTE
typedef VkFlags VkObjectEntryUsageFlagsNVX;
VkObjectEntryUsageFlagsNVX is a bitmask type for setting a mask of
zero or more VkObjectEntryUsageFlagBitsNVX.
To destroy an object table, call:
void vkDestroyObjectTableNVX(
VkDevice device,
VkObjectTableNVX objectTable,
const VkAllocationCallbacks* pAllocator);
-
deviceis the logical device that destroys the table. -
objectTableis the table to destroy. -
pAllocatorcontrols host memory allocation as described in the Memory Allocation chapter.
30.2.2. Registering Objects
Resource bindings of Vulkan objects are registered at an arbitrary
uint32_t index within an object table.
As long as the object table references such objects, they must not be
deleted.
VkResult vkRegisterObjectsNVX(
VkDevice device,
VkObjectTableNVX objectTable,
uint32_t objectCount,
const VkObjectTableEntryNVX* const* ppObjectTableEntries,
const uint32_t* pObjectIndices);
-
deviceis the logical device that creates the object table. -
objectTableis the table for which the resources are registered. -
objectCountis the number of resources to register. -
ppObjectTableEntriesprovides an array for detailed binding informations, each array element is a pointer to a struct of typeVkObjectTablePipelineEntryNVX,VkObjectTableDescriptorSetEntryNVX,VkObjectTableVertexBufferEntryNVX,VkObjectTableIndexBufferEntryNVXorVkObjectTablePushConstantEntryNVX(see below for details). -
pObjectIndicesare the indices at which each resource is registered.
Common to all resource entries are:
typedef struct VkObjectTableEntryNVX {
VkObjectEntryTypeNVX type;
VkObjectEntryUsageFlagsNVX flags;
} VkObjectTableEntryNVX;
-
typedefines the entry type -
flagsdefines which VkPipelineBindPoint the resource can be used with. Some entry types allow only a single flag to be set.
typedef struct VkObjectTablePipelineEntryNVX {
VkObjectEntryTypeNVX type;
VkObjectEntryUsageFlagsNVX flags;
VkPipeline pipeline;
} VkObjectTablePipelineEntryNVX;
-
pipelinespecifies the VkPipeline that this resource entry references.
typedef struct VkObjectTableDescriptorSetEntryNVX {
VkObjectEntryTypeNVX type;
VkObjectEntryUsageFlagsNVX flags;
VkPipelineLayout pipelineLayout;
VkDescriptorSet descriptorSet;
} VkObjectTableDescriptorSetEntryNVX;
-
pipelineLayoutspecifies the VkPipelineLayout that thedescriptorSetis used with. -
descriptorSetspecifies the VkDescriptorSet that can be bound with this entry.
typedef struct VkObjectTableVertexBufferEntryNVX {
VkObjectEntryTypeNVX type;
VkObjectEntryUsageFlagsNVX flags;
VkBuffer buffer;
} VkObjectTableVertexBufferEntryNVX;
-
bufferspecifies the VkBuffer that can be bound as vertex bufer
typedef struct VkObjectTableIndexBufferEntryNVX {
VkObjectEntryTypeNVX type;
VkObjectEntryUsageFlagsNVX flags;
VkBuffer buffer;
VkIndexType indexType;
} VkObjectTableIndexBufferEntryNVX;
-
bufferspecifies the VkBuffer that can be bound as index buffer -
indexTypespecifies the VkIndexType used with this index buffer
typedef struct VkObjectTablePushConstantEntryNVX {
VkObjectEntryTypeNVX type;
VkObjectEntryUsageFlagsNVX flags;
VkPipelineLayout pipelineLayout;
VkShaderStageFlags stageFlags;
} VkObjectTablePushConstantEntryNVX;
-
pipelineLayoutspecifies the VkPipelineLayout that the pushconstants are used with -
stageFlagsspecifies the VkShaderStageFlags that the pushconstants are used with
Use the following command to unregister resources from an object table:
VkResult vkUnregisterObjectsNVX(
VkDevice device,
VkObjectTableNVX objectTable,
uint32_t objectCount,
const VkObjectEntryTypeNVX* pObjectEntryTypes,
const uint32_t* pObjectIndices);
-
deviceis the logical device that creates the object table. -
objectTableis the table from which the resources are unregistered. -
objectCountis the number of resources being removed from the object table. -
pObjectEntryTypeprovides an array of VkObjectEntryTypeNVX for the resources being removed. -
pObjectIndicesprovides the array of object indices to be removed.
30.3. Indirect Commands Layout
The device-side command generation happens through an iterative processing of an atomic sequence comprised of command tokens, which are represented by:
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkIndirectCommandsLayoutNVX)
30.3.1. Tokenized Command Processing
The processing is in principle illustrated below:
void cmdProcessSequence(cmd, objectTable, indirectCommandsLayout, pIndirectCommandsTokens, s)
{
for (c = 0; c < indirectCommandsLayout.tokenCount; c++)
{
indirectCommandsLayout.pTokens[c].command (cmd, objectTable, pIndirectCommandsTokens[c], s);
}
}
void cmdProcessAllSequences(cmd, objectTable, indirectCommandsLayout, pIndirectCommandsTokens, sequencesCount)
{
for (s = 0; s < sequencesCount; s++)
{
cmdProcessSequence(cmd, objectTable, indirectCommandsLayout, pIndirectCommandsTokens, s);
}
}
The processing of each sequence is considered stateless, therefore all state
changes must occur prior work provoking commands within the sequence.
A single sequence is either strictly targeting
VK_PIPELINE_BIND_POINT_GRAPHICS or
VK_PIPELINE_BIND_POINT_COMPUTE.
The primary input data for each token is provided through VkBuffer
content at command generation time using vkCmdProcessCommandsNVX,
however some functional arguments, for example binding sets, are specified
at layout creation time.
The input size is different for each token.
Possible values of those elements of the
VkIndirectCommandsLayoutCreateInfoNVX::pTokens array which
specify command tokens (other elements of the array specify command
parameters) are:
typedef enum VkIndirectCommandsTokenTypeNVX {
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7,
VK_INDIRECT_COMMANDS_TOKEN_TYPE_MAX_ENUM_NVX = 0x7FFFFFFF
} VkIndirectCommandsTokenTypeNVX;
| Token type | Equivalent command |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The VkIndirectCommandsLayoutTokenNVX structure specifies details to
the function arguments that need to be known at layout creation time:
typedef struct VkIndirectCommandsLayoutTokenNVX {
VkIndirectCommandsTokenTypeNVX tokenType;
uint32_t bindingUnit;
uint32_t dynamicCount;
uint32_t divisor;
} VkIndirectCommandsLayoutTokenNVX;
-
typespecifies the token command type. -
bindingUnithas a different meaning depending on the type, please refer pseudo code further down for details. -
dynamicCounthas a different meaning depending on the type, please refer pseudo code further down for details. -
divisordefines the rate at which the input data buffers are accessed.
The VkIndirectCommandsTokenNVX structure specifies the input data for
a token at processing time.
typedef struct VkIndirectCommandsTokenNVX {
VkIndirectCommandsTokenTypeNVX tokenType;
VkBuffer buffer;
VkDeviceSize offset;
} VkIndirectCommandsTokenNVX;
-
tokenTypespecifies the token command type. -
bufferspecifies the VkBuffer storing the functional arguments for each squence. These argumetns can be written by the device. -
offsetspecified an offset intobufferwhere the arguments start.
The following code provides detailed information on how an individual sequence is processed:
void cmdProcessSequence(cmd, objectTable, indirectCommandsLayout, pIndirectCommandsTokens, s)
{
for (uint32_t c = 0; c < indirectCommandsLayout.tokenCount; c++){
input = pIndirectCommandsTokens[c];
i = s / indirectCommandsLayout.pTokens[c].divisor;
switch(input.type){
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX:
size_t stride = sizeof(uint32_t);
uint32_t* data = input.buffer.pointer( input.offset + stride * i );
uint32_t object = data[0];
vkCmdBindPipeline(cmd, indirectCommandsLayout.pipelineBindPoint,
objectTable.pipelines[ object ].pipeline);
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX:
size_t stride = sizeof(uint32_t) + sizeof(uint32_t) * indirectCommandsLayout.pTokens[c].dynamicCount;
uint32_t* data = input.buffer.pointer( input.offset + stride * i);
uint32_t object = data[0];
vkCmdBindDescriptorSets(cmd, indirectCommandsLayout.pipelineBindPoint,
objectTable.descriptorsets[ object ].layout,
indirectCommandsLayout.pTokens[ c ].bindingUnit,
1, &objectTable.descriptorsets[ object ].descriptorSet,
indirectCommandsLayout.pTokens[ c ].dynamicCount, data + 1);
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX:
size_t stride = sizeof(uint32_t) + indirectCommandsLayout.pTokens[c].dynamicCount;
uint32_t* data = input.buffer.pointer( input.offset + stride * i );
uint32_t object = data[0];
vkCmdPushConstants(cmd,
objectTable.pushconstants[ object ].layout,
objectTable.pushconstants[ object ].stageFlags,
indirectCommandsLayout.pTokens[ c ].bindingUnit, indirectCommandsLayout.pTokens[c].dynamicCount, data + 1);
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX:
size_t s tride = sizeof(uint32_t) + sizeof(uint32_t) * indirectCommandsLayout.pTokens[c].dynamicCount;
uint32_t* data = input.buffer.pointer( input.offset + stride * i );
uint32_t object = data[0];
vkCmdBindIndexBuffer(cmd,
objectTable.vertexbuffers[ object ].buffer,
indirectCommandsLayout.pTokens[ c ].dynamicCount ? data[1] : 0,
objectTable.vertexbuffers[ object ].indexType);
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX:
size_t stride = sizeof(uint32_t) + sizeof(uint32_t) * indirectCommandsLayout.pTokens[c].dynamicCount;
uint32_t* data = input.buffer.pointer( input.offset + stride * i );
uint32_t object = data[0];
vkCmdBindVertexBuffers(cmd,
indirectCommandsLayout.pTokens[ c ].bindingUnit, 1,
&objectTable.vertexbuffers[ object ].buffer,
indirectCommandsLayout.pTokens[ c ].dynamicCount ? data + 1 : {0}); // device size handled as uint32_t
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX:
vkCmdDrawIndexedIndirect(cmd,
input.buffer,
sizeof(VkDrawIndexedIndirectCommand) * i + input.offset, 1, 0);
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX:
vkCmdDrawIndirect(cmd,
input.buffer,
sizeof(VkDrawIndirectCommand) * i + input.offset, 1, 0);
break;
VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX:
vkCmdDispatchIndirect(cmd,
input.buffer,
sizeof(VkDispatchIndirectCommand) * i + input.offset);
break;
}
}
}
30.3.2. Creation and Deletion
Indirect command layouts are created by:
VkResult vkCreateIndirectCommandsLayoutNVX(
VkDevice device,
const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout);
-
deviceis the logical device that creates the indirect command layout. -
pCreateInfois a pointer to an instance of theVkIndirectCommandsLayoutCreateInfoNVXstructure containing parameters affecting creation of the indirect command layout. -
pAllocatorcontrols host memory allocation as described in the Memory Allocation chapter. -
pIndirectCommandsLayoutpoints to aVkIndirectCommandsLayoutNVXhandle in which the resulting indirect command layout is returned.
The VkIndirectCommandsLayoutCreateInfoNVX structure is defined as:
typedef struct VkIndirectCommandsLayoutCreateInfoNVX {
VkStructureType sType;
const void* pNext;
VkPipelineBindPoint pipelineBindPoint;
VkIndirectCommandsLayoutUsageFlagsNVX flags;
uint32_t tokenCount;
const VkIndirectCommandsLayoutTokenNVX* pTokens;
} VkIndirectCommandsLayoutCreateInfoNVX;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
pipelineBindPointis the VkPipelineBindPoint that this layout targets. -
flagsis a bitmask of VkIndirectCommandsLayoutUsageFlagBitsNVX specifying usage hints of this layout. -
tokenCountis the length of the individual command sequnce. -
pTokensis an array describing each command token in detail. See VkIndirectCommandsTokenTypeNVX and VkIndirectCommandsLayoutTokenNVX below for details.
The following code illustrates some of the key flags:
void cmdProcessAllSequences(cmd, objectTable, indirectCommandsLayout, pIndirectCommandsTokens, sequencesCount, indexbuffer, indexbufferoffset)
{
for (s = 0; s < sequencesCount; s++)
{
sequence = s;
if (indirectCommandsLayout.flags & VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX) {
sequence = incoherent_implementation_dependent_permutation[ sequence ];
}
if (indirectCommandsLayout.flags & VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX) {
sequence = indexbuffer.load_uint32( sequence * sizeof(uint32_t) + indexbufferoffset);
}
cmdProcessSequence( cmd, objectTable, indirectCommandsLayout, pIndirectCommandsTokens, sequence );
}
}
Bits which can be set in
VkIndirectCommandsLayoutCreateInfoNVX::flags, specifying usage
hints of an indirect command layout, are:
typedef enum VkIndirectCommandsLayoutUsageFlagBitsNVX {
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_FLAG_BITS_MAX_ENUM_NVX = 0x7FFFFFFF
} VkIndirectCommandsLayoutUsageFlagBitsNVX;
-
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVXspecifies that the processing of sequences can happen at an implementation-dependent order, which is not guaranteed to be coherent across multiple invocations. -
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVXspecifies that there is likely a high difference between allocated number of sequences and actually used. -
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVXspecifies that there are likely many draw or dispatch calls that are zero-sized (zero grid dimension, no primitives to render). -
VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVXspecifies that the input data for the sequences is not implicitly indexed from 0..sequencesUsed but a user providedVkBufferencoding the index is provided.
typedef VkFlags VkIndirectCommandsLayoutUsageFlagsNVX;
VkIndirectCommandsLayoutUsageFlagsNVX is a bitmask type for setting a
mask of zero or more VkIndirectCommandsLayoutUsageFlagBitsNVX.
Indirect command layouts are destroyed by:
void vkDestroyIndirectCommandsLayoutNVX(
VkDevice device,
VkIndirectCommandsLayoutNVX indirectCommandsLayout,
const VkAllocationCallbacks* pAllocator);
-
deviceis the logical device that destroys the layout. -
indirectCommandsLayoutis the table to destroy. -
pAllocatorcontrols host memory allocation as described in the Memory Allocation chapter.
30.4. Indirect Commands Generation
Command space for generated commands recorded into a secondary command buffer must be reserved by calling:
void vkCmdReserveSpaceForCommandsNVX(
VkCommandBuffer commandBuffer,
const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo);
-
commandBufferis the secondary command buffer in which the space for device-generated commands is reserved. -
pProcessCommandsInfois a pointer to an instance of the VkCmdReserveSpaceForCommandsInfoNVX structure containing parameters affecting the reservation of command buffer space.
typedef struct VkCmdReserveSpaceForCommandsInfoNVX {
VkStructureType sType;
const void* pNext;
VkObjectTableNVX objectTable;
VkIndirectCommandsLayoutNVX indirectCommandsLayout;
uint32_t maxSequencesCount;
} VkCmdReserveSpaceForCommandsInfoNVX;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
objectTableis the VkObjectTableNVX to be used for the generation process. Only registered objects at the time vkCmdReserveSpaceForCommandsNVX is called, will be taken into account for the reservation. -
indirectCommandsLayoutis the VkIndirectCommandsLayoutNVX that must also be used at generation time. -
maxSequencesCountis the maximum number of sequences for which command buffer space will be reserved.
The generated commands will behave as if they were recorded within the call
to vkCmdReserveSpaceForCommandsNVX, that means they can inherit state
defined in the command buffer prior this call.
However, given the stateless nature of the generated sequences, they will
not affect commands after the reserved space.
Treat the state that can be affected by the provided
VkIndirectCommandsLayoutNVX as undefined.
The actual generation on the device is handled with:
void vkCmdProcessCommandsNVX(
VkCommandBuffer commandBuffer,
const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo);
-
commandBufferis the primary command buffer in which the generation process takes space. -
pProcessCommandsInfois a pointer to an instance of the VkCmdProcessCommandsInfoNVX structure containing parameters affecting the processing of commands.
typedef struct VkCmdProcessCommandsInfoNVX {
VkStructureType sType;
const void* pNext;
VkObjectTableNVX objectTable;
VkIndirectCommandsLayoutNVX indirectCommandsLayout;
uint32_t indirectCommandsTokenCount;
const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens;
uint32_t maxSequencesCount;
VkCommandBuffer targetCommandBuffer;
VkBuffer sequencesCountBuffer;
VkDeviceSize sequencesCountOffset;
VkBuffer sequencesIndexBuffer;
VkDeviceSize sequencesIndexOffset;
} VkCmdProcessCommandsInfoNVX;
-
sTypeis the type of this structure. -
pNextisNULLor a pointer to an extension-specific structure. -
objectTableis the VkObjectTableNVX to be used for the generation process. Only registered objects at the time vkCmdReserveSpaceForCommandsNVX is called, will be taken into account for the reservation. -
indirectCommandsLayoutis the VkIndirectCommandsLayoutNVX that provides the command sequence to generate. -
indirectCommandsTokenCountdefines the number of input tokens used. -
pIndirectCommandsTokensprovides an array of VkIndirectCommandsTokenNVX that reference the input data for each token command. -
maxSequencesCountis the maximum number of sequences for which command buffer space will be reserved. IfsequencesCountBufferis VK_NULL_HANDLE, this is also the actual number of sequences generated. -
targetCommandBuffercan be the secondary VkCommandBuffer in which the commands should be recorded. IftargetCommandBufferisNULLan implicit reservation as well as execution takes place on the processingVkCommandBuffer. -
sequencesCountBuffercan be VkBuffer from which the actual amount of sequences is sourced from asuint32_tvalue. -
sequencesCountOffsetis the byte offset intosequencesCountBufferwhere the count value is stored. -
sequencesIndexBuffermust be set ifindirectCommandsLayout’sVK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVXis set and provides the used sequence indices asuint32_tarray. Otherwise it must be VK_NULL_HANDLE. -
sequencesIndexOffsetis the byte offset intosequencesIndexBufferwhere the index values start.
Referencing the functions defined in Indirect Commands Layout,
vkCmdProcessCommandsNVX behaves as:
// For targetCommandBuffers the existing reservedSpace is reset & overwritten.
VkCommandBuffer cmd = targetCommandBuffer ?
targetCommandBuffer.reservedSpace :
commandBuffer;
uint32_t sequencesCount = sequencesCountBuffer ?
min(maxSequencesCount, sequencesCountBuffer.load_uint32(sequencesCountOffset) :
maxSequencesCount;
cmdProcessAllSequences(cmd, objectTable,
indirectCommandsLayout, pIndirectCommandsTokens,
sequencesCount,
sequencesIndexBuffer, sequencesIndexOffset);
// The stateful commands within indirectCommandsLayout will not
// affect the state of subsequent commands in the target
// command buffer (cmd)
|
Note
It is important to note that the state that may be affected through generated commands must be considered undefined for the commands following them. It is not possible to setup generated state and provoking work that uses this state outside of the generated sequence. |