Home | History | Annotate | Download | only in vulkan
      1 /*
      2  * Copyright  2015 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #include <assert.h>
     25 #include <stdbool.h>
     26 #include <string.h>
     27 #include <unistd.h>
     28 #include <fcntl.h>
     29 
     30 #include "anv_private.h"
     31 
     32 VkResult anv_CreateQueryPool(
     33     VkDevice                                    _device,
     34     const VkQueryPoolCreateInfo*                pCreateInfo,
     35     const VkAllocationCallbacks*                pAllocator,
     36     VkQueryPool*                                pQueryPool)
     37 {
     38    ANV_FROM_HANDLE(anv_device, device, _device);
     39    struct anv_query_pool *pool;
     40    VkResult result;
     41    uint32_t slot_size;
     42    uint64_t size;
     43 
     44    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO);
     45 
     46    switch (pCreateInfo->queryType) {
     47    case VK_QUERY_TYPE_OCCLUSION:
     48    case VK_QUERY_TYPE_TIMESTAMP:
     49       break;
     50    case VK_QUERY_TYPE_PIPELINE_STATISTICS:
     51       return VK_ERROR_INCOMPATIBLE_DRIVER;
     52    default:
     53       assert(!"Invalid query type");
     54    }
     55 
     56    slot_size = sizeof(struct anv_query_pool_slot);
     57    pool = vk_alloc2(&device->alloc, pAllocator, sizeof(*pool), 8,
     58                      VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
     59    if (pool == NULL)
     60       return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
     61 
     62    pool->type = pCreateInfo->queryType;
     63    pool->slots = pCreateInfo->queryCount;
     64 
     65    size = pCreateInfo->queryCount * slot_size;
     66    result = anv_bo_init_new(&pool->bo, device, size);
     67    if (result != VK_SUCCESS)
     68       goto fail;
     69 
     70    pool->bo.map = anv_gem_mmap(device, pool->bo.gem_handle, 0, size, 0);
     71 
     72    *pQueryPool = anv_query_pool_to_handle(pool);
     73 
     74    return VK_SUCCESS;
     75 
     76  fail:
     77    vk_free2(&device->alloc, pAllocator, pool);
     78 
     79    return result;
     80 }
     81 
     82 void anv_DestroyQueryPool(
     83     VkDevice                                    _device,
     84     VkQueryPool                                 _pool,
     85     const VkAllocationCallbacks*                pAllocator)
     86 {
     87    ANV_FROM_HANDLE(anv_device, device, _device);
     88    ANV_FROM_HANDLE(anv_query_pool, pool, _pool);
     89 
     90    if (!pool)
     91       return;
     92 
     93    anv_gem_munmap(pool->bo.map, pool->bo.size);
     94    anv_gem_close(device, pool->bo.gem_handle);
     95    vk_free2(&device->alloc, pAllocator, pool);
     96 }
     97 
     98 VkResult anv_GetQueryPoolResults(
     99     VkDevice                                    _device,
    100     VkQueryPool                                 queryPool,
    101     uint32_t                                    firstQuery,
    102     uint32_t                                    queryCount,
    103     size_t                                      dataSize,
    104     void*                                       pData,
    105     VkDeviceSize                                stride,
    106     VkQueryResultFlags                          flags)
    107 {
    108    ANV_FROM_HANDLE(anv_device, device, _device);
    109    ANV_FROM_HANDLE(anv_query_pool, pool, queryPool);
    110    int64_t timeout = INT64_MAX;
    111    uint64_t result;
    112    int ret;
    113 
    114    assert(pool->type == VK_QUERY_TYPE_OCCLUSION ||
    115           pool->type == VK_QUERY_TYPE_TIMESTAMP);
    116 
    117    if (pData == NULL)
    118       return VK_SUCCESS;
    119 
    120    if (flags & VK_QUERY_RESULT_WAIT_BIT) {
    121       ret = anv_gem_wait(device, pool->bo.gem_handle, &timeout);
    122       if (ret == -1) {
    123          /* We don't know the real error. */
    124          return vk_errorf(VK_ERROR_OUT_OF_DEVICE_MEMORY,
    125                           "gem_wait failed %m");
    126       }
    127    }
    128 
    129    void *data_end = pData + dataSize;
    130    struct anv_query_pool_slot *slot = pool->bo.map;
    131 
    132    if (!device->info.has_llc) {
    133       uint64_t offset = firstQuery * sizeof(*slot);
    134       uint64_t size = queryCount * sizeof(*slot);
    135       anv_invalidate_range(pool->bo.map + offset,
    136                            MIN2(size, pool->bo.size - offset));
    137    }
    138 
    139    VkResult status = VK_SUCCESS;
    140    for (uint32_t i = 0; i < queryCount; i++) {
    141       bool available = slot[firstQuery + i].available;
    142 
    143       /* From the Vulkan 1.0.42 spec:
    144        *
    145        *    "If VK_QUERY_RESULT_WAIT_BIT and VK_QUERY_RESULT_PARTIAL_BIT are
    146        *    both not set then no result values are written to pData for
    147        *    queries that are in the unavailable state at the time of the call,
    148        *    and vkGetQueryPoolResults returns VK_NOT_READY. However,
    149        *    availability state is still written to pData for those queries if
    150        *    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT is set."
    151        */
    152       bool write_results = available || (flags & VK_QUERY_RESULT_PARTIAL_BIT);
    153 
    154       if (write_results) {
    155          switch (pool->type) {
    156          case VK_QUERY_TYPE_OCCLUSION: {
    157             result = slot[firstQuery + i].end - slot[firstQuery + i].begin;
    158             break;
    159          }
    160          case VK_QUERY_TYPE_PIPELINE_STATISTICS:
    161             unreachable("pipeline stats not supported");
    162          case VK_QUERY_TYPE_TIMESTAMP: {
    163             result = slot[firstQuery + i].begin;
    164             break;
    165          }
    166          default:
    167             unreachable("invalid pool type");
    168          }
    169       } else {
    170          status = VK_NOT_READY;
    171       }
    172 
    173       if (flags & VK_QUERY_RESULT_64_BIT) {
    174          uint64_t *dst = pData;
    175          if (write_results)
    176             dst[0] = result;
    177          if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
    178             dst[1] = slot[firstQuery + i].available;
    179       } else {
    180          uint32_t *dst = pData;
    181          if (result > UINT32_MAX)
    182             result = UINT32_MAX;
    183          if (write_results)
    184             dst[0] = result;
    185          if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
    186             dst[1] = slot[firstQuery + i].available;
    187       }
    188 
    189       pData += stride;
    190       if (pData >= data_end)
    191          break;
    192    }
    193 
    194    return status;
    195 }
    196