• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
anv_CreateQueryPool(VkDevice _device,const VkQueryPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkQueryPool * pQueryPool)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 
anv_DestroyQueryPool(VkDevice _device,VkQueryPool _pool,const VkAllocationCallbacks * pAllocator)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 
anv_GetQueryPoolResults(VkDevice _device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,size_t dataSize,void * pData,VkDeviceSize stride,VkQueryResultFlags flags)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