vk: Add the new extension/layer enumeration entrypoints
[mesa.git] / src / vulkan / query.c
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 "private.h"
31
32 struct anv_query_pool_slot {
33 uint64_t begin;
34 uint64_t end;
35 uint64_t available;
36 };
37
38 struct anv_query_pool {
39 struct anv_object base;
40 VkQueryType type;
41 uint32_t slots;
42 struct anv_bo bo;
43 };
44
45 static void
46 anv_query_pool_destroy(struct anv_device *device,
47 struct anv_object *object,
48 VkObjectType obj_type)
49 {
50 struct anv_query_pool *pool = (struct anv_query_pool *) object;
51
52 assert(obj_type == VK_OBJECT_TYPE_QUERY_POOL);
53
54 anv_DestroyQueryPool(anv_device_to_handle(device),
55 anv_query_pool_to_handle(pool));
56 }
57
58 VkResult anv_CreateQueryPool(
59 VkDevice _device,
60 const VkQueryPoolCreateInfo* pCreateInfo,
61 VkQueryPool* pQueryPool)
62 {
63 ANV_FROM_HANDLE(anv_device, device, _device);
64 struct anv_query_pool *pool;
65 VkResult result;
66 size_t size;
67
68 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO);
69
70 switch (pCreateInfo->queryType) {
71 case VK_QUERY_TYPE_OCCLUSION:
72 break;
73 case VK_QUERY_TYPE_PIPELINE_STATISTICS:
74 return VK_UNSUPPORTED;
75 default:
76 unreachable("");
77 }
78
79 pool = anv_device_alloc(device, sizeof(*pool), 8,
80 VK_SYSTEM_ALLOC_TYPE_API_OBJECT);
81 if (pool == NULL)
82 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
83
84 pool->base.destructor = anv_query_pool_destroy;
85
86 pool->type = pCreateInfo->queryType;
87 size = pCreateInfo->slots * sizeof(struct anv_query_pool_slot);
88 result = anv_bo_init_new(&pool->bo, device, size);
89 if (result != VK_SUCCESS)
90 goto fail;
91
92 pool->bo.map = anv_gem_mmap(device, pool->bo.gem_handle, 0, size);
93
94 *pQueryPool = anv_query_pool_to_handle(pool);
95
96 return VK_SUCCESS;
97
98 fail:
99 anv_device_free(device, pool);
100
101 return result;
102 }
103
104 VkResult anv_DestroyQueryPool(
105 VkDevice _device,
106 VkQueryPool _pool)
107 {
108 ANV_FROM_HANDLE(anv_device, device, _device);
109 ANV_FROM_HANDLE(anv_query_pool, pool, _pool);
110
111 anv_gem_munmap(pool->bo.map, pool->bo.size);
112 anv_gem_close(device, pool->bo.gem_handle);
113 anv_device_free(device, pool);
114
115 return VK_SUCCESS;
116 }
117
118 VkResult anv_GetQueryPoolResults(
119 VkDevice _device,
120 VkQueryPool queryPool,
121 uint32_t startQuery,
122 uint32_t queryCount,
123 size_t* pDataSize,
124 void* pData,
125 VkQueryResultFlags flags)
126 {
127 ANV_FROM_HANDLE(anv_device, device, _device);
128 ANV_FROM_HANDLE(anv_query_pool, pool, queryPool);
129 struct anv_query_pool_slot *slot = pool->bo.map;
130 int64_t timeout = INT64_MAX;
131 uint32_t *dst32 = pData;
132 uint64_t *dst64 = pData;
133 uint64_t result;
134 int ret;
135
136 if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
137 /* Where is the availabilty info supposed to go? */
138 anv_finishme("VK_QUERY_RESULT_WITH_AVAILABILITY_BIT");
139 return VK_UNSUPPORTED;
140 }
141
142 assert(pool->type == VK_QUERY_TYPE_OCCLUSION);
143
144 if (flags & VK_QUERY_RESULT_64_BIT)
145 *pDataSize = queryCount * sizeof(uint64_t);
146 else
147 *pDataSize = queryCount * sizeof(uint32_t);
148
149 if (pData == NULL)
150 return VK_SUCCESS;
151
152 if (flags & VK_QUERY_RESULT_WAIT_BIT) {
153 ret = anv_gem_wait(device, pool->bo.gem_handle, &timeout);
154 if (ret == -1)
155 return vk_error(VK_ERROR_UNKNOWN);
156 }
157
158 for (uint32_t i = 0; i < queryCount; i++) {
159 result = slot[startQuery + i].end - slot[startQuery + i].begin;
160 if (flags & VK_QUERY_RESULT_64_BIT) {
161 *dst64++ = result;
162 } else {
163 if (result > UINT32_MAX)
164 result = UINT32_MAX;
165 *dst32++ = result;
166 }
167 }
168
169 return VK_SUCCESS;
170 }
171
172 static void
173 anv_batch_emit_ps_depth_count(struct anv_batch *batch,
174 struct anv_bo *bo, uint32_t offset)
175 {
176 anv_batch_emit(batch, GEN8_PIPE_CONTROL,
177 .DestinationAddressType = DAT_PPGTT,
178 .PostSyncOperation = WritePSDepthCount,
179 .Address = { bo, offset }); /* FIXME: This is only lower 32 bits */
180 }
181
182 void anv_CmdBeginQuery(
183 VkCmdBuffer cmdBuffer,
184 VkQueryPool queryPool,
185 uint32_t slot,
186 VkQueryControlFlags flags)
187 {
188 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer);
189 ANV_FROM_HANDLE(anv_query_pool, pool, queryPool);
190
191 switch (pool->type) {
192 case VK_QUERY_TYPE_OCCLUSION:
193 anv_batch_emit_ps_depth_count(&cmd_buffer->batch, &pool->bo,
194 slot * sizeof(struct anv_query_pool_slot));
195 break;
196
197 case VK_QUERY_TYPE_PIPELINE_STATISTICS:
198 default:
199 unreachable("");
200 }
201 }
202
203 void anv_CmdEndQuery(
204 VkCmdBuffer cmdBuffer,
205 VkQueryPool queryPool,
206 uint32_t slot)
207 {
208 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer);
209 ANV_FROM_HANDLE(anv_query_pool, pool, queryPool);
210
211 switch (pool->type) {
212 case VK_QUERY_TYPE_OCCLUSION:
213 anv_batch_emit_ps_depth_count(&cmd_buffer->batch, &pool->bo,
214 slot * sizeof(struct anv_query_pool_slot) + 8);
215 break;
216
217 case VK_QUERY_TYPE_PIPELINE_STATISTICS:
218 default:
219 unreachable("");
220 }
221 }
222
223 void anv_CmdResetQueryPool(
224 VkCmdBuffer cmdBuffer,
225 VkQueryPool queryPool,
226 uint32_t startQuery,
227 uint32_t queryCount)
228 {
229 stub();
230 }
231
232 #define TIMESTAMP 0x2358
233
234 void anv_CmdWriteTimestamp(
235 VkCmdBuffer cmdBuffer,
236 VkTimestampType timestampType,
237 VkBuffer destBuffer,
238 VkDeviceSize destOffset)
239 {
240 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer);
241 ANV_FROM_HANDLE(anv_buffer, buffer, destBuffer);
242 struct anv_bo *bo = buffer->bo;
243
244 switch (timestampType) {
245 case VK_TIMESTAMP_TYPE_TOP:
246 anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM,
247 .RegisterAddress = TIMESTAMP,
248 .MemoryAddress = { bo, buffer->offset + destOffset });
249 anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM,
250 .RegisterAddress = TIMESTAMP + 4,
251 .MemoryAddress = { bo, buffer->offset + destOffset + 4 });
252 break;
253
254 case VK_TIMESTAMP_TYPE_BOTTOM:
255 anv_batch_emit(&cmd_buffer->batch, GEN8_PIPE_CONTROL,
256 .DestinationAddressType = DAT_PPGTT,
257 .PostSyncOperation = WriteTimestamp,
258 .Address = /* FIXME: This is only lower 32 bits */
259 { bo, buffer->offset + destOffset });
260 break;
261
262 default:
263 break;
264 }
265 }
266
267 #define alu_opcode(v) __gen_field((v), 20, 31)
268 #define alu_operand1(v) __gen_field((v), 10, 19)
269 #define alu_operand2(v) __gen_field((v), 0, 9)
270 #define alu(opcode, operand1, operand2) \
271 alu_opcode(opcode) | alu_operand1(operand1) | alu_operand2(operand2)
272
273 #define OPCODE_NOOP 0x000
274 #define OPCODE_LOAD 0x080
275 #define OPCODE_LOADINV 0x480
276 #define OPCODE_LOAD0 0x081
277 #define OPCODE_LOAD1 0x481
278 #define OPCODE_ADD 0x100
279 #define OPCODE_SUB 0x101
280 #define OPCODE_AND 0x102
281 #define OPCODE_OR 0x103
282 #define OPCODE_XOR 0x104
283 #define OPCODE_STORE 0x180
284 #define OPCODE_STOREINV 0x580
285
286 #define OPERAND_R0 0x00
287 #define OPERAND_R1 0x01
288 #define OPERAND_R2 0x02
289 #define OPERAND_R3 0x03
290 #define OPERAND_R4 0x04
291 #define OPERAND_SRCA 0x20
292 #define OPERAND_SRCB 0x21
293 #define OPERAND_ACCU 0x31
294 #define OPERAND_ZF 0x32
295 #define OPERAND_CF 0x33
296
297 #define CS_GPR(n) (0x2600 + (n) * 8)
298
299 static void
300 emit_load_alu_reg_u64(struct anv_batch *batch, uint32_t reg,
301 struct anv_bo *bo, uint32_t offset)
302 {
303 anv_batch_emit(batch, GEN8_MI_LOAD_REGISTER_MEM,
304 .RegisterAddress = reg,
305 .MemoryAddress = { bo, offset });
306 anv_batch_emit(batch, GEN8_MI_LOAD_REGISTER_MEM,
307 .RegisterAddress = reg + 4,
308 .MemoryAddress = { bo, offset + 4 });
309 }
310
311 void anv_CmdCopyQueryPoolResults(
312 VkCmdBuffer cmdBuffer,
313 VkQueryPool queryPool,
314 uint32_t startQuery,
315 uint32_t queryCount,
316 VkBuffer destBuffer,
317 VkDeviceSize destOffset,
318 VkDeviceSize destStride,
319 VkQueryResultFlags flags)
320 {
321 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer, cmdBuffer);
322 ANV_FROM_HANDLE(anv_query_pool, pool, queryPool);
323 ANV_FROM_HANDLE(anv_buffer, buffer, destBuffer);
324 uint32_t slot_offset, dst_offset;
325
326 if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
327 /* Where is the availabilty info supposed to go? */
328 anv_finishme("VK_QUERY_RESULT_WITH_AVAILABILITY_BIT");
329 return;
330 }
331
332 assert(pool->type == VK_QUERY_TYPE_OCCLUSION);
333
334 /* FIXME: If we're not waiting, should we just do this on the CPU? */
335 if (flags & VK_QUERY_RESULT_WAIT_BIT)
336 anv_batch_emit(&cmd_buffer->batch, GEN8_PIPE_CONTROL,
337 .CommandStreamerStallEnable = true,
338 .StallAtPixelScoreboard = true);
339
340 dst_offset = buffer->offset + destOffset;
341 for (uint32_t i = 0; i < queryCount; i++) {
342
343 slot_offset = (startQuery + i) * sizeof(struct anv_query_pool_slot);
344
345 emit_load_alu_reg_u64(&cmd_buffer->batch, CS_GPR(0), &pool->bo, slot_offset);
346 emit_load_alu_reg_u64(&cmd_buffer->batch, CS_GPR(1), &pool->bo, slot_offset + 8);
347
348 /* FIXME: We need to clamp the result for 32 bit. */
349
350 uint32_t *dw = anv_batch_emitn(&cmd_buffer->batch, 5, GEN8_MI_MATH);
351 dw[1] = alu(OPCODE_LOAD, OPERAND_SRCA, OPERAND_R1);
352 dw[2] = alu(OPCODE_LOAD, OPERAND_SRCB, OPERAND_R0);
353 dw[3] = alu(OPCODE_SUB, 0, 0);
354 dw[4] = alu(OPCODE_STORE, OPERAND_R2, OPERAND_ACCU);
355
356 anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM,
357 .RegisterAddress = CS_GPR(2),
358 /* FIXME: This is only lower 32 bits */
359 .MemoryAddress = { buffer->bo, dst_offset });
360
361 if (flags & VK_QUERY_RESULT_64_BIT)
362 anv_batch_emit(&cmd_buffer->batch, GEN8_MI_STORE_REGISTER_MEM,
363 .RegisterAddress = CS_GPR(2) + 4,
364 /* FIXME: This is only lower 32 bits */
365 .MemoryAddress = { buffer->bo, dst_offset + 4 });
366
367 dst_offset += destStride;
368 }
369 }