1 /*
2 * Copyright © 2019 Red Hat.
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 "lvp_private.h"
25 #include "pipe/p_context.h"
26
lvp_CreateQueryPool(VkDevice _device,const VkQueryPoolCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkQueryPool * pQueryPool)27 VKAPI_ATTR VkResult VKAPI_CALL lvp_CreateQueryPool(
28 VkDevice _device,
29 const VkQueryPoolCreateInfo* pCreateInfo,
30 const VkAllocationCallbacks* pAllocator,
31 VkQueryPool* pQueryPool)
32 {
33 LVP_FROM_HANDLE(lvp_device, device, _device);
34
35 enum pipe_query_type pipeq;
36 switch (pCreateInfo->queryType) {
37 case VK_QUERY_TYPE_OCCLUSION:
38 pipeq = PIPE_QUERY_OCCLUSION_COUNTER;
39 break;
40 case VK_QUERY_TYPE_TIMESTAMP:
41 pipeq = PIPE_QUERY_TIMESTAMP;
42 break;
43 case VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT:
44 pipeq = PIPE_QUERY_SO_STATISTICS;
45 break;
46 case VK_QUERY_TYPE_PIPELINE_STATISTICS:
47 pipeq = PIPE_QUERY_PIPELINE_STATISTICS;
48 break;
49 case VK_QUERY_TYPE_PRIMITIVES_GENERATED_EXT:
50 case VK_QUERY_TYPE_MESH_PRIMITIVES_GENERATED_EXT:
51 pipeq = PIPE_QUERY_PRIMITIVES_GENERATED;
52 break;
53 default:
54 return VK_ERROR_FEATURE_NOT_PRESENT;
55 }
56
57 struct lvp_query_pool *pool;
58 size_t pool_size = sizeof(*pool)
59 + pCreateInfo->queryCount * sizeof(struct pipe_query *);
60
61 pool = vk_zalloc2(&device->vk.alloc, pAllocator,
62 pool_size, 8,
63 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
64 if (!pool)
65 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
66
67 vk_object_base_init(&device->vk, &pool->base,
68 VK_OBJECT_TYPE_QUERY_POOL);
69 pool->type = pCreateInfo->queryType;
70 pool->count = pCreateInfo->queryCount;
71 pool->base_type = pipeq;
72 pool->pipeline_stats = pCreateInfo->pipelineStatistics;
73
74 *pQueryPool = lvp_query_pool_to_handle(pool);
75 return VK_SUCCESS;
76 }
77
lvp_DestroyQueryPool(VkDevice _device,VkQueryPool _pool,const VkAllocationCallbacks * pAllocator)78 VKAPI_ATTR void VKAPI_CALL lvp_DestroyQueryPool(
79 VkDevice _device,
80 VkQueryPool _pool,
81 const VkAllocationCallbacks* pAllocator)
82 {
83 LVP_FROM_HANDLE(lvp_device, device, _device);
84 LVP_FROM_HANDLE(lvp_query_pool, pool, _pool);
85
86 if (!pool)
87 return;
88
89 for (unsigned i = 0; i < pool->count; i++)
90 if (pool->queries[i])
91 device->queue.ctx->destroy_query(device->queue.ctx, pool->queries[i]);
92 vk_object_base_finish(&pool->base);
93 vk_free2(&device->vk.alloc, pAllocator, pool);
94 }
95
lvp_GetQueryPoolResults(VkDevice _device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount,size_t dataSize,void * pData,VkDeviceSize stride,VkQueryResultFlags flags)96 VKAPI_ATTR VkResult VKAPI_CALL lvp_GetQueryPoolResults(
97 VkDevice _device,
98 VkQueryPool queryPool,
99 uint32_t firstQuery,
100 uint32_t queryCount,
101 size_t dataSize,
102 void* pData,
103 VkDeviceSize stride,
104 VkQueryResultFlags flags)
105 {
106 LVP_FROM_HANDLE(lvp_device, device, _device);
107 LVP_FROM_HANDLE(lvp_query_pool, pool, queryPool);
108 VkResult vk_result = VK_SUCCESS;
109
110 device->vk.dispatch_table.DeviceWaitIdle(_device);
111
112 for (unsigned i = firstQuery; i < firstQuery + queryCount; i++) {
113 uint8_t *dest = (uint8_t *)((char *)pData + (stride * (i - firstQuery)));
114 union pipe_query_result result;
115 bool ready = false;
116
117 if (pool->queries[i]) {
118 ready = device->queue.ctx->get_query_result(device->queue.ctx,
119 pool->queries[i],
120 (flags & VK_QUERY_RESULT_WAIT_BIT),
121 &result);
122 } else {
123 result.u64 = 0;
124 }
125
126 if (!ready && !(flags & VK_QUERY_RESULT_PARTIAL_BIT))
127 vk_result = VK_NOT_READY;
128
129 if (flags & VK_QUERY_RESULT_64_BIT) {
130 uint64_t *dest64 = (uint64_t *) dest;
131 if (ready || (flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
132 if (pool->type == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
133 uint32_t mask = pool->pipeline_stats;
134 const uint64_t *pstats = result.pipeline_statistics.counters;
135 while (mask) {
136 uint32_t i = u_bit_scan(&mask);
137 *dest64++ = pstats[i];
138 }
139 } else if (pool->type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
140 *dest64++ = result.so_statistics.num_primitives_written;
141 *dest64++ = result.so_statistics.primitives_storage_needed;
142 } else {
143 *dest64++ = result.u64;
144 }
145 } else {
146 if (pool->type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
147 dest64 += 2; // 16 bytes
148 } else {
149 dest64 += 1; // 8 bytes
150 }
151 }
152 if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
153 *dest64 = ready;
154 }
155 } else {
156 uint32_t *dest32 = (uint32_t *) dest;
157 if (ready || (flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
158 if (pool->type == VK_QUERY_TYPE_PIPELINE_STATISTICS) {
159 uint32_t mask = pool->pipeline_stats;
160 const uint64_t *pstats = result.pipeline_statistics.counters;
161 while (mask) {
162 uint32_t i = u_bit_scan(&mask);
163 *dest32++ = (uint32_t) MIN2(pstats[i], UINT32_MAX);
164 }
165 } else if (pool->type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
166 *dest32++ = (uint32_t)
167 MIN2(result.so_statistics.num_primitives_written, UINT32_MAX);
168 *dest32++ = (uint32_t)
169 MIN2(result.so_statistics.primitives_storage_needed, UINT32_MAX);
170 } else {
171 *dest32++ = (uint32_t) MIN2(result.u64, UINT32_MAX);
172 }
173 } else {
174 if (pool->type == VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT) {
175 dest32 += 2; // 8 bytes
176 } else {
177 dest32 += 1; // 4 bytes
178 }
179 }
180 if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
181 *dest32 = ready;
182 }
183 }
184 }
185 return vk_result;
186 }
187
lvp_ResetQueryPool(VkDevice _device,VkQueryPool queryPool,uint32_t firstQuery,uint32_t queryCount)188 VKAPI_ATTR void VKAPI_CALL lvp_ResetQueryPool(
189 VkDevice _device,
190 VkQueryPool queryPool,
191 uint32_t firstQuery,
192 uint32_t queryCount)
193 {
194 LVP_FROM_HANDLE(lvp_device, device, _device);
195 LVP_FROM_HANDLE(lvp_query_pool, pool, queryPool);
196
197 for (uint32_t i = 0; i < queryCount; i++) {
198 uint32_t idx = i + firstQuery;
199
200 if (pool->queries[idx]) {
201 device->queue.ctx->destroy_query(device->queue.ctx, pool->queries[idx]);
202 pool->queries[idx] = NULL;
203 }
204 }
205 }
206