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.