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.