The operation of queries is controlled by the commands
vkCmdBeginQuery, vkCmdEndQuery, vkCmdResetQueryPool,
vkCmdCopyQueryPoolResults, and vkCmdWriteTimestamp.
In order for a VkCommandBuffer to record query management commands,
the queue family for which its VkCommandPool was created must support
the appropriate type of operations (graphics, compute) suitable for the
query type of a given query pool.
Each query in a query pool has a status that is either unavailable or
available, and also has state to store the numerical results of a query
operation of the type requested when the query pool was created.
Resetting a query via vkCmdResetQueryPool sets the status to
unavailable and makes the numerical results undefined.
Performing a query operation with vkCmdBeginQuery and
vkCmdEndQuery changes the status to available when the query
finishes, and updates the numerical results.
Both the availability status and numerical results are retrieved by calling
either vkGetQueryPoolResults or vkCmdCopyQueryPoolResults.
All query commands execute in order and are guaranteed to see the effects of
each other’s memory accesses, with one significant exception:
vkCmdCopyQueryPoolResults may execute before the results of
vkCmdEndQuery are available.
However, if VK_QUERY_RESULT_WAIT_BIT is used, then
vkCmdCopyQueryPoolResults must reflect the result of any previously
executed queries.
Other sequences of commands, such as vkCmdResetQueryPool followed by
vkCmdBeginQuery, must make the effects of the first command visible
to the second command.
After query pool creation, each query is in an undefined state and must be reset prior to use. Queries must also be reset between uses. Using a query that has not been reset will result in undefined behavior.
To reset a range of queries in a query pool, call:
void vkCmdResetQueryPool(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount);
commandBuffer is the command buffer into which this command will
be recorded.
queryPool is the handle of the query pool managing the queries
being reset.
firstQuery is the initial query index to reset.
queryCount is the number of queries to reset.
When executed on a queue, this command sets the status of query indices
[firstQuery, firstQuery + queryCount - 1] to
unavailable.
Once queries are reset and ready for use, query commands can be issued to a
command buffer.
Occlusion queries and pipeline statistics queries count events - drawn
samples and pipeline stage invocations, respectively - resulting from
commands that are recorded between a vkCmdBeginQuery command and a
vkCmdEndQuery command within a specified command buffer, effectively
scoping a set of drawing and/or compute commands.
Timestamp queries write timestamps to a query pool.
A query must begin and end in the same command buffer, although if it is a
primary command buffer, and the
inherited queries feature is enabled,
it can execute secondary command buffers during the query operation.
For a secondary command buffer to be executed while a query is active, it
must set the occlusionQueryEnable, queryFlags, and/or
pipelineStatistics members of VkCommandBufferInheritanceInfo to
conservative values, as described in the Command Buffer Recording section.
A query must either begin and end inside the same subpass of a render pass
instance, or must both begin and end outside of a render pass instance
(i.e. contain entire render pass instances).
To begin a query, call:
void vkCmdBeginQuery(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query,
VkQueryControlFlags flags);
commandBuffer is the command buffer into which this command will
be recorded.
queryPool is the query pool that will manage the results of the
query.
query is the query index within the query pool that will contain
the results.
flags is a bitmask indicating constraints on the types of queries
that can be performed.
Bits which can be set include:
typedef enum VkQueryControlFlagBits {
VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001,
} VkQueryControlFlagBits;
If the queryType of the pool is VK_QUERY_TYPE_OCCLUSION and
flags contains VK_QUERY_CONTROL_PRECISE_BIT, an implementation
must return a result that matches the actual number of samples passed.
This is described in more detail in Occlusion Queries.
After beginning a query, that query is considered active within the command buffer it was called in until that same query is ended. Queries active in a primary command buffer when secondary command buffers are executed are considered active for those secondary command buffers.
To end a query after the set of desired draw or dispatch commands is executed, call:
void vkCmdEndQuery(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query);
commandBuffer is the command buffer into which this command will
be recorded.
queryPool is the query pool that is managing the results of the
query.
query is the query index within the query pool where the result is
stored.
As queries operate asynchronously, ending a query does not immediately set
the query’s status to available.
A query is considered finished when the final results of the query are
ready to be retrieved by vkGetQueryPoolResults and
vkCmdCopyQueryPoolResults, and this is when the query’s status is set
to available.
Once a query is ended the query must finish in finite time, unless the state of the query is changed using other commands, e.g. by issuing a reset of the query.
An application can retrieve results either by requesting they be written
into application-provided memory, or by requesting they be copied into a
VkBuffer.
In either case, the layout in memory is defined as follows:
stride
bytes later.
VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is used, the final
element of each query’s result is an integer indicating whether the
query’s result is available, with any non-zero value indicating that it
is available.
pipelineStatistics when the pool is created, and
the statistics values are written in bit order starting from the least
significant bit.
Timestamps write one integer value.
stride is not at least as
large as the size of the array of integers corresponding to a single
query, the values written to memory are undefined.
To retrieve status and results for a set of queries, call:
VkResult vkGetQueryPoolResults(
VkDevice device,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount,
size_t dataSize,
void* pData,
VkDeviceSize stride,
VkQueryResultFlags flags);
device is the logical device that owns the query pool.
queryPool is the query pool managing the queries containing the
desired results.
firstQuery is the initial query index.
queryCount is the number of queries.
firstQuery and queryCount together define a range of
queries.
dataSize is the size in bytes of the buffer pointed to by
pData.
pData is a pointer to a user-allocated buffer where the results
will be written
stride is the stride in bytes between results for individual
queries within pData.
flags is a bitmask of VkQueryResultFlagBits specifying how
and when results are returned.
Bits which can be set include:
typedef enum VkQueryResultFlagBits {
VK_QUERY_RESULT_64_BIT = 0x00000001,
VK_QUERY_RESULT_WAIT_BIT = 0x00000002,
VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004,
VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008,
} VkQueryResultFlagBits;
VK_QUERY_RESULT_64_BIT indicates the results will be written as
an array of 64-bit unsigned integer values.
If this bit is not set, the results will be written as an array of
32-bit unsigned integer values.
VK_QUERY_RESULT_WAIT_BIT indicates that Vulkan will wait for each
query’s status to become available before retrieving its results.
VK_QUERY_RESULT_WITH_AVAILABILITY_BIT indicates that the
availability status accompanies the results.
VK_QUERY_RESULT_PARTIAL_BIT indicates that returning partial
results is acceptable.
If no bits are set in flags, and all requested queries are in the
available state, results are written as an array of 32-bit unsigned integer
values.
The behavior when not all queries are available, is described
below.
If VK_QUERY_RESULT_64_BIT is not set and the result overflows a 32-bit
value, the value may either wrap or saturate.
Similarly, if VK_QUERY_RESULT_64_BIT is set and the result overflows a
64-bit value, the value may either wrap or saturate.
If VK_QUERY_RESULT_WAIT_BIT is set, Vulkan will wait for each query to
be in the available state before retrieving the numerical results for that
query.
In this case, vkGetQueryPoolResults is guaranteed to succeed and
return VK_SUCCESS if the queries become available in a finite time
(i.e. if they have been issued and not reset).
If queries will never finish (e.g. due to being reset but not issued), then
vkGetQueryPoolResults may not return in finite time.
If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are
both not set then no result values are written to pData for queries
that are in the unavailable state at the time of the call, and
vkGetQueryPoolResults returns VK_NOT_READY.
However, availability state is still written to pData for those
queries if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set.
| Note | |
|---|---|
Applications must take care to ensure that use of the
For example, if a query has been used previously and a command buffer
records the commands The above also applies when |
| Note | |
|---|---|
Applications can double-buffer query pool usage, with a pool per frame, and reset queries at the end of the frame in which they are read. |
If VK_QUERY_RESULT_PARTIAL_BIT is set, VK_QUERY_RESULT_WAIT_BIT
is not set, and the query’s status is unavailable, an intermediate result
value between zero and the final result value is written to pData for
that query.
VK_QUERY_RESULT_PARTIAL_BIT must not be used if the pool’s
queryType is VK_QUERY_TYPE_TIMESTAMP.
If VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set, the final integer
value written for each query is non-zero if the query’s status was available
or zero if the status was unavailable.
When VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is used, implementations
must guarantee that if they return a non-zero availability value then the
numerical results must be valid, assuming the results are not reset by a
subsequent command.
| Note | |
|---|---|
Satisfying this guarantee may require careful ordering by the application, e.g. to read the availability status before reading the results. |
To copy query statuses and numerical results directly to buffer memory, call:
void vkCmdCopyQueryPoolResults(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize stride,
VkQueryResultFlags flags);
commandBuffer is the command buffer into which this command will
be recorded.
queryPool is the query pool managing the queries containing the
desired results.
firstQuery is the initial query index.
queryCount is the number of queries.
firstQuery and queryCount together define a range of
queries.
dstBuffer is a VkBuffer object that will receive the results
of the copy command.
dstOffset is an offset into dstBuffer.
stride is the stride in bytes between results for individual
queries within dstBuffer.
The required size of the backing memory for dstBuffer is
determined as described above for vkGetQueryPoolResults.
flags is a bitmask of VkQueryResultFlagBits specifying how
and when results are returned.
vkCmdCopyQueryPoolResults is guaranteed to see the effect of previous
uses of vkCmdResetQueryPool in the same queue, without any additional
synchronization.
Thus, the results will always reflect the most recent use of the query.
flags has the same possible values described above for the flags
parameter of vkGetQueryPoolResults, but the different style of
execution causes some subtle behavioral differences.
Because vkCmdCopyQueryPoolResults executes in order with respect to
other query commands, there is less ambiguity about which use of a query is
being requested.
If no bits are set in flags, results for all requested queries in the
available state are written as 32-bit unsigned integer values, and nothing
is written for queries in the unavailable state.
If VK_QUERY_RESULT_64_BIT is set, the results are written as an array
of 64-bit unsigned integer values as described for
vkGetQueryPoolResults.
If VK_QUERY_RESULT_WAIT_BIT is set, the implementation will wait for
each query’s status to be in the available state before retrieving the
numerical results for that query.
This is guaranteed to reflect the most recent use of the query on the same
queue, assuming that the query is not being simultaneously used by other
queues.
If the query does not become available in a finite amount of time (e.g. due
to not issuing a query since the last reset), a VK_ERROR_DEVICE_LOST
error may occur.
Similarly, if VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set and
VK_QUERY_RESULT_WAIT_BIT is not set, the availability is guaranteed to
reflect the most recent use of the query on the same queue, assuming that
the query is not being simultaneously used by other queues.
As with vkGetQueryPoolResults, implementations must guarantee that if
they return a non-zero availability value, then the numerical results are
valid.
If VK_QUERY_RESULT_PARTIAL_BIT is set, VK_QUERY_RESULT_WAIT_BIT
is not set, and the query’s status is unavailable, an intermediate result
value between zero and the final result value is written for that query.
VK_QUERY_RESULT_PARTIAL_BIT must not be used if the pool’s
queryType is VK_QUERY_TYPE_TIMESTAMP.
vkCmdCopyQueryPoolResults is considered to be a transfer operation,
and its writes to buffer memory must be synchronized using
VK_PIPELINE_STAGE_TRANSFER_BIT and VK_ACCESS_TRANSFER_WRITE_BIT
before using the results.
Rendering operations such as clears, MSAA resolves, attachment load/store operations, and blits may count towards the results of queries. This behavior is implementation-dependent and may vary depending on the path used within an implementation. For example, some implementations have several types of clears, some of which may include vertices and some not.