a8bab7d3e3518345ff1e99fc2985daa0e90b1b30
[mesa.git] / src / gallium / drivers / iris / iris_query.c
1 /*
2 * Copyright © 2017 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 shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 /**
24 * @file iris_query.c
25 *
26 * XXX: this file is EMPTY. it will eventually implement query objects!
27 */
28
29 #include <stdio.h>
30 #include <errno.h>
31 #include "pipe/p_defines.h"
32 #include "pipe/p_state.h"
33 #include "pipe/p_context.h"
34 #include "pipe/p_screen.h"
35 #include "util/u_inlines.h"
36 #include "iris_context.h"
37 #include "iris_defines.h"
38 #include "iris_resource.h"
39 #include "iris_screen.h"
40
41 #define CS_GPR(n) (0x2600 + (n) * 8)
42
43 #define MI_MATH (0x1a << 23)
44
45 #define MI_ALU_LOAD 0x080
46 #define MI_ALU_LOADINV 0x480
47 #define MI_ALU_LOAD0 0x081
48 #define MI_ALU_LOAD1 0x481
49 #define MI_ALU_ADD 0x100
50 #define MI_ALU_SUB 0x101
51 #define MI_ALU_AND 0x102
52 #define MI_ALU_OR 0x103
53 #define MI_ALU_XOR 0x104
54 #define MI_ALU_STORE 0x180
55 #define MI_ALU_STOREINV 0x580
56
57 #define MI_ALU_R0 0x00
58 #define MI_ALU_R1 0x01
59 #define MI_ALU_R2 0x02
60 #define MI_ALU_R3 0x03
61 #define MI_ALU_R4 0x04
62 #define MI_ALU_SRCA 0x20
63 #define MI_ALU_SRCB 0x21
64 #define MI_ALU_ACCU 0x31
65 #define MI_ALU_ZF 0x32
66 #define MI_ALU_CF 0x33
67
68 #define MI_ALU0(op) ((MI_ALU_##op << 20))
69 #define MI_ALU1(op, x) ((MI_ALU_##op << 20) | (MI_ALU_##x << 10)
70 #define MI_ALU2(op, x, y) \
71 ((MI_ALU_##op << 20) | (MI_ALU_##x << 10) | (MI_ALU_##y))
72
73 struct iris_query {
74 enum pipe_query_type type;
75
76 bool ready;
77
78 uint64_t result;
79
80 struct iris_bo *bo;
81 struct iris_query_snapshots *map;
82 };
83
84 struct iris_query_snapshots {
85 uint64_t start;
86 uint64_t end;
87 uint64_t snapshots_landed;
88 };
89
90 /**
91 * Is this type of query written by PIPE_CONTROL?
92 */
93 static bool
94 iris_is_query_pipelined(struct iris_query *q)
95 {
96 switch (q->type) {
97 case PIPE_QUERY_OCCLUSION_COUNTER:
98 case PIPE_QUERY_OCCLUSION_PREDICATE:
99 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
100 case PIPE_QUERY_TIMESTAMP:
101 case PIPE_QUERY_TIMESTAMP_DISJOINT:
102 case PIPE_QUERY_TIME_ELAPSED:
103 return true;
104
105 default:
106 return false;
107 }
108 }
109
110 static void
111 write_availability(struct iris_context *ice,
112 struct iris_query *q,
113 bool available)
114 {
115 struct iris_batch *batch = &ice->render_batch;
116 unsigned flags = PIPE_CONTROL_WRITE_IMMEDIATE;
117 unsigned offset = offsetof(struct iris_query_snapshots, snapshots_landed);
118
119 if (!iris_is_query_pipelined(q)) {
120 ice->vtbl.store_data_imm64(batch, q->bo, offset, available);
121 } else {
122 if (available) {
123 /* Order available *after* the query results. */
124 flags |= PIPE_CONTROL_FLUSH_ENABLE;
125 } else {
126 /* Make it unavailable *before* any pipelined reads. */
127 flags |= PIPE_CONTROL_CS_STALL;
128 }
129 iris_emit_pipe_control_write(batch, flags, q->bo, offset, available);
130 }
131 }
132
133 /**
134 * Write PS_DEPTH_COUNT to q->(dest) via a PIPE_CONTROL.
135 */
136 static void
137 iris_pipelined_write(struct iris_batch *batch,
138 struct iris_query *q,
139 enum pipe_control_flags flags,
140 unsigned offset)
141 {
142 const struct gen_device_info *devinfo = &batch->screen->devinfo;
143 const unsigned optional_cs_stall =
144 devinfo->gen == 9 && devinfo->gt == 4 ? PIPE_CONTROL_CS_STALL : 0;
145
146 iris_emit_pipe_control_write(batch, flags | optional_cs_stall,
147 q->bo, offset, 0ull);
148 }
149
150 static void
151 write_value(struct iris_context *ice, struct iris_query *q, unsigned offset)
152 {
153 iris_use_pinned_bo(&ice->render_batch, q->bo, true);
154
155 switch (q->type) {
156 case PIPE_QUERY_OCCLUSION_COUNTER:
157 case PIPE_QUERY_OCCLUSION_PREDICATE:
158 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
159 iris_pipelined_write(&ice->render_batch, q,
160 PIPE_CONTROL_WRITE_DEPTH_COUNT |
161 PIPE_CONTROL_DEPTH_STALL,
162 offset);
163 case PIPE_QUERY_TIME_ELAPSED:
164 iris_pipelined_write(&ice->render_batch, q,
165 PIPE_CONTROL_WRITE_TIMESTAMP,
166 offset);
167 break;
168 default:
169 assert(false);
170 }
171 }
172
173 static void
174 calculate_result_on_cpu(struct iris_query *q)
175 {
176 switch (q->type) {
177 case PIPE_QUERY_OCCLUSION_PREDICATE:
178 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
179 q->result = q->map->end != q->map->start;
180 break;
181 case PIPE_QUERY_OCCLUSION_COUNTER:
182 case PIPE_QUERY_TIME_ELAPSED:
183 case PIPE_QUERY_PRIMITIVES_GENERATED:
184 case PIPE_QUERY_PRIMITIVES_EMITTED:
185 default:
186 q->result = q->map->end - q->map->start;
187 break;
188 }
189
190 q->ready = true;
191 }
192
193 /**
194 * Calculate the result and store it to CS_GPR0.
195 */
196 static void
197 calculate_result_on_gpu(struct iris_context *ice, struct iris_query *q)
198 {
199 struct iris_batch *batch = &ice->render_batch;
200
201 ice->vtbl.load_register_mem64(batch, CS_GPR(1), q->bo,
202 offsetof(struct iris_query_snapshots, start));
203 ice->vtbl.load_register_mem64(batch, CS_GPR(2), q->bo,
204 offsetof(struct iris_query_snapshots, end));
205
206 static const uint32_t math[] = {
207 MI_MATH | (5 - 2),
208 MI_ALU2(LOAD, SRCA, R2),
209 MI_ALU2(LOAD, SRCB, R1),
210 MI_ALU0(SUB),
211 MI_ALU2(STORE, R0, ACCU),
212 };
213 iris_batch_emit(batch, math, sizeof(math));
214 }
215
216 static struct pipe_query *
217 iris_create_query(struct pipe_context *ctx,
218 unsigned query_type,
219 unsigned index)
220 {
221 struct iris_query *q = calloc(1, sizeof(struct iris_query));
222
223 q->type = query_type;
224
225 return (struct pipe_query *) q;
226 }
227
228 static void
229 iris_destroy_query(struct pipe_context *ctx, struct pipe_query *p_query)
230 {
231 struct iris_query *query = (void *) p_query;
232 iris_bo_unreference(query->bo);
233 free(query);
234 }
235
236
237 static boolean
238 iris_begin_query(struct pipe_context *ctx, struct pipe_query *query)
239 {
240 struct iris_screen *screen = (void *) ctx->screen;
241 struct iris_context *ice = (void *) ctx;
242 struct iris_query *q = (void *) query;
243
244 iris_bo_unreference(q->bo);
245 q->bo = iris_bo_alloc(screen->bufmgr, "query object", 4096,
246 IRIS_MEMZONE_OTHER);
247 if (!q->bo)
248 return false;
249
250 q->map = iris_bo_map(&ice->dbg, q->bo, MAP_READ | MAP_ASYNC);
251 if (!q->map)
252 return false;
253
254 q->result = 0ull;
255 q->ready = false;
256
257 write_availability(ice, q, false);
258 write_value(ice, q, offsetof(struct iris_query_snapshots, start));
259
260 return true;
261 }
262
263 static bool
264 iris_end_query(struct pipe_context *ctx, struct pipe_query *query)
265 {
266 struct iris_context *ice = (void *) ctx;
267 struct iris_query *q = (void *) query;
268
269 write_value(ice, q, offsetof(struct iris_query_snapshots, end));
270 write_availability(ice, q, true);
271
272 return true;
273 }
274
275 static boolean
276 iris_get_query_result(struct pipe_context *ctx,
277 struct pipe_query *query,
278 boolean wait,
279 union pipe_query_result *result)
280 {
281 struct iris_context *ice = (void *) ctx;
282 struct iris_query *q = (void *) query;
283
284 if (!q->ready) {
285 if (iris_batch_references(&ice->render_batch, q->bo))
286 iris_batch_flush(&ice->render_batch);
287
288 if (!q->map->snapshots_landed) {
289 if (wait)
290 iris_bo_wait_rendering(q->bo);
291 else
292 return false;
293 }
294
295 assert(q->map->snapshots_landed);
296 calculate_result_on_cpu(q);
297 }
298
299 assert(q->ready);
300 result->u64 = q->result;
301
302 return true;
303 }
304
305 static void
306 iris_get_query_result_resource(struct pipe_context *ctx,
307 struct pipe_query *query,
308 boolean wait,
309 enum pipe_query_value_type result_type,
310 int index,
311 struct pipe_resource *p_res,
312 unsigned offset)
313 {
314 struct iris_context *ice = (void *) ctx;
315 struct iris_query *q = (void *) query;
316 struct iris_batch *batch = &ice->render_batch;
317
318 if (!q->ready && q->map->snapshots_landed) {
319 /* The final snapshots happen to have landed, so let's just compute
320 * the result on the CPU now...
321 */
322 calculate_result_on_cpu(q);
323 }
324
325 if (q->ready) {
326 /* We happen to have the result on the CPU, so just copy it. */
327 if (result_type <= PIPE_QUERY_TYPE_U32) {
328 ice->vtbl.store_data_imm32(batch, iris_resource_bo(p_res), offset,
329 q->result);
330 } else {
331 ice->vtbl.store_data_imm64(batch, iris_resource_bo(p_res), offset,
332 q->result);
333 }
334 return;
335 }
336
337 /* Calculate the result to CS_GPR0 */
338 calculate_result_on_gpu(ice, q);
339
340 bool predicated = !wait && iris_is_query_pipelined(q);
341
342 if (predicated) {
343 ice->vtbl.load_register_imm64(batch, MI_PREDICATE_SRC1, 0ull);
344 ice->vtbl.load_register_mem64(batch, MI_PREDICATE_SRC0, q->bo,
345 offsetof(struct iris_query_snapshots,
346 snapshots_landed));
347 uint32_t predicate = MI_PREDICATE |
348 MI_PREDICATE_LOADOP_LOADINV |
349 MI_PREDICATE_COMBINEOP_SET |
350 MI_PREDICATE_COMPAREOP_SRCS_EQUAL;
351 iris_batch_emit(batch, &predicate, sizeof(uint32_t));
352 }
353
354 if (result_type <= PIPE_QUERY_TYPE_U32) {
355 ice->vtbl.store_register_mem32(batch, CS_GPR(0),
356 iris_resource_bo(p_res),
357 offset, predicated);
358 } else {
359 ice->vtbl.store_register_mem64(batch, CS_GPR(0),
360 iris_resource_bo(p_res),
361 offset, predicated);
362 }
363 }
364
365 static void
366 iris_set_active_query_state(struct pipe_context *pipe, boolean enable)
367 {
368 /* Do nothing, intentionally - only u_blitter uses this. */
369 }
370
371 void
372 iris_init_query_functions(struct pipe_context *ctx)
373 {
374 ctx->create_query = iris_create_query;
375 ctx->destroy_query = iris_destroy_query;
376 ctx->begin_query = iris_begin_query;
377 ctx->end_query = iris_end_query;
378 ctx->get_query_result = iris_get_query_result;
379 ctx->get_query_result_resource = iris_get_query_result_resource;
380 ctx->set_active_query_state = iris_set_active_query_state;
381 }