1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2017 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
12bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci */
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_ci/**
24bf215546Sopenharmony_ci * @file crocus_query.c
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci * ============================= GENXML CODE =============================
27bf215546Sopenharmony_ci *              [This file is compiled once per generation.]
28bf215546Sopenharmony_ci * =======================================================================
29bf215546Sopenharmony_ci *
30bf215546Sopenharmony_ci * Query object support.  This allows measuring various simple statistics
31bf215546Sopenharmony_ci * via counters on the GPU.  We use GenX code for MI_MATH calculations.
32bf215546Sopenharmony_ci */
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include <stdio.h>
35bf215546Sopenharmony_ci#include <errno.h>
36bf215546Sopenharmony_ci#include "perf/intel_perf.h"
37bf215546Sopenharmony_ci#include "pipe/p_defines.h"
38bf215546Sopenharmony_ci#include "pipe/p_state.h"
39bf215546Sopenharmony_ci#include "pipe/p_context.h"
40bf215546Sopenharmony_ci#include "pipe/p_screen.h"
41bf215546Sopenharmony_ci#include "util/u_inlines.h"
42bf215546Sopenharmony_ci#include "util/u_upload_mgr.h"
43bf215546Sopenharmony_ci#include "crocus_context.h"
44bf215546Sopenharmony_ci#include "crocus_defines.h"
45bf215546Sopenharmony_ci#include "crocus_fence.h"
46bf215546Sopenharmony_ci#include "crocus_monitor.h"
47bf215546Sopenharmony_ci#include "crocus_resource.h"
48bf215546Sopenharmony_ci#include "crocus_screen.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci#include "crocus_genx_macros.h"
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci#if GFX_VER == 6
53bf215546Sopenharmony_ci// TOOD: Add these to genxml?
54bf215546Sopenharmony_ci#define SO_PRIM_STORAGE_NEEDED(n) (0x2280)
55bf215546Sopenharmony_ci#define SO_NUM_PRIMS_WRITTEN(n)   (0x2288)
56bf215546Sopenharmony_ci
57bf215546Sopenharmony_ci// TODO: remove HS/DS/CS
58bf215546Sopenharmony_ci#define GFX6_IA_VERTICES_COUNT_num          0x2310
59bf215546Sopenharmony_ci#define GFX6_IA_PRIMITIVES_COUNT_num        0x2318
60bf215546Sopenharmony_ci#define GFX6_VS_INVOCATION_COUNT_num        0x2320
61bf215546Sopenharmony_ci#define GFX6_HS_INVOCATION_COUNT_num        0x2300
62bf215546Sopenharmony_ci#define GFX6_DS_INVOCATION_COUNT_num        0x2308
63bf215546Sopenharmony_ci#define GFX6_GS_INVOCATION_COUNT_num        0x2328
64bf215546Sopenharmony_ci#define GFX6_GS_PRIMITIVES_COUNT_num        0x2330
65bf215546Sopenharmony_ci#define GFX6_CL_INVOCATION_COUNT_num        0x2338
66bf215546Sopenharmony_ci#define GFX6_CL_PRIMITIVES_COUNT_num        0x2340
67bf215546Sopenharmony_ci#define GFX6_PS_INVOCATION_COUNT_num        0x2348
68bf215546Sopenharmony_ci#define GFX6_CS_INVOCATION_COUNT_num        0x2290
69bf215546Sopenharmony_ci#define GFX6_PS_DEPTH_COUNT_num             0x2350
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci#elif GFX_VER >= 7
72bf215546Sopenharmony_ci#define SO_PRIM_STORAGE_NEEDED(n) (GENX(SO_PRIM_STORAGE_NEEDED0_num) + (n) * 8)
73bf215546Sopenharmony_ci#define SO_NUM_PRIMS_WRITTEN(n)   (GENX(SO_NUM_PRIMS_WRITTEN0_num) + (n) * 8)
74bf215546Sopenharmony_ci#endif
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_cistruct crocus_query {
77bf215546Sopenharmony_ci   struct threaded_query b;
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci   enum pipe_query_type type;
80bf215546Sopenharmony_ci   int index;
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci   bool ready;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_ci   bool stalled;
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   uint64_t result;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci   struct crocus_state_ref query_state_ref;
89bf215546Sopenharmony_ci   struct crocus_query_snapshots *map;
90bf215546Sopenharmony_ci   struct crocus_syncobj *syncobj;
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   int batch_idx;
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   struct crocus_monitor_object *monitor;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   /* Fence for PIPE_QUERY_GPU_FINISHED. */
97bf215546Sopenharmony_ci   struct pipe_fence_handle *fence;
98bf215546Sopenharmony_ci};
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_cistruct crocus_query_snapshots {
101bf215546Sopenharmony_ci   /** crocus_render_condition's saved MI_PREDICATE_RESULT value. */
102bf215546Sopenharmony_ci   uint64_t predicate_result;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   /** Have the start/end snapshots landed? */
105bf215546Sopenharmony_ci   uint64_t snapshots_landed;
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   /** Starting and ending counter snapshots */
108bf215546Sopenharmony_ci   uint64_t start;
109bf215546Sopenharmony_ci   uint64_t end;
110bf215546Sopenharmony_ci};
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_cistruct crocus_query_so_overflow {
113bf215546Sopenharmony_ci   uint64_t predicate_result;
114bf215546Sopenharmony_ci   uint64_t snapshots_landed;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   struct {
117bf215546Sopenharmony_ci      uint64_t prim_storage_needed[2];
118bf215546Sopenharmony_ci      uint64_t num_prims[2];
119bf215546Sopenharmony_ci   } stream[4];
120bf215546Sopenharmony_ci};
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci#if GFX_VERx10 >= 75
123bf215546Sopenharmony_cistatic struct mi_value
124bf215546Sopenharmony_ciquery_mem64(struct crocus_query *q, uint32_t offset)
125bf215546Sopenharmony_ci{
126bf215546Sopenharmony_ci   return mi_mem64(rw_bo(crocus_resource_bo(q->query_state_ref.res),
127bf215546Sopenharmony_ci                         q->query_state_ref.offset + offset));
128bf215546Sopenharmony_ci}
129bf215546Sopenharmony_ci#endif
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci/**
132bf215546Sopenharmony_ci * Is this type of query written by PIPE_CONTROL?
133bf215546Sopenharmony_ci */
134bf215546Sopenharmony_cistatic bool
135bf215546Sopenharmony_cicrocus_is_query_pipelined(struct crocus_query *q)
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci   switch (q->type) {
138bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_COUNTER:
139bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE:
140bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
141bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP:
142bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP_DISJOINT:
143bf215546Sopenharmony_ci   case PIPE_QUERY_TIME_ELAPSED:
144bf215546Sopenharmony_ci      return true;
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci   default:
147bf215546Sopenharmony_ci      return false;
148bf215546Sopenharmony_ci   }
149bf215546Sopenharmony_ci}
150bf215546Sopenharmony_ci
151bf215546Sopenharmony_cistatic void
152bf215546Sopenharmony_cimark_available(struct crocus_context *ice, struct crocus_query *q)
153bf215546Sopenharmony_ci{
154bf215546Sopenharmony_ci#if GFX_VERx10 >= 75
155bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[q->batch_idx];
156bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
157bf215546Sopenharmony_ci   unsigned flags = PIPE_CONTROL_WRITE_IMMEDIATE;
158bf215546Sopenharmony_ci   unsigned offset = offsetof(struct crocus_query_snapshots, snapshots_landed);
159bf215546Sopenharmony_ci   struct crocus_bo *bo = crocus_resource_bo(q->query_state_ref.res);
160bf215546Sopenharmony_ci   offset += q->query_state_ref.offset;
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci   if (!crocus_is_query_pipelined(q)) {
163bf215546Sopenharmony_ci      screen->vtbl.store_data_imm64(batch, bo, offset, true);
164bf215546Sopenharmony_ci   } else {
165bf215546Sopenharmony_ci      /* Order available *after* the query results. */
166bf215546Sopenharmony_ci      flags |= PIPE_CONTROL_FLUSH_ENABLE;
167bf215546Sopenharmony_ci      crocus_emit_pipe_control_write(batch, "query: mark available",
168bf215546Sopenharmony_ci                                     flags, bo, offset, true);
169bf215546Sopenharmony_ci   }
170bf215546Sopenharmony_ci#endif
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci/**
174bf215546Sopenharmony_ci * Write PS_DEPTH_COUNT to q->(dest) via a PIPE_CONTROL.
175bf215546Sopenharmony_ci */
176bf215546Sopenharmony_cistatic void
177bf215546Sopenharmony_cicrocus_pipelined_write(struct crocus_batch *batch,
178bf215546Sopenharmony_ci                       struct crocus_query *q,
179bf215546Sopenharmony_ci                       enum pipe_control_flags flags,
180bf215546Sopenharmony_ci                       unsigned offset)
181bf215546Sopenharmony_ci{
182bf215546Sopenharmony_ci   struct crocus_bo *bo = crocus_resource_bo(q->query_state_ref.res);
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   crocus_emit_pipe_control_write(batch, "query: pipelined snapshot write",
185bf215546Sopenharmony_ci                                  flags,
186bf215546Sopenharmony_ci                                  bo, offset, 0ull);
187bf215546Sopenharmony_ci}
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_cistatic void
190bf215546Sopenharmony_ciwrite_value(struct crocus_context *ice, struct crocus_query *q, unsigned offset)
191bf215546Sopenharmony_ci{
192bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[q->batch_idx];
193bf215546Sopenharmony_ci#if GFX_VER >= 6
194bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
195bf215546Sopenharmony_ci   struct crocus_bo *bo = crocus_resource_bo(q->query_state_ref.res);
196bf215546Sopenharmony_ci#endif
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   if (!crocus_is_query_pipelined(q)) {
199bf215546Sopenharmony_ci      crocus_emit_pipe_control_flush(batch,
200bf215546Sopenharmony_ci                                     "query: non-pipelined snapshot write",
201bf215546Sopenharmony_ci                                     PIPE_CONTROL_CS_STALL |
202bf215546Sopenharmony_ci                                     PIPE_CONTROL_STALL_AT_SCOREBOARD);
203bf215546Sopenharmony_ci      q->stalled = true;
204bf215546Sopenharmony_ci   }
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   switch (q->type) {
207bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_COUNTER:
208bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE:
209bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
210bf215546Sopenharmony_ci      crocus_pipelined_write(&ice->batches[CROCUS_BATCH_RENDER], q,
211bf215546Sopenharmony_ci                             PIPE_CONTROL_WRITE_DEPTH_COUNT |
212bf215546Sopenharmony_ci                             PIPE_CONTROL_DEPTH_STALL,
213bf215546Sopenharmony_ci                             offset);
214bf215546Sopenharmony_ci      break;
215bf215546Sopenharmony_ci   case PIPE_QUERY_TIME_ELAPSED:
216bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP:
217bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP_DISJOINT:
218bf215546Sopenharmony_ci      crocus_pipelined_write(&ice->batches[CROCUS_BATCH_RENDER], q,
219bf215546Sopenharmony_ci                             PIPE_CONTROL_WRITE_TIMESTAMP,
220bf215546Sopenharmony_ci                             offset);
221bf215546Sopenharmony_ci      break;
222bf215546Sopenharmony_ci   case PIPE_QUERY_PRIMITIVES_GENERATED:
223bf215546Sopenharmony_ci#if GFX_VER >= 6
224bf215546Sopenharmony_ci      screen->vtbl.store_register_mem64(batch,
225bf215546Sopenharmony_ci                                        q->index == 0 ?
226bf215546Sopenharmony_ci                                        GENX(CL_INVOCATION_COUNT_num) :
227bf215546Sopenharmony_ci                                        SO_PRIM_STORAGE_NEEDED(q->index),
228bf215546Sopenharmony_ci                                        bo, offset, false);
229bf215546Sopenharmony_ci#endif
230bf215546Sopenharmony_ci      break;
231bf215546Sopenharmony_ci   case PIPE_QUERY_PRIMITIVES_EMITTED:
232bf215546Sopenharmony_ci#if GFX_VER >= 6
233bf215546Sopenharmony_ci      screen->vtbl.store_register_mem64(batch,
234bf215546Sopenharmony_ci                                        SO_NUM_PRIMS_WRITTEN(q->index),
235bf215546Sopenharmony_ci                                        bo, offset, false);
236bf215546Sopenharmony_ci#endif
237bf215546Sopenharmony_ci      break;
238bf215546Sopenharmony_ci   case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE: {
239bf215546Sopenharmony_ci#if GFX_VER >= 6
240bf215546Sopenharmony_ci      static const uint32_t index_to_reg[] = {
241bf215546Sopenharmony_ci         GENX(IA_VERTICES_COUNT_num),
242bf215546Sopenharmony_ci         GENX(IA_PRIMITIVES_COUNT_num),
243bf215546Sopenharmony_ci         GENX(VS_INVOCATION_COUNT_num),
244bf215546Sopenharmony_ci         GENX(GS_INVOCATION_COUNT_num),
245bf215546Sopenharmony_ci         GENX(GS_PRIMITIVES_COUNT_num),
246bf215546Sopenharmony_ci         GENX(CL_INVOCATION_COUNT_num),
247bf215546Sopenharmony_ci         GENX(CL_PRIMITIVES_COUNT_num),
248bf215546Sopenharmony_ci         GENX(PS_INVOCATION_COUNT_num),
249bf215546Sopenharmony_ci         GENX(HS_INVOCATION_COUNT_num),
250bf215546Sopenharmony_ci         GENX(DS_INVOCATION_COUNT_num),
251bf215546Sopenharmony_ci         GENX(CS_INVOCATION_COUNT_num),
252bf215546Sopenharmony_ci      };
253bf215546Sopenharmony_ci      uint32_t reg = index_to_reg[q->index];
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci#if GFX_VER == 6
256bf215546Sopenharmony_ci      /* Gfx6 GS code counts full primitives, that is, it won't count individual
257bf215546Sopenharmony_ci       * triangles in a triangle strip. Use CL_INVOCATION_COUNT for that.
258bf215546Sopenharmony_ci       */
259bf215546Sopenharmony_ci      if (q->index == PIPE_STAT_QUERY_GS_PRIMITIVES)
260bf215546Sopenharmony_ci         reg = GENX(CL_INVOCATION_COUNT_num);
261bf215546Sopenharmony_ci#endif
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci      screen->vtbl.store_register_mem64(batch, reg, bo, offset, false);
264bf215546Sopenharmony_ci#endif
265bf215546Sopenharmony_ci      break;
266bf215546Sopenharmony_ci   }
267bf215546Sopenharmony_ci   default:
268bf215546Sopenharmony_ci      assert(false);
269bf215546Sopenharmony_ci   }
270bf215546Sopenharmony_ci}
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci#if GFX_VER >= 6
273bf215546Sopenharmony_cistatic void
274bf215546Sopenharmony_ciwrite_overflow_values(struct crocus_context *ice, struct crocus_query *q, bool end)
275bf215546Sopenharmony_ci{
276bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
277bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
278bf215546Sopenharmony_ci   uint32_t count = q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ? 1 : 4;
279bf215546Sopenharmony_ci   struct crocus_bo *bo = crocus_resource_bo(q->query_state_ref.res);
280bf215546Sopenharmony_ci   uint32_t offset = q->query_state_ref.offset;
281bf215546Sopenharmony_ci   crocus_emit_pipe_control_flush(batch,
282bf215546Sopenharmony_ci                                  "query: write SO overflow snapshots",
283bf215546Sopenharmony_ci                                  PIPE_CONTROL_CS_STALL |
284bf215546Sopenharmony_ci                                  PIPE_CONTROL_STALL_AT_SCOREBOARD);
285bf215546Sopenharmony_ci   for (uint32_t i = 0; i < count; i++) {
286bf215546Sopenharmony_ci      int s = q->index + i;
287bf215546Sopenharmony_ci      int g_idx = offset + offsetof(struct crocus_query_so_overflow,
288bf215546Sopenharmony_ci                                    stream[s].num_prims[end]);
289bf215546Sopenharmony_ci      int w_idx = offset + offsetof(struct crocus_query_so_overflow,
290bf215546Sopenharmony_ci                                    stream[s].prim_storage_needed[end]);
291bf215546Sopenharmony_ci      screen->vtbl.store_register_mem64(batch, SO_NUM_PRIMS_WRITTEN(s),
292bf215546Sopenharmony_ci                                        bo, g_idx, false);
293bf215546Sopenharmony_ci      screen->vtbl.store_register_mem64(batch, SO_PRIM_STORAGE_NEEDED(s),
294bf215546Sopenharmony_ci                                        bo, w_idx, false);
295bf215546Sopenharmony_ci   }
296bf215546Sopenharmony_ci}
297bf215546Sopenharmony_ci#endif
298bf215546Sopenharmony_cistatic uint64_t
299bf215546Sopenharmony_cicrocus_raw_timestamp_delta(uint64_t time0, uint64_t time1)
300bf215546Sopenharmony_ci{
301bf215546Sopenharmony_ci   if (time0 > time1) {
302bf215546Sopenharmony_ci      return (1ULL << TIMESTAMP_BITS) + time1 - time0;
303bf215546Sopenharmony_ci   } else {
304bf215546Sopenharmony_ci      return time1 - time0;
305bf215546Sopenharmony_ci   }
306bf215546Sopenharmony_ci}
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_cistatic bool
309bf215546Sopenharmony_cistream_overflowed(struct crocus_query_so_overflow *so, int s)
310bf215546Sopenharmony_ci{
311bf215546Sopenharmony_ci   return (so->stream[s].prim_storage_needed[1] -
312bf215546Sopenharmony_ci           so->stream[s].prim_storage_needed[0]) !=
313bf215546Sopenharmony_ci          (so->stream[s].num_prims[1] - so->stream[s].num_prims[0]);
314bf215546Sopenharmony_ci}
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_cistatic void
317bf215546Sopenharmony_cicalculate_result_on_cpu(const struct intel_device_info *devinfo,
318bf215546Sopenharmony_ci                        struct crocus_query *q)
319bf215546Sopenharmony_ci{
320bf215546Sopenharmony_ci   switch (q->type) {
321bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE:
322bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
323bf215546Sopenharmony_ci      q->result = q->map->end != q->map->start;
324bf215546Sopenharmony_ci      break;
325bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP:
326bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP_DISJOINT:
327bf215546Sopenharmony_ci      /* The timestamp is the single starting snapshot. */
328bf215546Sopenharmony_ci      q->result = intel_device_info_timebase_scale(devinfo, q->map->start);
329bf215546Sopenharmony_ci      q->result &= (1ull << TIMESTAMP_BITS) - 1;
330bf215546Sopenharmony_ci      break;
331bf215546Sopenharmony_ci   case PIPE_QUERY_TIME_ELAPSED:
332bf215546Sopenharmony_ci      q->result = crocus_raw_timestamp_delta(q->map->start, q->map->end);
333bf215546Sopenharmony_ci      q->result = intel_device_info_timebase_scale(devinfo, q->result);
334bf215546Sopenharmony_ci      q->result &= (1ull << TIMESTAMP_BITS) - 1;
335bf215546Sopenharmony_ci      break;
336bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
337bf215546Sopenharmony_ci      q->result = stream_overflowed((void *) q->map, q->index);
338bf215546Sopenharmony_ci      break;
339bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
340bf215546Sopenharmony_ci      q->result = false;
341bf215546Sopenharmony_ci      for (int i = 0; i < PIPE_MAX_VERTEX_STREAMS; i++)
342bf215546Sopenharmony_ci         q->result |= stream_overflowed((void *) q->map, i);
343bf215546Sopenharmony_ci      break;
344bf215546Sopenharmony_ci   case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
345bf215546Sopenharmony_ci      q->result = q->map->end - q->map->start;
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci      /* WaDividePSInvocationCountBy4:HSW,BDW */
348bf215546Sopenharmony_ci      if (GFX_VERx10 >= 75 && q->index == PIPE_STAT_QUERY_PS_INVOCATIONS)
349bf215546Sopenharmony_ci         q->result /= 4;
350bf215546Sopenharmony_ci      break;
351bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_COUNTER:
352bf215546Sopenharmony_ci   case PIPE_QUERY_PRIMITIVES_GENERATED:
353bf215546Sopenharmony_ci   case PIPE_QUERY_PRIMITIVES_EMITTED:
354bf215546Sopenharmony_ci   default:
355bf215546Sopenharmony_ci      q->result = q->map->end - q->map->start;
356bf215546Sopenharmony_ci      break;
357bf215546Sopenharmony_ci   }
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   q->ready = true;
360bf215546Sopenharmony_ci}
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci#if GFX_VERx10 >= 75
363bf215546Sopenharmony_ci/**
364bf215546Sopenharmony_ci * Calculate the streamout overflow for stream \p idx:
365bf215546Sopenharmony_ci *
366bf215546Sopenharmony_ci * (num_prims[1] - num_prims[0]) - (storage_needed[1] - storage_needed[0])
367bf215546Sopenharmony_ci */
368bf215546Sopenharmony_cistatic struct mi_value
369bf215546Sopenharmony_cicalc_overflow_for_stream(struct mi_builder *b,
370bf215546Sopenharmony_ci                         struct crocus_query *q,
371bf215546Sopenharmony_ci                         int idx)
372bf215546Sopenharmony_ci{
373bf215546Sopenharmony_ci#define C(counter, i) query_mem64(q, \
374bf215546Sopenharmony_ci   offsetof(struct crocus_query_so_overflow, stream[idx].counter[i]))
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci   return mi_isub(b, mi_isub(b, C(num_prims, 1), C(num_prims, 0)),
377bf215546Sopenharmony_ci                  mi_isub(b, C(prim_storage_needed, 1),
378bf215546Sopenharmony_ci                          C(prim_storage_needed, 0)));
379bf215546Sopenharmony_ci#undef C
380bf215546Sopenharmony_ci}
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci/**
383bf215546Sopenharmony_ci * Calculate whether any stream has overflowed.
384bf215546Sopenharmony_ci */
385bf215546Sopenharmony_cistatic struct mi_value
386bf215546Sopenharmony_cicalc_overflow_any_stream(struct mi_builder *b, struct crocus_query *q)
387bf215546Sopenharmony_ci{
388bf215546Sopenharmony_ci   struct mi_value stream_result[PIPE_MAX_VERTEX_STREAMS];
389bf215546Sopenharmony_ci   for (int i = 0; i < PIPE_MAX_VERTEX_STREAMS; i++)
390bf215546Sopenharmony_ci      stream_result[i] = calc_overflow_for_stream(b, q, i);
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_ci   struct mi_value result = stream_result[0];
393bf215546Sopenharmony_ci   for (int i = 1; i < PIPE_MAX_VERTEX_STREAMS; i++)
394bf215546Sopenharmony_ci      result = mi_ior(b, result, stream_result[i]);
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci   return result;
397bf215546Sopenharmony_ci}
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_cistatic bool
401bf215546Sopenharmony_ciquery_is_boolean(enum pipe_query_type type)
402bf215546Sopenharmony_ci{
403bf215546Sopenharmony_ci   switch (type) {
404bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE:
405bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
406bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
407bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
408bf215546Sopenharmony_ci      return true;
409bf215546Sopenharmony_ci   default:
410bf215546Sopenharmony_ci      return false;
411bf215546Sopenharmony_ci   }
412bf215546Sopenharmony_ci}
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci/**
415bf215546Sopenharmony_ci * Calculate the result using MI_MATH.
416bf215546Sopenharmony_ci */
417bf215546Sopenharmony_cistatic struct mi_value
418bf215546Sopenharmony_cicalculate_result_on_gpu(const struct intel_device_info *devinfo,
419bf215546Sopenharmony_ci                        struct mi_builder *b,
420bf215546Sopenharmony_ci                        struct crocus_query *q)
421bf215546Sopenharmony_ci{
422bf215546Sopenharmony_ci   struct mi_value result;
423bf215546Sopenharmony_ci   struct mi_value start_val =
424bf215546Sopenharmony_ci      query_mem64(q, offsetof(struct crocus_query_snapshots, start));
425bf215546Sopenharmony_ci   struct mi_value end_val =
426bf215546Sopenharmony_ci      query_mem64(q, offsetof(struct crocus_query_snapshots, end));
427bf215546Sopenharmony_ci
428bf215546Sopenharmony_ci   switch (q->type) {
429bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
430bf215546Sopenharmony_ci      result = calc_overflow_for_stream(b, q, q->index);
431bf215546Sopenharmony_ci      break;
432bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
433bf215546Sopenharmony_ci      result = calc_overflow_any_stream(b, q);
434bf215546Sopenharmony_ci      break;
435bf215546Sopenharmony_ci   case PIPE_QUERY_TIMESTAMP: {
436bf215546Sopenharmony_ci      /* TODO: This discards any fractional bits of the timebase scale.
437bf215546Sopenharmony_ci       * We would need to do a bit of fixed point math on the CS ALU, or
438bf215546Sopenharmony_ci       * launch an actual shader to calculate this with full precision.
439bf215546Sopenharmony_ci       */
440bf215546Sopenharmony_ci      uint32_t scale = 1000000000ull / devinfo->timestamp_frequency;
441bf215546Sopenharmony_ci      result = mi_iand(b, mi_imm((1ull << 36) - 1),
442bf215546Sopenharmony_ci                       mi_imul_imm(b, start_val, scale));
443bf215546Sopenharmony_ci      break;
444bf215546Sopenharmony_ci   }
445bf215546Sopenharmony_ci   case PIPE_QUERY_TIME_ELAPSED: {
446bf215546Sopenharmony_ci      /* TODO: This discards fractional bits (see above). */
447bf215546Sopenharmony_ci      uint32_t scale = 1000000000ull / devinfo->timestamp_frequency;
448bf215546Sopenharmony_ci      result = mi_imul_imm(b, mi_isub(b, end_val, start_val), scale);
449bf215546Sopenharmony_ci      break;
450bf215546Sopenharmony_ci   }
451bf215546Sopenharmony_ci   default:
452bf215546Sopenharmony_ci      result = mi_isub(b, end_val, start_val);
453bf215546Sopenharmony_ci      break;
454bf215546Sopenharmony_ci   }
455bf215546Sopenharmony_ci   /* WaDividePSInvocationCountBy4:HSW,BDW */
456bf215546Sopenharmony_ci   if (GFX_VERx10 >= 75 &&
457bf215546Sopenharmony_ci       q->type == PIPE_QUERY_PIPELINE_STATISTICS_SINGLE &&
458bf215546Sopenharmony_ci       q->index == PIPE_STAT_QUERY_PS_INVOCATIONS)
459bf215546Sopenharmony_ci      result = mi_ushr32_imm(b, result, 2);
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci   if (query_is_boolean(q->type))
462bf215546Sopenharmony_ci      result = mi_iand(b, mi_nz(b, result), mi_imm(1));
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_ci   return result;
465bf215546Sopenharmony_ci}
466bf215546Sopenharmony_ci#endif
467bf215546Sopenharmony_ci
468bf215546Sopenharmony_cistatic struct pipe_query *
469bf215546Sopenharmony_cicrocus_create_query(struct pipe_context *ctx,
470bf215546Sopenharmony_ci                    unsigned query_type,
471bf215546Sopenharmony_ci                    unsigned index)
472bf215546Sopenharmony_ci{
473bf215546Sopenharmony_ci   struct crocus_query *q = calloc(1, sizeof(struct crocus_query));
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci   q->type = query_type;
476bf215546Sopenharmony_ci   q->index = index;
477bf215546Sopenharmony_ci   q->monitor = NULL;
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_PIPELINE_STATISTICS_SINGLE &&
480bf215546Sopenharmony_ci       q->index == PIPE_STAT_QUERY_CS_INVOCATIONS)
481bf215546Sopenharmony_ci      q->batch_idx = CROCUS_BATCH_COMPUTE;
482bf215546Sopenharmony_ci   else
483bf215546Sopenharmony_ci      q->batch_idx = CROCUS_BATCH_RENDER;
484bf215546Sopenharmony_ci   return (struct pipe_query *) q;
485bf215546Sopenharmony_ci}
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_cistatic struct pipe_query *
488bf215546Sopenharmony_cicrocus_create_batch_query(struct pipe_context *ctx,
489bf215546Sopenharmony_ci                          unsigned num_queries,
490bf215546Sopenharmony_ci                          unsigned *query_types)
491bf215546Sopenharmony_ci{
492bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
493bf215546Sopenharmony_ci   struct crocus_query *q = calloc(1, sizeof(struct crocus_query));
494bf215546Sopenharmony_ci   if (unlikely(!q))
495bf215546Sopenharmony_ci      return NULL;
496bf215546Sopenharmony_ci   q->type = PIPE_QUERY_DRIVER_SPECIFIC;
497bf215546Sopenharmony_ci   q->index = -1;
498bf215546Sopenharmony_ci   q->monitor = crocus_create_monitor_object(ice, num_queries, query_types);
499bf215546Sopenharmony_ci   if (unlikely(!q->monitor)) {
500bf215546Sopenharmony_ci      free(q);
501bf215546Sopenharmony_ci      return NULL;
502bf215546Sopenharmony_ci   }
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci   return (struct pipe_query *) q;
505bf215546Sopenharmony_ci}
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_cistatic void
508bf215546Sopenharmony_cicrocus_destroy_query(struct pipe_context *ctx, struct pipe_query *p_query)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci   struct crocus_query *query = (void *) p_query;
511bf215546Sopenharmony_ci   struct crocus_screen *screen = (void *) ctx->screen;
512bf215546Sopenharmony_ci   if (query->monitor) {
513bf215546Sopenharmony_ci      crocus_destroy_monitor_object(ctx, query->monitor);
514bf215546Sopenharmony_ci      query->monitor = NULL;
515bf215546Sopenharmony_ci   } else {
516bf215546Sopenharmony_ci      crocus_syncobj_reference(screen, &query->syncobj, NULL);
517bf215546Sopenharmony_ci      screen->base.fence_reference(ctx->screen, &query->fence, NULL);
518bf215546Sopenharmony_ci   }
519bf215546Sopenharmony_ci   pipe_resource_reference(&query->query_state_ref.res, NULL);
520bf215546Sopenharmony_ci   free(query);
521bf215546Sopenharmony_ci}
522bf215546Sopenharmony_ci
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_cistatic bool
525bf215546Sopenharmony_cicrocus_begin_query(struct pipe_context *ctx, struct pipe_query *query)
526bf215546Sopenharmony_ci{
527bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
528bf215546Sopenharmony_ci   struct crocus_query *q = (void *) query;
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_ci   if (q->monitor)
531bf215546Sopenharmony_ci      return crocus_begin_monitor(ctx, q->monitor);
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci   void *ptr = NULL;
534bf215546Sopenharmony_ci   uint32_t size;
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
537bf215546Sopenharmony_ci       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE)
538bf215546Sopenharmony_ci      size = sizeof(struct crocus_query_so_overflow);
539bf215546Sopenharmony_ci   else
540bf215546Sopenharmony_ci      size = sizeof(struct crocus_query_snapshots);
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci   u_upload_alloc(ice->query_buffer_uploader, 0,
543bf215546Sopenharmony_ci                  size, size, &q->query_state_ref.offset,
544bf215546Sopenharmony_ci                  &q->query_state_ref.res, &ptr);
545bf215546Sopenharmony_ci
546bf215546Sopenharmony_ci   if (!q->query_state_ref.res)
547bf215546Sopenharmony_ci      return false;
548bf215546Sopenharmony_ci   if (!crocus_resource_bo(q->query_state_ref.res))
549bf215546Sopenharmony_ci      return false;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci   q->map = ptr;
552bf215546Sopenharmony_ci   if (!q->map)
553bf215546Sopenharmony_ci      return false;
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci   q->result = 0ull;
556bf215546Sopenharmony_ci   q->ready = false;
557bf215546Sopenharmony_ci   WRITE_ONCE(q->map->snapshots_landed, false);
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_PRIMITIVES_GENERATED && q->index == 0) {
560bf215546Sopenharmony_ci      ice->state.prims_generated_query_active = true;
561bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_DIRTY_STREAMOUT | CROCUS_DIRTY_CLIP;
562bf215546Sopenharmony_ci   }
563bf215546Sopenharmony_ci
564bf215546Sopenharmony_ci#if GFX_VER <= 5
565bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_OCCLUSION_COUNTER ||
566bf215546Sopenharmony_ci       q->type == PIPE_QUERY_OCCLUSION_PREDICATE) {
567bf215546Sopenharmony_ci      ice->state.stats_wm++;
568bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_DIRTY_WM | CROCUS_DIRTY_COLOR_CALC_STATE;
569bf215546Sopenharmony_ci   }
570bf215546Sopenharmony_ci#endif
571bf215546Sopenharmony_ci#if GFX_VER >= 6
572bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
573bf215546Sopenharmony_ci       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE)
574bf215546Sopenharmony_ci      write_overflow_values(ice, q, false);
575bf215546Sopenharmony_ci   else
576bf215546Sopenharmony_ci#endif
577bf215546Sopenharmony_ci      write_value(ice, q,
578bf215546Sopenharmony_ci                  q->query_state_ref.offset +
579bf215546Sopenharmony_ci                  offsetof(struct crocus_query_snapshots, start));
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_ci   return true;
582bf215546Sopenharmony_ci}
583bf215546Sopenharmony_ci
584bf215546Sopenharmony_cistatic bool
585bf215546Sopenharmony_cicrocus_end_query(struct pipe_context *ctx, struct pipe_query *query)
586bf215546Sopenharmony_ci{
587bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
588bf215546Sopenharmony_ci   struct crocus_query *q = (void *) query;
589bf215546Sopenharmony_ci
590bf215546Sopenharmony_ci   if (q->monitor)
591bf215546Sopenharmony_ci      return crocus_end_monitor(ctx, q->monitor);
592bf215546Sopenharmony_ci
593bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_GPU_FINISHED) {
594bf215546Sopenharmony_ci      ctx->flush(ctx, &q->fence, PIPE_FLUSH_DEFERRED);
595bf215546Sopenharmony_ci      return true;
596bf215546Sopenharmony_ci   }
597bf215546Sopenharmony_ci
598bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[q->batch_idx];
599bf215546Sopenharmony_ci
600bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_TIMESTAMP) {
601bf215546Sopenharmony_ci      crocus_begin_query(ctx, query);
602bf215546Sopenharmony_ci      crocus_batch_reference_signal_syncobj(batch, &q->syncobj);
603bf215546Sopenharmony_ci      mark_available(ice, q);
604bf215546Sopenharmony_ci      return true;
605bf215546Sopenharmony_ci   }
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci#if GFX_VER <= 5
608bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_OCCLUSION_COUNTER ||
609bf215546Sopenharmony_ci       q->type == PIPE_QUERY_OCCLUSION_PREDICATE) {
610bf215546Sopenharmony_ci      ice->state.stats_wm--;
611bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_DIRTY_WM | CROCUS_DIRTY_COLOR_CALC_STATE;
612bf215546Sopenharmony_ci   }
613bf215546Sopenharmony_ci#endif
614bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_PRIMITIVES_GENERATED && q->index == 0) {
615bf215546Sopenharmony_ci      ice->state.prims_generated_query_active = false;
616bf215546Sopenharmony_ci      ice->state.dirty |= CROCUS_DIRTY_STREAMOUT | CROCUS_DIRTY_CLIP;
617bf215546Sopenharmony_ci   }
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci#if GFX_VER >= 6
620bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
621bf215546Sopenharmony_ci       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE)
622bf215546Sopenharmony_ci      write_overflow_values(ice, q, true);
623bf215546Sopenharmony_ci   else
624bf215546Sopenharmony_ci#endif
625bf215546Sopenharmony_ci      write_value(ice, q,
626bf215546Sopenharmony_ci                  q->query_state_ref.offset +
627bf215546Sopenharmony_ci                  offsetof(struct crocus_query_snapshots, end));
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci   crocus_batch_reference_signal_syncobj(batch, &q->syncobj);
630bf215546Sopenharmony_ci   mark_available(ice, q);
631bf215546Sopenharmony_ci
632bf215546Sopenharmony_ci   return true;
633bf215546Sopenharmony_ci}
634bf215546Sopenharmony_ci
635bf215546Sopenharmony_ci/**
636bf215546Sopenharmony_ci * See if the snapshots have landed for a query, and if so, compute the
637bf215546Sopenharmony_ci * result and mark it ready.  Does not flush (unlike crocus_get_query_result).
638bf215546Sopenharmony_ci */
639bf215546Sopenharmony_cistatic void
640bf215546Sopenharmony_cicrocus_check_query_no_flush(struct crocus_context *ice, struct crocus_query *q)
641bf215546Sopenharmony_ci{
642bf215546Sopenharmony_ci   struct crocus_screen *screen = (void *) ice->ctx.screen;
643bf215546Sopenharmony_ci   const struct intel_device_info *devinfo = &screen->devinfo;
644bf215546Sopenharmony_ci
645bf215546Sopenharmony_ci   if (!q->ready && READ_ONCE(q->map->snapshots_landed)) {
646bf215546Sopenharmony_ci      calculate_result_on_cpu(devinfo, q);
647bf215546Sopenharmony_ci   }
648bf215546Sopenharmony_ci}
649bf215546Sopenharmony_ci
650bf215546Sopenharmony_cistatic bool
651bf215546Sopenharmony_cicrocus_get_query_result(struct pipe_context *ctx,
652bf215546Sopenharmony_ci                        struct pipe_query *query,
653bf215546Sopenharmony_ci                        bool wait,
654bf215546Sopenharmony_ci                        union pipe_query_result *result)
655bf215546Sopenharmony_ci{
656bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
657bf215546Sopenharmony_ci   struct crocus_query *q = (void *) query;
658bf215546Sopenharmony_ci
659bf215546Sopenharmony_ci   if (q->monitor)
660bf215546Sopenharmony_ci      return crocus_get_monitor_result(ctx, q->monitor, wait, result->batch);
661bf215546Sopenharmony_ci
662bf215546Sopenharmony_ci   struct crocus_screen *screen = (void *) ctx->screen;
663bf215546Sopenharmony_ci   const struct intel_device_info *devinfo = &screen->devinfo;
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci   if (unlikely(screen->devinfo.no_hw)) {
666bf215546Sopenharmony_ci      result->u64 = 0;
667bf215546Sopenharmony_ci      return true;
668bf215546Sopenharmony_ci   }
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci   if (!q->ready) {
671bf215546Sopenharmony_ci      struct crocus_batch *batch = &ice->batches[q->batch_idx];
672bf215546Sopenharmony_ci      if (q->syncobj == crocus_batch_get_signal_syncobj(batch))
673bf215546Sopenharmony_ci         crocus_batch_flush(batch);
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci#if GFX_VERx10 >= 75
676bf215546Sopenharmony_ci      while (!READ_ONCE(q->map->snapshots_landed)) {
677bf215546Sopenharmony_ci         if (wait)
678bf215546Sopenharmony_ci            crocus_wait_syncobj(ctx->screen, q->syncobj, INT64_MAX);
679bf215546Sopenharmony_ci         else
680bf215546Sopenharmony_ci            return false;
681bf215546Sopenharmony_ci      }
682bf215546Sopenharmony_ci      assert(READ_ONCE(q->map->snapshots_landed));
683bf215546Sopenharmony_ci#else
684bf215546Sopenharmony_ci      if (crocus_wait_syncobj(ctx->screen, q->syncobj, wait ? INT64_MAX : 0)) {
685bf215546Sopenharmony_ci         /* if we've waited and timedout, just set the query to ready to avoid infinite loop */
686bf215546Sopenharmony_ci         if (wait)
687bf215546Sopenharmony_ci            q->ready = true;
688bf215546Sopenharmony_ci         return false;
689bf215546Sopenharmony_ci      }
690bf215546Sopenharmony_ci#endif
691bf215546Sopenharmony_ci      calculate_result_on_cpu(devinfo, q);
692bf215546Sopenharmony_ci   }
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci   assert(q->ready);
695bf215546Sopenharmony_ci
696bf215546Sopenharmony_ci   result->u64 = q->result;
697bf215546Sopenharmony_ci
698bf215546Sopenharmony_ci   return true;
699bf215546Sopenharmony_ci}
700bf215546Sopenharmony_ci
701bf215546Sopenharmony_ci#if GFX_VER >= 7
702bf215546Sopenharmony_cistatic void
703bf215546Sopenharmony_cicrocus_get_query_result_resource(struct pipe_context *ctx,
704bf215546Sopenharmony_ci                                 struct pipe_query *query,
705bf215546Sopenharmony_ci                                 enum pipe_query_flags flags,
706bf215546Sopenharmony_ci                                 enum pipe_query_value_type result_type,
707bf215546Sopenharmony_ci                                 int index,
708bf215546Sopenharmony_ci                                 struct pipe_resource *p_res,
709bf215546Sopenharmony_ci                                 unsigned offset)
710bf215546Sopenharmony_ci{
711bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
712bf215546Sopenharmony_ci   struct crocus_query *q = (void *) query;
713bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[q->batch_idx];
714bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
715bf215546Sopenharmony_ci   const struct intel_device_info *devinfo = &batch->screen->devinfo;
716bf215546Sopenharmony_ci   struct crocus_resource *res = (void *) p_res;
717bf215546Sopenharmony_ci   struct crocus_bo *query_bo = crocus_resource_bo(q->query_state_ref.res);
718bf215546Sopenharmony_ci   struct crocus_bo *dst_bo = crocus_resource_bo(p_res);
719bf215546Sopenharmony_ci   unsigned snapshots_landed_offset =
720bf215546Sopenharmony_ci      offsetof(struct crocus_query_snapshots, snapshots_landed);
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci   res->bind_history |= PIPE_BIND_QUERY_BUFFER;
723bf215546Sopenharmony_ci
724bf215546Sopenharmony_ci   if (index == -1) {
725bf215546Sopenharmony_ci      /* They're asking for the availability of the result.  If we still
726bf215546Sopenharmony_ci       * have commands queued up which produce the result, submit them
727bf215546Sopenharmony_ci       * now so that progress happens.  Either way, copy the snapshots
728bf215546Sopenharmony_ci       * landed field to the destination resource.
729bf215546Sopenharmony_ci       */
730bf215546Sopenharmony_ci      if (q->syncobj == crocus_batch_get_signal_syncobj(batch))
731bf215546Sopenharmony_ci         crocus_batch_flush(batch);
732bf215546Sopenharmony_ci
733bf215546Sopenharmony_ci      screen->vtbl.copy_mem_mem(batch, dst_bo, offset,
734bf215546Sopenharmony_ci                                query_bo, snapshots_landed_offset,
735bf215546Sopenharmony_ci                                result_type <= PIPE_QUERY_TYPE_U32 ? 4 : 8);
736bf215546Sopenharmony_ci      return;
737bf215546Sopenharmony_ci   }
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci   if (!q->ready && READ_ONCE(q->map->snapshots_landed)) {
740bf215546Sopenharmony_ci      /* The final snapshots happen to have landed, so let's just compute
741bf215546Sopenharmony_ci       * the result on the CPU now...
742bf215546Sopenharmony_ci       */
743bf215546Sopenharmony_ci      calculate_result_on_cpu(devinfo, q);
744bf215546Sopenharmony_ci   }
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_ci   if (q->ready) {
747bf215546Sopenharmony_ci      /* We happen to have the result on the CPU, so just copy it. */
748bf215546Sopenharmony_ci      if (result_type <= PIPE_QUERY_TYPE_U32) {
749bf215546Sopenharmony_ci         screen->vtbl.store_data_imm32(batch, dst_bo, offset, q->result);
750bf215546Sopenharmony_ci      } else {
751bf215546Sopenharmony_ci         screen->vtbl.store_data_imm64(batch, dst_bo, offset, q->result);
752bf215546Sopenharmony_ci      }
753bf215546Sopenharmony_ci
754bf215546Sopenharmony_ci      /* Make sure the result lands before they use bind the QBO elsewhere
755bf215546Sopenharmony_ci       * and use the result.
756bf215546Sopenharmony_ci       */
757bf215546Sopenharmony_ci      // XXX: Why?  i965 doesn't do this.
758bf215546Sopenharmony_ci      crocus_emit_pipe_control_flush(batch,
759bf215546Sopenharmony_ci                                     "query: unknown QBO flushing hack",
760bf215546Sopenharmony_ci                                     PIPE_CONTROL_CS_STALL);
761bf215546Sopenharmony_ci      return;
762bf215546Sopenharmony_ci   }
763bf215546Sopenharmony_ci
764bf215546Sopenharmony_ci#if GFX_VERx10 >= 75
765bf215546Sopenharmony_ci   bool predicated = !(flags & PIPE_QUERY_WAIT) && !q->stalled;
766bf215546Sopenharmony_ci
767bf215546Sopenharmony_ci   struct mi_builder b;
768bf215546Sopenharmony_ci   mi_builder_init(&b, &batch->screen->devinfo, batch);
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_ci   struct mi_value result = calculate_result_on_gpu(devinfo, &b, q);
771bf215546Sopenharmony_ci   struct mi_value dst =
772bf215546Sopenharmony_ci      result_type <= PIPE_QUERY_TYPE_U32 ? mi_mem32(rw_bo(dst_bo, offset))
773bf215546Sopenharmony_ci                                         : mi_mem64(rw_bo(dst_bo, offset));
774bf215546Sopenharmony_ci
775bf215546Sopenharmony_ci   if (predicated) {
776bf215546Sopenharmony_ci      mi_store(&b, mi_reg32(MI_PREDICATE_RESULT),
777bf215546Sopenharmony_ci                   mi_mem64(ro_bo(query_bo, snapshots_landed_offset)));
778bf215546Sopenharmony_ci      mi_store_if(&b, dst, result);
779bf215546Sopenharmony_ci   } else {
780bf215546Sopenharmony_ci      mi_store(&b, dst, result);
781bf215546Sopenharmony_ci   }
782bf215546Sopenharmony_ci#endif
783bf215546Sopenharmony_ci}
784bf215546Sopenharmony_ci#endif
785bf215546Sopenharmony_ci
786bf215546Sopenharmony_cistatic void
787bf215546Sopenharmony_cicrocus_set_active_query_state(struct pipe_context *ctx, bool enable)
788bf215546Sopenharmony_ci{
789bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
790bf215546Sopenharmony_ci
791bf215546Sopenharmony_ci   if (ice->state.statistics_counters_enabled == enable)
792bf215546Sopenharmony_ci      return;
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci   // XXX: most packets aren't paying attention to this yet, because it'd
795bf215546Sopenharmony_ci   // have to be done dynamically at draw time, which is a pain
796bf215546Sopenharmony_ci   ice->state.statistics_counters_enabled = enable;
797bf215546Sopenharmony_ci   ice->state.dirty |= CROCUS_DIRTY_CLIP |
798bf215546Sopenharmony_ci                       CROCUS_DIRTY_RASTER |
799bf215546Sopenharmony_ci                       CROCUS_DIRTY_STREAMOUT |
800bf215546Sopenharmony_ci                       CROCUS_DIRTY_WM;
801bf215546Sopenharmony_ci   ice->state.stage_dirty |= CROCUS_STAGE_DIRTY_GS |
802bf215546Sopenharmony_ci                             CROCUS_STAGE_DIRTY_TCS |
803bf215546Sopenharmony_ci                             CROCUS_STAGE_DIRTY_TES |
804bf215546Sopenharmony_ci                             CROCUS_STAGE_DIRTY_VS;
805bf215546Sopenharmony_ci}
806bf215546Sopenharmony_ci
807bf215546Sopenharmony_cistatic void
808bf215546Sopenharmony_ciset_predicate_enable(struct crocus_context *ice, bool value)
809bf215546Sopenharmony_ci{
810bf215546Sopenharmony_ci   if (value)
811bf215546Sopenharmony_ci      ice->state.predicate = CROCUS_PREDICATE_STATE_RENDER;
812bf215546Sopenharmony_ci   else
813bf215546Sopenharmony_ci      ice->state.predicate = CROCUS_PREDICATE_STATE_DONT_RENDER;
814bf215546Sopenharmony_ci}
815bf215546Sopenharmony_ci
816bf215546Sopenharmony_ci#if GFX_VER >= 7
817bf215546Sopenharmony_cistatic void
818bf215546Sopenharmony_ciset_predicate_for_result(struct crocus_context *ice,
819bf215546Sopenharmony_ci                         struct crocus_query *q,
820bf215546Sopenharmony_ci                         bool inverted)
821bf215546Sopenharmony_ci{
822bf215546Sopenharmony_ci   struct crocus_batch *batch = &ice->batches[CROCUS_BATCH_RENDER];
823bf215546Sopenharmony_ci   struct crocus_bo *bo = crocus_resource_bo(q->query_state_ref.res);
824bf215546Sopenharmony_ci
825bf215546Sopenharmony_ci#if GFX_VERx10 < 75
826bf215546Sopenharmony_ci   /* IVB doesn't have enough MI for this */
827bf215546Sopenharmony_ci   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
828bf215546Sopenharmony_ci       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE) {
829bf215546Sopenharmony_ci      ice->state.predicate = CROCUS_PREDICATE_STATE_STALL_FOR_QUERY;
830bf215546Sopenharmony_ci      return;
831bf215546Sopenharmony_ci   }
832bf215546Sopenharmony_ci#endif
833bf215546Sopenharmony_ci
834bf215546Sopenharmony_ci   /* The CPU doesn't have the query result yet; use hardware predication */
835bf215546Sopenharmony_ci   ice->state.predicate = CROCUS_PREDICATE_STATE_USE_BIT;
836bf215546Sopenharmony_ci
837bf215546Sopenharmony_ci   /* Ensure the memory is coherent for MI_LOAD_REGISTER_* commands. */
838bf215546Sopenharmony_ci   crocus_emit_pipe_control_flush(batch,
839bf215546Sopenharmony_ci                                  "conditional rendering: set predicate",
840bf215546Sopenharmony_ci                                  PIPE_CONTROL_FLUSH_ENABLE);
841bf215546Sopenharmony_ci   q->stalled = true;
842bf215546Sopenharmony_ci
843bf215546Sopenharmony_ci#if GFX_VERx10 < 75
844bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
845bf215546Sopenharmony_ci   screen->vtbl.load_register_mem64(batch, MI_PREDICATE_SRC0, bo,
846bf215546Sopenharmony_ci                                    q->query_state_ref.offset + offsetof(struct crocus_query_snapshots, start));
847bf215546Sopenharmony_ci   screen->vtbl.load_register_mem64(batch, MI_PREDICATE_SRC1, bo,
848bf215546Sopenharmony_ci                                    q->query_state_ref.offset + offsetof(struct crocus_query_snapshots, end));
849bf215546Sopenharmony_ci
850bf215546Sopenharmony_ci   uint32_t mi_predicate = MI_PREDICATE | MI_PREDICATE_COMBINEOP_SET |
851bf215546Sopenharmony_ci      MI_PREDICATE_COMPAREOP_SRCS_EQUAL;
852bf215546Sopenharmony_ci   if (inverted)
853bf215546Sopenharmony_ci      mi_predicate |= MI_PREDICATE_LOADOP_LOAD;
854bf215546Sopenharmony_ci   else
855bf215546Sopenharmony_ci      mi_predicate |= MI_PREDICATE_LOADOP_LOADINV;
856bf215546Sopenharmony_ci   crocus_batch_emit(batch, &mi_predicate, sizeof(uint32_t));
857bf215546Sopenharmony_ci#else
858bf215546Sopenharmony_ci   struct mi_builder b;
859bf215546Sopenharmony_ci   mi_builder_init(&b, &batch->screen->devinfo, batch);
860bf215546Sopenharmony_ci
861bf215546Sopenharmony_ci   struct mi_value result;
862bf215546Sopenharmony_ci
863bf215546Sopenharmony_ci   switch (q->type) {
864bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
865bf215546Sopenharmony_ci      result = calc_overflow_for_stream(&b, q, q->index);
866bf215546Sopenharmony_ci      break;
867bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
868bf215546Sopenharmony_ci      result = calc_overflow_any_stream(&b, q);
869bf215546Sopenharmony_ci      break;
870bf215546Sopenharmony_ci   default: {
871bf215546Sopenharmony_ci      /* PIPE_QUERY_OCCLUSION_* */
872bf215546Sopenharmony_ci      struct mi_value start =
873bf215546Sopenharmony_ci         query_mem64(q, offsetof(struct crocus_query_snapshots, start));
874bf215546Sopenharmony_ci      struct mi_value end =
875bf215546Sopenharmony_ci         query_mem64(q, offsetof(struct crocus_query_snapshots, end));
876bf215546Sopenharmony_ci      result = mi_isub(&b, end, start);
877bf215546Sopenharmony_ci      break;
878bf215546Sopenharmony_ci   }
879bf215546Sopenharmony_ci   }
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci   result = inverted ? mi_z(&b, result) : mi_nz(&b, result);
882bf215546Sopenharmony_ci   result = mi_iand(&b, result, mi_imm(1));
883bf215546Sopenharmony_ci
884bf215546Sopenharmony_ci   /* We immediately set the predicate on the render batch, as all the
885bf215546Sopenharmony_ci    * counters come from 3D operations.  However, we may need to predicate
886bf215546Sopenharmony_ci    * a compute dispatch, which executes in a different GEM context and has
887bf215546Sopenharmony_ci    * a different MI_PREDICATE_RESULT register.  So, we save the result to
888bf215546Sopenharmony_ci    * memory and reload it in crocus_launch_grid.
889bf215546Sopenharmony_ci    */
890bf215546Sopenharmony_ci   mi_value_ref(&b, result);
891bf215546Sopenharmony_ci
892bf215546Sopenharmony_ci   mi_store(&b, mi_reg64(MI_PREDICATE_SRC0), result);
893bf215546Sopenharmony_ci   mi_store(&b, mi_reg64(MI_PREDICATE_SRC1), mi_imm(0));
894bf215546Sopenharmony_ci
895bf215546Sopenharmony_ci   unsigned mi_predicate = MI_PREDICATE | MI_PREDICATE_LOADOP_LOADINV |
896bf215546Sopenharmony_ci      MI_PREDICATE_COMBINEOP_SET |
897bf215546Sopenharmony_ci      MI_PREDICATE_COMPAREOP_SRCS_EQUAL;
898bf215546Sopenharmony_ci
899bf215546Sopenharmony_ci   crocus_batch_emit(batch, &mi_predicate, sizeof(uint32_t));
900bf215546Sopenharmony_ci   mi_store(&b, query_mem64(q, offsetof(struct crocus_query_snapshots,
901bf215546Sopenharmony_ci                                        predicate_result)), result);
902bf215546Sopenharmony_ci#endif
903bf215546Sopenharmony_ci   ice->state.compute_predicate = bo;
904bf215546Sopenharmony_ci}
905bf215546Sopenharmony_ci#endif
906bf215546Sopenharmony_ci
907bf215546Sopenharmony_cistatic void
908bf215546Sopenharmony_cicrocus_render_condition(struct pipe_context *ctx,
909bf215546Sopenharmony_ci                        struct pipe_query *query,
910bf215546Sopenharmony_ci                        bool condition,
911bf215546Sopenharmony_ci                        enum pipe_render_cond_flag mode)
912bf215546Sopenharmony_ci{
913bf215546Sopenharmony_ci   struct crocus_context *ice = (void *) ctx;
914bf215546Sopenharmony_ci   struct crocus_query *q = (void *) query;
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   /* The old condition isn't relevant; we'll update it if necessary */
917bf215546Sopenharmony_ci   ice->state.compute_predicate = NULL;
918bf215546Sopenharmony_ci   ice->condition.query = q;
919bf215546Sopenharmony_ci   ice->condition.condition = condition;
920bf215546Sopenharmony_ci   ice->condition.mode = mode;
921bf215546Sopenharmony_ci
922bf215546Sopenharmony_ci   if (!q) {
923bf215546Sopenharmony_ci      ice->state.predicate = CROCUS_PREDICATE_STATE_RENDER;
924bf215546Sopenharmony_ci      return;
925bf215546Sopenharmony_ci   }
926bf215546Sopenharmony_ci
927bf215546Sopenharmony_ci   crocus_check_query_no_flush(ice, q);
928bf215546Sopenharmony_ci
929bf215546Sopenharmony_ci   if (q->result || q->ready) {
930bf215546Sopenharmony_ci      set_predicate_enable(ice, (q->result != 0) ^ condition);
931bf215546Sopenharmony_ci   } else {
932bf215546Sopenharmony_ci      if (mode == PIPE_RENDER_COND_NO_WAIT ||
933bf215546Sopenharmony_ci          mode == PIPE_RENDER_COND_BY_REGION_NO_WAIT) {
934bf215546Sopenharmony_ci         perf_debug(&ice->dbg, "Conditional rendering demoted from "
935bf215546Sopenharmony_ci                    "\"no wait\" to \"wait\".");
936bf215546Sopenharmony_ci      }
937bf215546Sopenharmony_ci#if GFX_VER >= 7
938bf215546Sopenharmony_ci      set_predicate_for_result(ice, q, condition);
939bf215546Sopenharmony_ci#else
940bf215546Sopenharmony_ci      ice->state.predicate = CROCUS_PREDICATE_STATE_STALL_FOR_QUERY;
941bf215546Sopenharmony_ci#endif
942bf215546Sopenharmony_ci   }
943bf215546Sopenharmony_ci}
944bf215546Sopenharmony_ci
945bf215546Sopenharmony_cistatic void
946bf215546Sopenharmony_cicrocus_resolve_conditional_render(struct crocus_context *ice)
947bf215546Sopenharmony_ci{
948bf215546Sopenharmony_ci   struct pipe_context *ctx = (void *) ice;
949bf215546Sopenharmony_ci   struct crocus_query *q = ice->condition.query;
950bf215546Sopenharmony_ci   struct pipe_query *query = (void *) q;
951bf215546Sopenharmony_ci   union pipe_query_result result;
952bf215546Sopenharmony_ci
953bf215546Sopenharmony_ci   if (ice->state.predicate != CROCUS_PREDICATE_STATE_USE_BIT)
954bf215546Sopenharmony_ci      return;
955bf215546Sopenharmony_ci
956bf215546Sopenharmony_ci   assert(q);
957bf215546Sopenharmony_ci
958bf215546Sopenharmony_ci   crocus_get_query_result(ctx, query, true, &result);
959bf215546Sopenharmony_ci   set_predicate_enable(ice, (q->result != 0) ^ ice->condition.condition);
960bf215546Sopenharmony_ci}
961bf215546Sopenharmony_ci
962bf215546Sopenharmony_ci#if GFX_VER >= 7
963bf215546Sopenharmony_cistatic void
964bf215546Sopenharmony_cicrocus_emit_compute_predicate(struct crocus_batch *batch)
965bf215546Sopenharmony_ci{
966bf215546Sopenharmony_ci   struct crocus_context *ice = batch->ice;
967bf215546Sopenharmony_ci   struct crocus_screen *screen = batch->screen;
968bf215546Sopenharmony_ci   screen->vtbl.load_register_mem32(batch, MI_PREDICATE_SRC0,
969bf215546Sopenharmony_ci                                    ice->state.compute_predicate, 0);
970bf215546Sopenharmony_ci   screen->vtbl.load_register_imm32(batch, MI_PREDICATE_SRC1, 0);
971bf215546Sopenharmony_ci   unsigned mi_predicate = MI_PREDICATE | MI_PREDICATE_LOADOP_LOADINV |
972bf215546Sopenharmony_ci      MI_PREDICATE_COMBINEOP_SET |
973bf215546Sopenharmony_ci      MI_PREDICATE_COMPAREOP_SRCS_EQUAL;
974bf215546Sopenharmony_ci
975bf215546Sopenharmony_ci   crocus_batch_emit(batch, &mi_predicate, sizeof(uint32_t));
976bf215546Sopenharmony_ci}
977bf215546Sopenharmony_ci#endif
978bf215546Sopenharmony_ci
979bf215546Sopenharmony_civoid
980bf215546Sopenharmony_cigenX(crocus_init_screen_query)(struct crocus_screen *screen)
981bf215546Sopenharmony_ci{
982bf215546Sopenharmony_ci   screen->vtbl.resolve_conditional_render = crocus_resolve_conditional_render;
983bf215546Sopenharmony_ci#if GFX_VER >= 7
984bf215546Sopenharmony_ci   screen->vtbl.emit_compute_predicate = crocus_emit_compute_predicate;
985bf215546Sopenharmony_ci#endif
986bf215546Sopenharmony_ci}
987bf215546Sopenharmony_ci
988bf215546Sopenharmony_civoid
989bf215546Sopenharmony_cigenX(crocus_init_query)(struct crocus_context *ice)
990bf215546Sopenharmony_ci{
991bf215546Sopenharmony_ci   struct pipe_context *ctx = &ice->ctx;
992bf215546Sopenharmony_ci
993bf215546Sopenharmony_ci   ctx->create_query = crocus_create_query;
994bf215546Sopenharmony_ci   ctx->create_batch_query = crocus_create_batch_query;
995bf215546Sopenharmony_ci   ctx->destroy_query = crocus_destroy_query;
996bf215546Sopenharmony_ci   ctx->begin_query = crocus_begin_query;
997bf215546Sopenharmony_ci   ctx->end_query = crocus_end_query;
998bf215546Sopenharmony_ci   ctx->get_query_result = crocus_get_query_result;
999bf215546Sopenharmony_ci#if GFX_VER >= 7
1000bf215546Sopenharmony_ci   ctx->get_query_result_resource = crocus_get_query_result_resource;
1001bf215546Sopenharmony_ci#endif
1002bf215546Sopenharmony_ci   ctx->set_active_query_state = crocus_set_active_query_state;
1003bf215546Sopenharmony_ci   ctx->render_condition = crocus_render_condition;
1004bf215546Sopenharmony_ci
1005bf215546Sopenharmony_ci}
1006