## 16.2. Query Operation

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:

- The first query’s result is written starting at the first byte requested by the command, and each subsequent query’s result begins `stride` bytes later.
- Each query’s result is a tightly packed array of unsigned integers, either 32- or 64-bits as requested by the command, storing the numerical results and, if requested, the availability status.
- If `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.
- Occlusion queries write one integer value - the number of samples passed. Pipeline statistics queries write one integer value for each bit that is enabled in the `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.
- If more than one query is retrieved and `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 `VK_QUERY_RESULT_WAIT_BIT` bit has the desired effect. For example, if a query has been used previously and a command buffer records the commands `vkCmdResetQueryPool`, `vkCmdBeginQuery`, and `vkCmdEndQuery` for that query, then the query will remain in the available state until the `vkCmdResetQueryPool` command executes on a queue. Applications can use fences or events to ensure that a query has already been reset before checking for its results or availability status. Otherwise, a stale value could be returned from a previous use of the query. The above also applies when `VK_QUERY_RESULT_WAIT_BIT` is used in combination with `VK_QUERY_RESULT_WITH_AVAILABILITY_BIT`. In this case, the returned availability status may reflect the result of a previous use of the query unless the `vkCmdResetQueryPool` command has been executed since the last use of the query.

| 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.