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