19f464c52Smaya/*
29f464c52Smaya * Copyright © 2017 Intel Corporation
39f464c52Smaya *
49f464c52Smaya * Permission is hereby granted, free of charge, to any person obtaining a
59f464c52Smaya * copy of this software and associated documentation files (the "Software"),
69f464c52Smaya * to deal in the Software without restriction, including without limitation
79f464c52Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense,
89f464c52Smaya * and/or sell copies of the Software, and to permit persons to whom the
99f464c52Smaya * Software is furnished to do so, subject to the following conditions:
109f464c52Smaya *
119f464c52Smaya * The above copyright notice and this permission notice shall be included
129f464c52Smaya * in all copies or substantial portions of the Software.
139f464c52Smaya *
149f464c52Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
159f464c52Smaya * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169f464c52Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
179f464c52Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
189f464c52Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
199f464c52Smaya * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
209f464c52Smaya * DEALINGS IN THE SOFTWARE.
219f464c52Smaya */
229f464c52Smaya
239f464c52Smaya/**
249f464c52Smaya * @file iris_query.c
259f464c52Smaya *
267ec681f3Smrg * ============================= GENXML CODE =============================
277ec681f3Smrg *              [This file is compiled once per generation.]
287ec681f3Smrg * =======================================================================
297ec681f3Smrg *
309f464c52Smaya * Query object support.  This allows measuring various simple statistics
317ec681f3Smrg * via counters on the GPU.  We use GenX code for MI_MATH calculations.
329f464c52Smaya */
339f464c52Smaya
349f464c52Smaya#include <stdio.h>
359f464c52Smaya#include <errno.h>
369f464c52Smaya#include "pipe/p_defines.h"
379f464c52Smaya#include "pipe/p_state.h"
389f464c52Smaya#include "pipe/p_context.h"
399f464c52Smaya#include "pipe/p_screen.h"
409f464c52Smaya#include "util/u_inlines.h"
419f464c52Smaya#include "util/u_upload_mgr.h"
429f464c52Smaya#include "iris_context.h"
439f464c52Smaya#include "iris_defines.h"
449f464c52Smaya#include "iris_fence.h"
457ec681f3Smrg#include "iris_monitor.h"
469f464c52Smaya#include "iris_resource.h"
479f464c52Smaya#include "iris_screen.h"
487ec681f3Smrg
497ec681f3Smrg#include "iris_genx_macros.h"
507ec681f3Smrg
517ec681f3Smrg#define SO_PRIM_STORAGE_NEEDED(n) (GENX(SO_PRIM_STORAGE_NEEDED0_num) + (n) * 8)
527ec681f3Smrg#define SO_NUM_PRIMS_WRITTEN(n)   (GENX(SO_NUM_PRIMS_WRITTEN0_num) + (n) * 8)
539f464c52Smaya
549f464c52Smayastruct iris_query {
557ec681f3Smrg   struct threaded_query b;
567ec681f3Smrg
579f464c52Smaya   enum pipe_query_type type;
589f464c52Smaya   int index;
599f464c52Smaya
609f464c52Smaya   bool ready;
619f464c52Smaya
629f464c52Smaya   bool stalled;
639f464c52Smaya
649f464c52Smaya   uint64_t result;
659f464c52Smaya
669f464c52Smaya   struct iris_state_ref query_state_ref;
679f464c52Smaya   struct iris_query_snapshots *map;
687ec681f3Smrg   struct iris_syncobj *syncobj;
699f464c52Smaya
709f464c52Smaya   int batch_idx;
717ec681f3Smrg
727ec681f3Smrg   struct iris_monitor_object *monitor;
737ec681f3Smrg
747ec681f3Smrg   /* Fence for PIPE_QUERY_GPU_FINISHED. */
757ec681f3Smrg   struct pipe_fence_handle *fence;
769f464c52Smaya};
779f464c52Smaya
789f464c52Smayastruct iris_query_snapshots {
799f464c52Smaya   /** iris_render_condition's saved MI_PREDICATE_RESULT value. */
809f464c52Smaya   uint64_t predicate_result;
819f464c52Smaya
829f464c52Smaya   /** Have the start/end snapshots landed? */
839f464c52Smaya   uint64_t snapshots_landed;
849f464c52Smaya
859f464c52Smaya   /** Starting and ending counter snapshots */
869f464c52Smaya   uint64_t start;
879f464c52Smaya   uint64_t end;
889f464c52Smaya};
899f464c52Smaya
909f464c52Smayastruct iris_query_so_overflow {
919f464c52Smaya   uint64_t predicate_result;
929f464c52Smaya   uint64_t snapshots_landed;
939f464c52Smaya
949f464c52Smaya   struct {
959f464c52Smaya      uint64_t prim_storage_needed[2];
969f464c52Smaya      uint64_t num_prims[2];
979f464c52Smaya   } stream[4];
989f464c52Smaya};
999f464c52Smaya
1007ec681f3Smrgstatic struct mi_value
1017ec681f3Smrgquery_mem64(struct iris_query *q, uint32_t offset)
1027ec681f3Smrg{
1037ec681f3Smrg   struct iris_address addr = {
1047ec681f3Smrg      .bo = iris_resource_bo(q->query_state_ref.res),
1057ec681f3Smrg      .offset = q->query_state_ref.offset + offset,
1067ec681f3Smrg      .access = IRIS_DOMAIN_OTHER_WRITE
1077ec681f3Smrg   };
1087ec681f3Smrg   return mi_mem64(addr);
1097ec681f3Smrg}
1107ec681f3Smrg
1119f464c52Smaya/**
1129f464c52Smaya * Is this type of query written by PIPE_CONTROL?
1139f464c52Smaya */
1149f464c52Smayastatic bool
1159f464c52Smayairis_is_query_pipelined(struct iris_query *q)
1169f464c52Smaya{
1179f464c52Smaya   switch (q->type) {
1189f464c52Smaya   case PIPE_QUERY_OCCLUSION_COUNTER:
1199f464c52Smaya   case PIPE_QUERY_OCCLUSION_PREDICATE:
1209f464c52Smaya   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
1219f464c52Smaya   case PIPE_QUERY_TIMESTAMP:
1229f464c52Smaya   case PIPE_QUERY_TIMESTAMP_DISJOINT:
1239f464c52Smaya   case PIPE_QUERY_TIME_ELAPSED:
1249f464c52Smaya      return true;
1259f464c52Smaya
1269f464c52Smaya   default:
1279f464c52Smaya      return false;
1289f464c52Smaya   }
1299f464c52Smaya}
1309f464c52Smaya
1319f464c52Smayastatic void
1329f464c52Smayamark_available(struct iris_context *ice, struct iris_query *q)
1339f464c52Smaya{
1349f464c52Smaya   struct iris_batch *batch = &ice->batches[q->batch_idx];
1359f464c52Smaya   unsigned flags = PIPE_CONTROL_WRITE_IMMEDIATE;
1369f464c52Smaya   unsigned offset = offsetof(struct iris_query_snapshots, snapshots_landed);
1379f464c52Smaya   struct iris_bo *bo = iris_resource_bo(q->query_state_ref.res);
1389f464c52Smaya   offset += q->query_state_ref.offset;
1399f464c52Smaya
1409f464c52Smaya   if (!iris_is_query_pipelined(q)) {
1417ec681f3Smrg      batch->screen->vtbl.store_data_imm64(batch, bo, offset, true);
1429f464c52Smaya   } else {
1439f464c52Smaya      /* Order available *after* the query results. */
1449f464c52Smaya      flags |= PIPE_CONTROL_FLUSH_ENABLE;
1457ec681f3Smrg      iris_emit_pipe_control_write(batch, "query: mark available",
1467ec681f3Smrg                                   flags, bo, offset, true);
1479f464c52Smaya   }
1489f464c52Smaya}
1499f464c52Smaya
1509f464c52Smaya/**
1519f464c52Smaya * Write PS_DEPTH_COUNT to q->(dest) via a PIPE_CONTROL.
1529f464c52Smaya */
1539f464c52Smayastatic void
1549f464c52Smayairis_pipelined_write(struct iris_batch *batch,
1559f464c52Smaya                     struct iris_query *q,
1569f464c52Smaya                     enum pipe_control_flags flags,
1579f464c52Smaya                     unsigned offset)
1589f464c52Smaya{
1597ec681f3Smrg   const struct intel_device_info *devinfo = &batch->screen->devinfo;
1609f464c52Smaya   const unsigned optional_cs_stall =
1617ec681f3Smrg      GFX_VER == 9 && devinfo->gt == 4 ?  PIPE_CONTROL_CS_STALL : 0;
1629f464c52Smaya   struct iris_bo *bo = iris_resource_bo(q->query_state_ref.res);
1639f464c52Smaya
1647ec681f3Smrg   iris_emit_pipe_control_write(batch, "query: pipelined snapshot write",
1657ec681f3Smrg                                flags | optional_cs_stall,
1669f464c52Smaya                                bo, offset, 0ull);
1679f464c52Smaya}
1689f464c52Smaya
1699f464c52Smayastatic void
1709f464c52Smayawrite_value(struct iris_context *ice, struct iris_query *q, unsigned offset)
1719f464c52Smaya{
1729f464c52Smaya   struct iris_batch *batch = &ice->batches[q->batch_idx];
1739f464c52Smaya   struct iris_bo *bo = iris_resource_bo(q->query_state_ref.res);
1749f464c52Smaya
1759f464c52Smaya   if (!iris_is_query_pipelined(q)) {
1769f464c52Smaya      iris_emit_pipe_control_flush(batch,
1777ec681f3Smrg                                   "query: non-pipelined snapshot write",
1789f464c52Smaya                                   PIPE_CONTROL_CS_STALL |
1799f464c52Smaya                                   PIPE_CONTROL_STALL_AT_SCOREBOARD);
1809f464c52Smaya      q->stalled = true;
1819f464c52Smaya   }
1829f464c52Smaya
1839f464c52Smaya   switch (q->type) {
1849f464c52Smaya   case PIPE_QUERY_OCCLUSION_COUNTER:
1859f464c52Smaya   case PIPE_QUERY_OCCLUSION_PREDICATE:
1869f464c52Smaya   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
1877ec681f3Smrg      if (GFX_VER >= 10) {
1889f464c52Smaya         /* "Driver must program PIPE_CONTROL with only Depth Stall Enable
1899f464c52Smaya          *  bit set prior to programming a PIPE_CONTROL with Write PS Depth
1909f464c52Smaya          *  Count sync operation."
1919f464c52Smaya          */
1927ec681f3Smrg         iris_emit_pipe_control_flush(batch,
1937ec681f3Smrg                                      "workaround: depth stall before writing "
1947ec681f3Smrg                                      "PS_DEPTH_COUNT",
1957ec681f3Smrg                                      PIPE_CONTROL_DEPTH_STALL);
1969f464c52Smaya      }
1979f464c52Smaya      iris_pipelined_write(&ice->batches[IRIS_BATCH_RENDER], q,
1989f464c52Smaya                           PIPE_CONTROL_WRITE_DEPTH_COUNT |
1999f464c52Smaya                           PIPE_CONTROL_DEPTH_STALL,
2009f464c52Smaya                           offset);
2019f464c52Smaya      break;
2029f464c52Smaya   case PIPE_QUERY_TIME_ELAPSED:
2039f464c52Smaya   case PIPE_QUERY_TIMESTAMP:
2049f464c52Smaya   case PIPE_QUERY_TIMESTAMP_DISJOINT:
2059f464c52Smaya      iris_pipelined_write(&ice->batches[IRIS_BATCH_RENDER], q,
2069f464c52Smaya                           PIPE_CONTROL_WRITE_TIMESTAMP,
2079f464c52Smaya                           offset);
2089f464c52Smaya      break;
2099f464c52Smaya   case PIPE_QUERY_PRIMITIVES_GENERATED:
2107ec681f3Smrg      batch->screen->vtbl.store_register_mem64(batch,
2117ec681f3Smrg                                     q->index == 0 ?
2127ec681f3Smrg                                     GENX(CL_INVOCATION_COUNT_num) :
2139f464c52Smaya                                     SO_PRIM_STORAGE_NEEDED(q->index),
2149f464c52Smaya                                     bo, offset, false);
2159f464c52Smaya      break;
2169f464c52Smaya   case PIPE_QUERY_PRIMITIVES_EMITTED:
2177ec681f3Smrg      batch->screen->vtbl.store_register_mem64(batch,
2189f464c52Smaya                                     SO_NUM_PRIMS_WRITTEN(q->index),
2199f464c52Smaya                                     bo, offset, false);
2209f464c52Smaya      break;
2219f464c52Smaya   case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE: {
2229f464c52Smaya      static const uint32_t index_to_reg[] = {
2237ec681f3Smrg         GENX(IA_VERTICES_COUNT_num),
2247ec681f3Smrg         GENX(IA_PRIMITIVES_COUNT_num),
2257ec681f3Smrg         GENX(VS_INVOCATION_COUNT_num),
2267ec681f3Smrg         GENX(GS_INVOCATION_COUNT_num),
2277ec681f3Smrg         GENX(GS_PRIMITIVES_COUNT_num),
2287ec681f3Smrg         GENX(CL_INVOCATION_COUNT_num),
2297ec681f3Smrg         GENX(CL_PRIMITIVES_COUNT_num),
2307ec681f3Smrg         GENX(PS_INVOCATION_COUNT_num),
2317ec681f3Smrg         GENX(HS_INVOCATION_COUNT_num),
2327ec681f3Smrg         GENX(DS_INVOCATION_COUNT_num),
2337ec681f3Smrg         GENX(CS_INVOCATION_COUNT_num),
2349f464c52Smaya      };
2359f464c52Smaya      const uint32_t reg = index_to_reg[q->index];
2369f464c52Smaya
2377ec681f3Smrg      batch->screen->vtbl.store_register_mem64(batch, reg, bo, offset, false);
2389f464c52Smaya      break;
2399f464c52Smaya   }
2409f464c52Smaya   default:
2419f464c52Smaya      assert(false);
2429f464c52Smaya   }
2439f464c52Smaya}
2449f464c52Smaya
2459f464c52Smayastatic void
2469f464c52Smayawrite_overflow_values(struct iris_context *ice, struct iris_query *q, bool end)
2479f464c52Smaya{
2489f464c52Smaya   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
2499f464c52Smaya   uint32_t count = q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ? 1 : 4;
2509f464c52Smaya   struct iris_bo *bo = iris_resource_bo(q->query_state_ref.res);
2519f464c52Smaya   uint32_t offset = q->query_state_ref.offset;
2529f464c52Smaya
2539f464c52Smaya   iris_emit_pipe_control_flush(batch,
2547ec681f3Smrg                                "query: write SO overflow snapshots",
2559f464c52Smaya                                PIPE_CONTROL_CS_STALL |
2569f464c52Smaya                                PIPE_CONTROL_STALL_AT_SCOREBOARD);
2579f464c52Smaya   for (uint32_t i = 0; i < count; i++) {
2589f464c52Smaya      int s = q->index + i;
2599f464c52Smaya      int g_idx = offset + offsetof(struct iris_query_so_overflow,
2609f464c52Smaya                           stream[s].num_prims[end]);
2619f464c52Smaya      int w_idx = offset + offsetof(struct iris_query_so_overflow,
2629f464c52Smaya                           stream[s].prim_storage_needed[end]);
2637ec681f3Smrg      batch->screen->vtbl.store_register_mem64(batch, SO_NUM_PRIMS_WRITTEN(s),
2649f464c52Smaya                                     bo, g_idx, false);
2657ec681f3Smrg      batch->screen->vtbl.store_register_mem64(batch, SO_PRIM_STORAGE_NEEDED(s),
2669f464c52Smaya                                     bo, w_idx, false);
2679f464c52Smaya   }
2689f464c52Smaya}
2699f464c52Smaya
2709f464c52Smayastatic uint64_t
2719f464c52Smayairis_raw_timestamp_delta(uint64_t time0, uint64_t time1)
2729f464c52Smaya{
2739f464c52Smaya   if (time0 > time1) {
2749f464c52Smaya      return (1ULL << TIMESTAMP_BITS) + time1 - time0;
2759f464c52Smaya   } else {
2769f464c52Smaya      return time1 - time0;
2779f464c52Smaya   }
2789f464c52Smaya}
2799f464c52Smaya
2809f464c52Smayastatic bool
2819f464c52Smayastream_overflowed(struct iris_query_so_overflow *so, int s)
2829f464c52Smaya{
2839f464c52Smaya   return (so->stream[s].prim_storage_needed[1] -
2849f464c52Smaya           so->stream[s].prim_storage_needed[0]) !=
2859f464c52Smaya          (so->stream[s].num_prims[1] - so->stream[s].num_prims[0]);
2869f464c52Smaya}
2879f464c52Smaya
2889f464c52Smayastatic void
2897ec681f3Smrgcalculate_result_on_cpu(const struct intel_device_info *devinfo,
2909f464c52Smaya                        struct iris_query *q)
2919f464c52Smaya{
2929f464c52Smaya   switch (q->type) {
2939f464c52Smaya   case PIPE_QUERY_OCCLUSION_PREDICATE:
2949f464c52Smaya   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
2959f464c52Smaya      q->result = q->map->end != q->map->start;
2969f464c52Smaya      break;
2979f464c52Smaya   case PIPE_QUERY_TIMESTAMP:
2989f464c52Smaya   case PIPE_QUERY_TIMESTAMP_DISJOINT:
2999f464c52Smaya      /* The timestamp is the single starting snapshot. */
3007ec681f3Smrg      q->result = intel_device_info_timebase_scale(devinfo, q->map->start);
3019f464c52Smaya      q->result &= (1ull << TIMESTAMP_BITS) - 1;
3029f464c52Smaya      break;
3039f464c52Smaya   case PIPE_QUERY_TIME_ELAPSED:
3049f464c52Smaya      q->result = iris_raw_timestamp_delta(q->map->start, q->map->end);
3057ec681f3Smrg      q->result = intel_device_info_timebase_scale(devinfo, q->result);
3069f464c52Smaya      q->result &= (1ull << TIMESTAMP_BITS) - 1;
3079f464c52Smaya      break;
3089f464c52Smaya   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
3099f464c52Smaya      q->result = stream_overflowed((void *) q->map, q->index);
3109f464c52Smaya      break;
3119f464c52Smaya   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
3129f464c52Smaya      q->result = false;
3139f464c52Smaya      for (int i = 0; i < MAX_VERTEX_STREAMS; i++)
3149f464c52Smaya         q->result |= stream_overflowed((void *) q->map, i);
3159f464c52Smaya      break;
3169f464c52Smaya   case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE:
3179f464c52Smaya      q->result = q->map->end - q->map->start;
3189f464c52Smaya
3199f464c52Smaya      /* WaDividePSInvocationCountBy4:HSW,BDW */
3207ec681f3Smrg      if (GFX_VER == 8 && q->index == PIPE_STAT_QUERY_PS_INVOCATIONS)
3219f464c52Smaya         q->result /= 4;
3229f464c52Smaya      break;
3239f464c52Smaya   case PIPE_QUERY_OCCLUSION_COUNTER:
3249f464c52Smaya   case PIPE_QUERY_PRIMITIVES_GENERATED:
3259f464c52Smaya   case PIPE_QUERY_PRIMITIVES_EMITTED:
3269f464c52Smaya   default:
3279f464c52Smaya      q->result = q->map->end - q->map->start;
3289f464c52Smaya      break;
3299f464c52Smaya   }
3309f464c52Smaya
3319f464c52Smaya   q->ready = true;
3329f464c52Smaya}
3339f464c52Smaya
3347ec681f3Smrg/**
3357ec681f3Smrg * Calculate the streamout overflow for stream \p idx:
3367ec681f3Smrg *
3377ec681f3Smrg * (num_prims[1] - num_prims[0]) - (storage_needed[1] - storage_needed[0])
3389f464c52Smaya */
3397ec681f3Smrgstatic struct mi_value
3407ec681f3Smrgcalc_overflow_for_stream(struct mi_builder *b,
3417ec681f3Smrg                         struct iris_query *q,
3427ec681f3Smrg                         int idx)
3439f464c52Smaya{
3447ec681f3Smrg#define C(counter, i) query_mem64(q, \
3457ec681f3Smrg   offsetof(struct iris_query_so_overflow, stream[idx].counter[i]))
3469f464c52Smaya
3477ec681f3Smrg   return mi_isub(b, mi_isub(b, C(num_prims, 1), C(num_prims, 0)),
3487ec681f3Smrg                     mi_isub(b, C(prim_storage_needed, 1),
3497ec681f3Smrg                                C(prim_storage_needed, 0)));
3507ec681f3Smrg#undef C
3519f464c52Smaya}
3529f464c52Smaya
3537ec681f3Smrg/**
3547ec681f3Smrg * Calculate whether any stream has overflowed.
3559f464c52Smaya */
3567ec681f3Smrgstatic struct mi_value
3577ec681f3Smrgcalc_overflow_any_stream(struct mi_builder *b, struct iris_query *q)
3589f464c52Smaya{
3597ec681f3Smrg   struct mi_value stream_result[MAX_VERTEX_STREAMS];
3607ec681f3Smrg   for (int i = 0; i < MAX_VERTEX_STREAMS; i++)
3617ec681f3Smrg      stream_result[i] = calc_overflow_for_stream(b, q, i);
3629f464c52Smaya
3637ec681f3Smrg   struct mi_value result = stream_result[0];
3647ec681f3Smrg   for (int i = 1; i < MAX_VERTEX_STREAMS; i++)
3657ec681f3Smrg      result = mi_ior(b, result, stream_result[i]);
3669f464c52Smaya
3677ec681f3Smrg   return result;
3689f464c52Smaya}
3699f464c52Smaya
3707ec681f3Smrgstatic bool
3717ec681f3Smrgquery_is_boolean(enum pipe_query_type type)
3729f464c52Smaya{
3737ec681f3Smrg   switch (type) {
3747ec681f3Smrg   case PIPE_QUERY_OCCLUSION_PREDICATE:
3757ec681f3Smrg   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
3767ec681f3Smrg   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
3777ec681f3Smrg   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
3787ec681f3Smrg      return true;
3797ec681f3Smrg   default:
3807ec681f3Smrg      return false;
3819f464c52Smaya   }
3829f464c52Smaya}
3839f464c52Smaya
3849f464c52Smaya/**
3857ec681f3Smrg * Calculate the result using MI_MATH.
3869f464c52Smaya */
3877ec681f3Smrgstatic struct mi_value
3887ec681f3Smrgcalculate_result_on_gpu(const struct intel_device_info *devinfo,
3897ec681f3Smrg                        struct mi_builder *b,
3907ec681f3Smrg                        struct iris_query *q)
3919f464c52Smaya{
3927ec681f3Smrg   struct mi_value result;
3937ec681f3Smrg   struct mi_value start_val =
3947ec681f3Smrg      query_mem64(q, offsetof(struct iris_query_snapshots, start));
3957ec681f3Smrg   struct mi_value end_val =
3967ec681f3Smrg      query_mem64(q, offsetof(struct iris_query_snapshots, end));
3979f464c52Smaya
3987ec681f3Smrg   switch (q->type) {
3997ec681f3Smrg   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
4007ec681f3Smrg      result = calc_overflow_for_stream(b, q, q->index);
4017ec681f3Smrg      break;
4027ec681f3Smrg   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
4037ec681f3Smrg      result = calc_overflow_any_stream(b, q);
4047ec681f3Smrg      break;
4057ec681f3Smrg   case PIPE_QUERY_TIMESTAMP: {
4069f464c52Smaya      /* TODO: This discards any fractional bits of the timebase scale.
4079f464c52Smaya       * We would need to do a bit of fixed point math on the CS ALU, or
4089f464c52Smaya       * launch an actual shader to calculate this with full precision.
4099f464c52Smaya       */
4107ec681f3Smrg      uint32_t scale = 1000000000ull / devinfo->timestamp_frequency;
4117ec681f3Smrg      result = mi_iand(b, mi_imm((1ull << 36) - 1),
4127ec681f3Smrg                          mi_imul_imm(b, start_val, scale));
4137ec681f3Smrg      break;
4147ec681f3Smrg   }
4157ec681f3Smrg   case PIPE_QUERY_TIME_ELAPSED: {
4167ec681f3Smrg      /* TODO: This discards fractional bits (see above). */
4177ec681f3Smrg      uint32_t scale = 1000000000ull / devinfo->timestamp_frequency;
4187ec681f3Smrg      result = mi_imul_imm(b, mi_isub(b, end_val, start_val), scale);
4197ec681f3Smrg      break;
4207ec681f3Smrg   }
4217ec681f3Smrg   default:
4227ec681f3Smrg      result = mi_isub(b, end_val, start_val);
4237ec681f3Smrg      break;
4249f464c52Smaya   }
4259f464c52Smaya
4269f464c52Smaya   /* WaDividePSInvocationCountBy4:HSW,BDW */
4277ec681f3Smrg   if (GFX_VER == 8 &&
4289f464c52Smaya       q->type == PIPE_QUERY_PIPELINE_STATISTICS_SINGLE &&
4299f464c52Smaya       q->index == PIPE_STAT_QUERY_PS_INVOCATIONS)
4307ec681f3Smrg      result = mi_ushr32_imm(b, result, 2);
4319f464c52Smaya
4327ec681f3Smrg   if (query_is_boolean(q->type))
4337ec681f3Smrg      result = mi_iand(b, mi_nz(b, result), mi_imm(1));
4349f464c52Smaya
4357ec681f3Smrg   return result;
4369f464c52Smaya}
4379f464c52Smaya
4389f464c52Smayastatic struct pipe_query *
4399f464c52Smayairis_create_query(struct pipe_context *ctx,
4409f464c52Smaya                  unsigned query_type,
4419f464c52Smaya                  unsigned index)
4429f464c52Smaya{
4439f464c52Smaya   struct iris_query *q = calloc(1, sizeof(struct iris_query));
4449f464c52Smaya
4459f464c52Smaya   q->type = query_type;
4469f464c52Smaya   q->index = index;
4477ec681f3Smrg   q->monitor = NULL;
4489f464c52Smaya
4499f464c52Smaya   if (q->type == PIPE_QUERY_PIPELINE_STATISTICS_SINGLE &&
4509f464c52Smaya       q->index == PIPE_STAT_QUERY_CS_INVOCATIONS)
4519f464c52Smaya      q->batch_idx = IRIS_BATCH_COMPUTE;
4529f464c52Smaya   else
4539f464c52Smaya      q->batch_idx = IRIS_BATCH_RENDER;
4549f464c52Smaya   return (struct pipe_query *) q;
4559f464c52Smaya}
4569f464c52Smaya
4577ec681f3Smrgstatic struct pipe_query *
4587ec681f3Smrgiris_create_batch_query(struct pipe_context *ctx,
4597ec681f3Smrg                        unsigned num_queries,
4607ec681f3Smrg                        unsigned *query_types)
4617ec681f3Smrg{
4627ec681f3Smrg   struct iris_context *ice = (void *) ctx;
4637ec681f3Smrg   struct iris_query *q = calloc(1, sizeof(struct iris_query));
4647ec681f3Smrg   if (unlikely(!q))
4657ec681f3Smrg      return NULL;
4667ec681f3Smrg   q->type = PIPE_QUERY_DRIVER_SPECIFIC;
4677ec681f3Smrg   q->index = -1;
4687ec681f3Smrg   q->monitor = iris_create_monitor_object(ice, num_queries, query_types);
4697ec681f3Smrg   if (unlikely(!q->monitor)) {
4707ec681f3Smrg      free(q);
4717ec681f3Smrg      return NULL;
4727ec681f3Smrg   }
4737ec681f3Smrg
4747ec681f3Smrg   return (struct pipe_query *) q;
4757ec681f3Smrg}
4767ec681f3Smrg
4779f464c52Smayastatic void
4789f464c52Smayairis_destroy_query(struct pipe_context *ctx, struct pipe_query *p_query)
4799f464c52Smaya{
4809f464c52Smaya   struct iris_query *query = (void *) p_query;
4819f464c52Smaya   struct iris_screen *screen = (void *) ctx->screen;
4827ec681f3Smrg   if (query->monitor) {
4837ec681f3Smrg      iris_destroy_monitor_object(ctx, query->monitor);
4847ec681f3Smrg      query->monitor = NULL;
4857ec681f3Smrg   } else {
4867ec681f3Smrg      iris_syncobj_reference(screen->bufmgr, &query->syncobj, NULL);
4877ec681f3Smrg      screen->base.fence_reference(ctx->screen, &query->fence, NULL);
4887ec681f3Smrg   }
4897ec681f3Smrg   pipe_resource_reference(&query->query_state_ref.res, NULL);
4909f464c52Smaya   free(query);
4919f464c52Smaya}
4929f464c52Smaya
4939f464c52Smaya
4947ec681f3Smrgstatic bool
4959f464c52Smayairis_begin_query(struct pipe_context *ctx, struct pipe_query *query)
4969f464c52Smaya{
4979f464c52Smaya   struct iris_context *ice = (void *) ctx;
4989f464c52Smaya   struct iris_query *q = (void *) query;
4997ec681f3Smrg
5007ec681f3Smrg   if (q->monitor)
5017ec681f3Smrg      return iris_begin_monitor(ctx, q->monitor);
5027ec681f3Smrg
5039f464c52Smaya   void *ptr = NULL;
5049f464c52Smaya   uint32_t size;
5059f464c52Smaya
5069f464c52Smaya   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
5079f464c52Smaya       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE)
5089f464c52Smaya      size = sizeof(struct iris_query_so_overflow);
5099f464c52Smaya   else
5109f464c52Smaya      size = sizeof(struct iris_query_snapshots);
5119f464c52Smaya
5129f464c52Smaya   u_upload_alloc(ice->query_buffer_uploader, 0,
5139f464c52Smaya                  size, size, &q->query_state_ref.offset,
5149f464c52Smaya                  &q->query_state_ref.res, &ptr);
5159f464c52Smaya
5169f464c52Smaya   if (!iris_resource_bo(q->query_state_ref.res))
5179f464c52Smaya      return false;
5189f464c52Smaya
5199f464c52Smaya   q->map = ptr;
5209f464c52Smaya   if (!q->map)
5219f464c52Smaya      return false;
5229f464c52Smaya
5239f464c52Smaya   q->result = 0ull;
5249f464c52Smaya   q->ready = false;
5259f464c52Smaya   WRITE_ONCE(q->map->snapshots_landed, false);
5269f464c52Smaya
5279f464c52Smaya   if (q->type == PIPE_QUERY_PRIMITIVES_GENERATED && q->index == 0) {
5289f464c52Smaya      ice->state.prims_generated_query_active = true;
5299f464c52Smaya      ice->state.dirty |= IRIS_DIRTY_STREAMOUT | IRIS_DIRTY_CLIP;
5309f464c52Smaya   }
5319f464c52Smaya
5329f464c52Smaya   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
5339f464c52Smaya       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE)
5349f464c52Smaya      write_overflow_values(ice, q, false);
5359f464c52Smaya   else
5369f464c52Smaya      write_value(ice, q,
5379f464c52Smaya                  q->query_state_ref.offset +
5389f464c52Smaya                  offsetof(struct iris_query_snapshots, start));
5399f464c52Smaya
5409f464c52Smaya   return true;
5419f464c52Smaya}
5429f464c52Smaya
5439f464c52Smayastatic bool
5449f464c52Smayairis_end_query(struct pipe_context *ctx, struct pipe_query *query)
5459f464c52Smaya{
5469f464c52Smaya   struct iris_context *ice = (void *) ctx;
5479f464c52Smaya   struct iris_query *q = (void *) query;
5487ec681f3Smrg
5497ec681f3Smrg   if (q->monitor)
5507ec681f3Smrg      return iris_end_monitor(ctx, q->monitor);
5517ec681f3Smrg
5527ec681f3Smrg   if (q->type == PIPE_QUERY_GPU_FINISHED) {
5537ec681f3Smrg      ctx->flush(ctx, &q->fence, PIPE_FLUSH_DEFERRED);
5547ec681f3Smrg      return true;
5557ec681f3Smrg   }
5567ec681f3Smrg
5579f464c52Smaya   struct iris_batch *batch = &ice->batches[q->batch_idx];
5589f464c52Smaya
5599f464c52Smaya   if (q->type == PIPE_QUERY_TIMESTAMP) {
5609f464c52Smaya      iris_begin_query(ctx, query);
5617ec681f3Smrg      iris_batch_reference_signal_syncobj(batch, &q->syncobj);
5629f464c52Smaya      mark_available(ice, q);
5639f464c52Smaya      return true;
5649f464c52Smaya   }
5659f464c52Smaya
5669f464c52Smaya   if (q->type == PIPE_QUERY_PRIMITIVES_GENERATED && q->index == 0) {
5679f464c52Smaya      ice->state.prims_generated_query_active = false;
5689f464c52Smaya      ice->state.dirty |= IRIS_DIRTY_STREAMOUT | IRIS_DIRTY_CLIP;
5699f464c52Smaya   }
5709f464c52Smaya
5719f464c52Smaya   if (q->type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
5729f464c52Smaya       q->type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE)
5739f464c52Smaya      write_overflow_values(ice, q, true);
5749f464c52Smaya   else
5759f464c52Smaya      write_value(ice, q,
5769f464c52Smaya                  q->query_state_ref.offset +
5779f464c52Smaya                  offsetof(struct iris_query_snapshots, end));
5789f464c52Smaya
5797ec681f3Smrg   iris_batch_reference_signal_syncobj(batch, &q->syncobj);
5809f464c52Smaya   mark_available(ice, q);
5819f464c52Smaya
5829f464c52Smaya   return true;
5839f464c52Smaya}
5849f464c52Smaya
5859f464c52Smaya/**
5869f464c52Smaya * See if the snapshots have landed for a query, and if so, compute the
5879f464c52Smaya * result and mark it ready.  Does not flush (unlike iris_get_query_result).
5889f464c52Smaya */
5899f464c52Smayastatic void
5909f464c52Smayairis_check_query_no_flush(struct iris_context *ice, struct iris_query *q)
5919f464c52Smaya{
5929f464c52Smaya   struct iris_screen *screen = (void *) ice->ctx.screen;
5937ec681f3Smrg   const struct intel_device_info *devinfo = &screen->devinfo;
5949f464c52Smaya
5959f464c52Smaya   if (!q->ready && READ_ONCE(q->map->snapshots_landed)) {
5969f464c52Smaya      calculate_result_on_cpu(devinfo, q);
5979f464c52Smaya   }
5989f464c52Smaya}
5999f464c52Smaya
6007ec681f3Smrgstatic bool
6019f464c52Smayairis_get_query_result(struct pipe_context *ctx,
6029f464c52Smaya                      struct pipe_query *query,
6037ec681f3Smrg                      bool wait,
6049f464c52Smaya                      union pipe_query_result *result)
6059f464c52Smaya{
6069f464c52Smaya   struct iris_context *ice = (void *) ctx;
6079f464c52Smaya   struct iris_query *q = (void *) query;
6087ec681f3Smrg
6097ec681f3Smrg   if (q->monitor)
6107ec681f3Smrg      return iris_get_monitor_result(ctx, q->monitor, wait, result->batch);
6117ec681f3Smrg
6129f464c52Smaya   struct iris_screen *screen = (void *) ctx->screen;
6137ec681f3Smrg   const struct intel_device_info *devinfo = &screen->devinfo;
6147ec681f3Smrg
6157ec681f3Smrg   if (unlikely(screen->devinfo.no_hw)) {
6167ec681f3Smrg      result->u64 = 0;
6177ec681f3Smrg      return true;
6187ec681f3Smrg   }
6197ec681f3Smrg
6207ec681f3Smrg   if (q->type == PIPE_QUERY_GPU_FINISHED) {
6217ec681f3Smrg      struct pipe_screen *screen = ctx->screen;
6227ec681f3Smrg
6237ec681f3Smrg      result->b = screen->fence_finish(screen, ctx, q->fence,
6247ec681f3Smrg                                       wait ? PIPE_TIMEOUT_INFINITE : 0);
6257ec681f3Smrg      return result->b;
6267ec681f3Smrg   }
6279f464c52Smaya
6289f464c52Smaya   if (!q->ready) {
6297ec681f3Smrg      struct iris_batch *batch = &ice->batches[q->batch_idx];
6307ec681f3Smrg      if (q->syncobj == iris_batch_get_signal_syncobj(batch))
6317ec681f3Smrg         iris_batch_flush(batch);
6329f464c52Smaya
6339f464c52Smaya      while (!READ_ONCE(q->map->snapshots_landed)) {
6349f464c52Smaya         if (wait)
6357ec681f3Smrg            iris_wait_syncobj(screen->bufmgr, q->syncobj, INT64_MAX);
6369f464c52Smaya         else
6379f464c52Smaya            return false;
6389f464c52Smaya      }
6399f464c52Smaya
6409f464c52Smaya      assert(READ_ONCE(q->map->snapshots_landed));
6419f464c52Smaya      calculate_result_on_cpu(devinfo, q);
6429f464c52Smaya   }
6439f464c52Smaya
6449f464c52Smaya   assert(q->ready);
6459f464c52Smaya
6469f464c52Smaya   result->u64 = q->result;
6479f464c52Smaya
6489f464c52Smaya   return true;
6499f464c52Smaya}
6509f464c52Smaya
6519f464c52Smayastatic void
6529f464c52Smayairis_get_query_result_resource(struct pipe_context *ctx,
6539f464c52Smaya                               struct pipe_query *query,
6547ec681f3Smrg                               bool wait,
6559f464c52Smaya                               enum pipe_query_value_type result_type,
6569f464c52Smaya                               int index,
6579f464c52Smaya                               struct pipe_resource *p_res,
6589f464c52Smaya                               unsigned offset)
6599f464c52Smaya{
6609f464c52Smaya   struct iris_context *ice = (void *) ctx;
6619f464c52Smaya   struct iris_query *q = (void *) query;
6629f464c52Smaya   struct iris_batch *batch = &ice->batches[q->batch_idx];
6637ec681f3Smrg   const struct intel_device_info *devinfo = &batch->screen->devinfo;
6649f464c52Smaya   struct iris_resource *res = (void *) p_res;
6657ec681f3Smrg   struct iris_bo *query_bo = iris_resource_bo(q->query_state_ref.res);
6667ec681f3Smrg   struct iris_bo *dst_bo = iris_resource_bo(p_res);
6679f464c52Smaya   unsigned snapshots_landed_offset =
6689f464c52Smaya      offsetof(struct iris_query_snapshots, snapshots_landed);
6699f464c52Smaya
6709f464c52Smaya   res->bind_history |= PIPE_BIND_QUERY_BUFFER;
6719f464c52Smaya
6729f464c52Smaya   if (index == -1) {
6739f464c52Smaya      /* They're asking for the availability of the result.  If we still
6749f464c52Smaya       * have commands queued up which produce the result, submit them
6759f464c52Smaya       * now so that progress happens.  Either way, copy the snapshots
6769f464c52Smaya       * landed field to the destination resource.
6779f464c52Smaya       */
6787ec681f3Smrg      if (q->syncobj == iris_batch_get_signal_syncobj(batch))
6799f464c52Smaya         iris_batch_flush(batch);
6809f464c52Smaya
6817ec681f3Smrg      batch->screen->vtbl.copy_mem_mem(batch, dst_bo, offset,
6827ec681f3Smrg                             query_bo, snapshots_landed_offset,
6839f464c52Smaya                             result_type <= PIPE_QUERY_TYPE_U32 ? 4 : 8);
6849f464c52Smaya      return;
6859f464c52Smaya   }
6869f464c52Smaya
6879f464c52Smaya   if (!q->ready && READ_ONCE(q->map->snapshots_landed)) {
6889f464c52Smaya      /* The final snapshots happen to have landed, so let's just compute
6899f464c52Smaya       * the result on the CPU now...
6909f464c52Smaya       */
6919f464c52Smaya      calculate_result_on_cpu(devinfo, q);
6929f464c52Smaya   }
6939f464c52Smaya
6949f464c52Smaya   if (q->ready) {
6959f464c52Smaya      /* We happen to have the result on the CPU, so just copy it. */
6969f464c52Smaya      if (result_type <= PIPE_QUERY_TYPE_U32) {
6977ec681f3Smrg         batch->screen->vtbl.store_data_imm32(batch, dst_bo, offset, q->result);
6989f464c52Smaya      } else {
6997ec681f3Smrg         batch->screen->vtbl.store_data_imm64(batch, dst_bo, offset, q->result);
7009f464c52Smaya      }
7019f464c52Smaya
7029f464c52Smaya      /* Make sure the result lands before they use bind the QBO elsewhere
7039f464c52Smaya       * and use the result.
7049f464c52Smaya       */
7059f464c52Smaya      // XXX: Why?  i965 doesn't do this.
7067ec681f3Smrg      iris_emit_pipe_control_flush(batch,
7077ec681f3Smrg                                   "query: unknown QBO flushing hack",
7087ec681f3Smrg                                   PIPE_CONTROL_CS_STALL);
7099f464c52Smaya      return;
7109f464c52Smaya   }
7119f464c52Smaya
7129f464c52Smaya   bool predicated = !wait && !q->stalled;
7139f464c52Smaya
7147ec681f3Smrg   struct mi_builder b;
7157ec681f3Smrg   mi_builder_init(&b, &batch->screen->devinfo, batch);
7167ec681f3Smrg
7177ec681f3Smrg   iris_batch_sync_region_start(batch);
7189f464c52Smaya
7197ec681f3Smrg   struct mi_value result = calculate_result_on_gpu(devinfo, &b, q);
7207ec681f3Smrg   struct mi_value dst =
7217ec681f3Smrg      result_type <= PIPE_QUERY_TYPE_U32 ?
7227ec681f3Smrg      mi_mem32(rw_bo(dst_bo, offset, IRIS_DOMAIN_OTHER_WRITE)) :
7237ec681f3Smrg      mi_mem64(rw_bo(dst_bo, offset, IRIS_DOMAIN_OTHER_WRITE));
7247ec681f3Smrg
7257ec681f3Smrg   if (predicated) {
7267ec681f3Smrg      mi_store(&b, mi_reg32(MI_PREDICATE_RESULT),
7277ec681f3Smrg                   mi_mem64(ro_bo(query_bo, snapshots_landed_offset)));
7287ec681f3Smrg      mi_store_if(&b, dst, result);
7299f464c52Smaya   } else {
7307ec681f3Smrg      mi_store(&b, dst, result);
7319f464c52Smaya   }
7327ec681f3Smrg
7337ec681f3Smrg   iris_batch_sync_region_end(batch);
7349f464c52Smaya}
7359f464c52Smaya
7369f464c52Smayastatic void
7377ec681f3Smrgiris_set_active_query_state(struct pipe_context *ctx, bool enable)
7389f464c52Smaya{
7399f464c52Smaya   struct iris_context *ice = (void *) ctx;
7409f464c52Smaya
7419f464c52Smaya   if (ice->state.statistics_counters_enabled == enable)
7429f464c52Smaya      return;
7439f464c52Smaya
7449f464c52Smaya   // XXX: most packets aren't paying attention to this yet, because it'd
7459f464c52Smaya   // have to be done dynamically at draw time, which is a pain
7469f464c52Smaya   ice->state.statistics_counters_enabled = enable;
7479f464c52Smaya   ice->state.dirty |= IRIS_DIRTY_CLIP |
7489f464c52Smaya                       IRIS_DIRTY_RASTER |
7499f464c52Smaya                       IRIS_DIRTY_STREAMOUT |
7509f464c52Smaya                       IRIS_DIRTY_WM;
7517ec681f3Smrg   ice->state.stage_dirty |= IRIS_STAGE_DIRTY_GS |
7527ec681f3Smrg                             IRIS_STAGE_DIRTY_TCS |
7537ec681f3Smrg                             IRIS_STAGE_DIRTY_TES |
7547ec681f3Smrg                             IRIS_STAGE_DIRTY_VS;
7559f464c52Smaya}
7569f464c52Smaya
7579f464c52Smayastatic void
7589f464c52Smayaset_predicate_enable(struct iris_context *ice, bool value)
7599f464c52Smaya{
7609f464c52Smaya   if (value)
7619f464c52Smaya      ice->state.predicate = IRIS_PREDICATE_STATE_RENDER;
7629f464c52Smaya   else
7639f464c52Smaya      ice->state.predicate = IRIS_PREDICATE_STATE_DONT_RENDER;
7649f464c52Smaya}
7659f464c52Smaya
7669f464c52Smayastatic void
7679f464c52Smayaset_predicate_for_result(struct iris_context *ice,
7689f464c52Smaya                         struct iris_query *q,
7699f464c52Smaya                         bool inverted)
7709f464c52Smaya{
7719f464c52Smaya   struct iris_batch *batch = &ice->batches[IRIS_BATCH_RENDER];
7729f464c52Smaya   struct iris_bo *bo = iris_resource_bo(q->query_state_ref.res);
7739f464c52Smaya
7747ec681f3Smrg   iris_batch_sync_region_start(batch);
7757ec681f3Smrg
7769f464c52Smaya   /* The CPU doesn't have the query result yet; use hardware predication */
7779f464c52Smaya   ice->state.predicate = IRIS_PREDICATE_STATE_USE_BIT;
7789f464c52Smaya
7799f464c52Smaya   /* Ensure the memory is coherent for MI_LOAD_REGISTER_* commands. */
7807ec681f3Smrg   iris_emit_pipe_control_flush(batch,
7817ec681f3Smrg                                "conditional rendering: set predicate",
7827ec681f3Smrg                                PIPE_CONTROL_FLUSH_ENABLE);
7839f464c52Smaya   q->stalled = true;
7849f464c52Smaya
7857ec681f3Smrg   struct mi_builder b;
7867ec681f3Smrg   mi_builder_init(&b, &batch->screen->devinfo, batch);
7877ec681f3Smrg
7887ec681f3Smrg   struct mi_value result;
7897ec681f3Smrg
7909f464c52Smaya   switch (q->type) {
7919f464c52Smaya   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
7927ec681f3Smrg      result = calc_overflow_for_stream(&b, q, q->index);
7937ec681f3Smrg      break;
7949f464c52Smaya   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
7957ec681f3Smrg      result = calc_overflow_any_stream(&b, q);
7969f464c52Smaya      break;
7977ec681f3Smrg   default: {
7989f464c52Smaya      /* PIPE_QUERY_OCCLUSION_* */
7997ec681f3Smrg      struct mi_value start =
8007ec681f3Smrg         query_mem64(q, offsetof(struct iris_query_snapshots, start));
8017ec681f3Smrg      struct mi_value end =
8027ec681f3Smrg         query_mem64(q, offsetof(struct iris_query_snapshots, end));
8037ec681f3Smrg      result = mi_isub(&b, end, start);
8049f464c52Smaya      break;
8059f464c52Smaya   }
8067ec681f3Smrg   }
8079f464c52Smaya
8087ec681f3Smrg   result = inverted ? mi_z(&b, result) : mi_nz(&b, result);
8097ec681f3Smrg   result = mi_iand(&b, result, mi_imm(1));
8109f464c52Smaya
8119f464c52Smaya   /* We immediately set the predicate on the render batch, as all the
8129f464c52Smaya    * counters come from 3D operations.  However, we may need to predicate
8139f464c52Smaya    * a compute dispatch, which executes in a different GEM context and has
8149f464c52Smaya    * a different MI_PREDICATE_RESULT register.  So, we save the result to
8159f464c52Smaya    * memory and reload it in iris_launch_grid.
8169f464c52Smaya    */
8177ec681f3Smrg   mi_value_ref(&b, result);
8187ec681f3Smrg   mi_store(&b, mi_reg32(MI_PREDICATE_RESULT), result);
8197ec681f3Smrg   mi_store(&b, query_mem64(q, offsetof(struct iris_query_snapshots,
8207ec681f3Smrg                                        predicate_result)), result);
8219f464c52Smaya   ice->state.compute_predicate = bo;
8227ec681f3Smrg
8237ec681f3Smrg   iris_batch_sync_region_end(batch);
8249f464c52Smaya}
8259f464c52Smaya
8269f464c52Smayastatic void
8279f464c52Smayairis_render_condition(struct pipe_context *ctx,
8289f464c52Smaya                      struct pipe_query *query,
8297ec681f3Smrg                      bool condition,
8309f464c52Smaya                      enum pipe_render_cond_flag mode)
8319f464c52Smaya{
8329f464c52Smaya   struct iris_context *ice = (void *) ctx;
8339f464c52Smaya   struct iris_query *q = (void *) query;
8349f464c52Smaya
8359f464c52Smaya   /* The old condition isn't relevant; we'll update it if necessary */
8369f464c52Smaya   ice->state.compute_predicate = NULL;
8379f464c52Smaya
8389f464c52Smaya   if (!q) {
8399f464c52Smaya      ice->state.predicate = IRIS_PREDICATE_STATE_RENDER;
8409f464c52Smaya      return;
8419f464c52Smaya   }
8429f464c52Smaya
8439f464c52Smaya   iris_check_query_no_flush(ice, q);
8449f464c52Smaya
8459f464c52Smaya   if (q->result || q->ready) {
8469f464c52Smaya      set_predicate_enable(ice, (q->result != 0) ^ condition);
8479f464c52Smaya   } else {
8489f464c52Smaya      if (mode == PIPE_RENDER_COND_NO_WAIT ||
8499f464c52Smaya          mode == PIPE_RENDER_COND_BY_REGION_NO_WAIT) {
8509f464c52Smaya         perf_debug(&ice->dbg, "Conditional rendering demoted from "
8519f464c52Smaya                    "\"no wait\" to \"wait\".");
8529f464c52Smaya      }
8539f464c52Smaya      set_predicate_for_result(ice, q, condition);
8549f464c52Smaya   }
8559f464c52Smaya}
8569f464c52Smaya
8579f464c52Smayavoid
8587ec681f3SmrggenX(init_query)(struct iris_context *ice)
8599f464c52Smaya{
8607ec681f3Smrg   struct pipe_context *ctx = &ice->ctx;
8619f464c52Smaya
8629f464c52Smaya   ctx->create_query = iris_create_query;
8637ec681f3Smrg   ctx->create_batch_query = iris_create_batch_query;
8649f464c52Smaya   ctx->destroy_query = iris_destroy_query;
8659f464c52Smaya   ctx->begin_query = iris_begin_query;
8669f464c52Smaya   ctx->end_query = iris_end_query;
8679f464c52Smaya   ctx->get_query_result = iris_get_query_result;
8689f464c52Smaya   ctx->get_query_result_resource = iris_get_query_result_resource;
8699f464c52Smaya   ctx->set_active_query_state = iris_set_active_query_state;
8709f464c52Smaya   ctx->render_condition = iris_render_condition;
8719f464c52Smaya}
872