• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC
3  * SPDX-License-Identifier: MIT
4  *
5  * based in part on anv and radv which are:
6  * Copyright © 2015 Intel Corporation
7  * Copyright © 2016 Red Hat.
8  * Copyright © 2016 Bas Nieuwenhuizen
9  */
10 
11 #include "vn_query_pool.h"
12 
13 #include "venus-protocol/vn_protocol_driver_query_pool.h"
14 
15 #include "vn_device.h"
16 
17 /* query pool commands */
18 
19 VkResult
vn_CreateQueryPool(VkDevice device,const VkQueryPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkQueryPool * pQueryPool)20 vn_CreateQueryPool(VkDevice device,
21                    const VkQueryPoolCreateInfo *pCreateInfo,
22                    const VkAllocationCallbacks *pAllocator,
23                    VkQueryPool *pQueryPool)
24 {
25    VN_TRACE_FUNC();
26    struct vn_device *dev = vn_device_from_handle(device);
27    const VkAllocationCallbacks *alloc =
28       pAllocator ? pAllocator : &dev->base.base.alloc;
29 
30    struct vn_query_pool *pool =
31       vk_zalloc(alloc, sizeof(*pool), VN_DEFAULT_ALIGN,
32                 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
33    if (!pool)
34       return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
35 
36    vn_object_base_init(&pool->base, VK_OBJECT_TYPE_QUERY_POOL, &dev->base);
37 
38    pool->allocator = *alloc;
39 
40    switch (pCreateInfo->queryType) {
41    case VK_QUERY_TYPE_OCCLUSION:
42       pool->result_array_size = 1;
43       break;
44    case VK_QUERY_TYPE_PIPELINE_STATISTICS:
45       pool->result_array_size =
46          util_bitcount(pCreateInfo->pipelineStatistics);
47       break;
48    case VK_QUERY_TYPE_TIMESTAMP:
49       pool->result_array_size = 1;
50       break;
51    case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
52       pool->result_array_size = 2;
53       break;
54    default:
55       unreachable("bad query type");
56       break;
57    }
58 
59    VkQueryPool pool_handle = vn_query_pool_to_handle(pool);
60    vn_async_vkCreateQueryPool(dev->instance, device, pCreateInfo, NULL,
61                               &pool_handle);
62 
63    *pQueryPool = pool_handle;
64 
65    return VK_SUCCESS;
66 }
67 
68 void
vn_DestroyQueryPool(VkDevice device,VkQueryPool queryPool,const VkAllocationCallbacks * pAllocator)69 vn_DestroyQueryPool(VkDevice device,
70                     VkQueryPool queryPool,
71                     const VkAllocationCallbacks *pAllocator)
72 {
73    VN_TRACE_FUNC();
74    struct vn_device *dev = vn_device_from_handle(device);
75    struct vn_query_pool *pool = vn_query_pool_from_handle(queryPool);
76    const VkAllocationCallbacks *alloc;
77 
78    if (!pool)
79       return;
80 
81    alloc = pAllocator ? pAllocator : &pool->allocator;
82 
83    vn_async_vkDestroyQueryPool(dev->instance, device, queryPool, NULL);
84 
85    vn_object_base_fini(&pool->base);
86    vk_free(alloc, pool);
87 }
88 
89 void
vn_ResetQueryPool(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount)90 vn_ResetQueryPool(VkDevice device,
91                   VkQueryPool queryPool,
92                   uint32_t firstQuery,
93                   uint32_t queryCount)
94 {
95    VN_TRACE_FUNC();
96    struct vn_device *dev = vn_device_from_handle(device);
97 
98    vn_async_vkResetQueryPool(dev->instance, device, queryPool, firstQuery,
99                              queryCount);
100 }
101 
102 VkResult
vn_GetQueryPoolResults(VkDevice device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,size_t dataSize,void * pData,VkDeviceSize stride,VkQueryResultFlags flags)103 vn_GetQueryPoolResults(VkDevice device,
104                        VkQueryPool queryPool,
105                        uint32_t firstQuery,
106                        uint32_t queryCount,
107                        size_t dataSize,
108                        void *pData,
109                        VkDeviceSize stride,
110                        VkQueryResultFlags flags)
111 {
112    VN_TRACE_FUNC();
113    struct vn_device *dev = vn_device_from_handle(device);
114    struct vn_query_pool *pool = vn_query_pool_from_handle(queryPool);
115    const VkAllocationCallbacks *alloc = &pool->allocator;
116 
117    const size_t result_width = flags & VK_QUERY_RESULT_64_BIT ? 8 : 4;
118    const size_t result_size = pool->result_array_size * result_width;
119    const bool result_always_written =
120       flags & (VK_QUERY_RESULT_WAIT_BIT | VK_QUERY_RESULT_PARTIAL_BIT);
121 
122    VkQueryResultFlags packed_flags = flags;
123    size_t packed_stride = result_size;
124    if (!result_always_written)
125       packed_flags |= VK_QUERY_RESULT_WITH_AVAILABILITY_BIT;
126    if (packed_flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
127       packed_stride += result_width;
128 
129    const size_t packed_size = packed_stride * queryCount;
130    void *packed_data;
131    if (result_always_written && packed_stride == stride) {
132       packed_data = pData;
133    } else {
134       packed_data = vk_alloc(alloc, packed_size, VN_DEFAULT_ALIGN,
135                              VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
136       if (!packed_data)
137          return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
138    }
139 
140    /* TODO the renderer should transparently vkCmdCopyQueryPoolResults to a
141     * coherent memory such that we can memcpy from the coherent memory to
142     * avoid this serialized round trip.
143     */
144    VkResult result = vn_call_vkGetQueryPoolResults(
145       dev->instance, device, queryPool, firstQuery, queryCount, packed_size,
146       packed_data, packed_stride, packed_flags);
147 
148    if (packed_data == pData)
149       return vn_result(dev->instance, result);
150 
151    const size_t copy_size =
152       result_size +
153       (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT ? result_width : 0);
154    const void *src = packed_data;
155    void *dst = pData;
156    if (result == VK_SUCCESS) {
157       for (uint32_t i = 0; i < queryCount; i++) {
158          memcpy(dst, src, copy_size);
159          src += packed_stride;
160          dst += stride;
161       }
162    } else if (result == VK_NOT_READY) {
163       assert(!result_always_written &&
164              (packed_flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT));
165       if (flags & VK_QUERY_RESULT_64_BIT) {
166          for (uint32_t i = 0; i < queryCount; i++) {
167             const bool avail = *(const uint64_t *)(src + result_size);
168             if (avail)
169                memcpy(dst, src, copy_size);
170             else if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
171                *(uint64_t *)(dst + result_size) = 0;
172 
173             src += packed_stride;
174             dst += stride;
175          }
176       } else {
177          for (uint32_t i = 0; i < queryCount; i++) {
178             const bool avail = *(const uint32_t *)(src + result_size);
179             if (avail)
180                memcpy(dst, src, copy_size);
181             else if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
182                *(uint32_t *)(dst + result_size) = 0;
183 
184             src += packed_stride;
185             dst += stride;
186          }
187       }
188    }
189 
190    vk_free(alloc, packed_data);
191    return vn_result(dev->instance, result);
192 }
193