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