1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © Microsoft 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 (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "d3d12_query.h" 25bf215546Sopenharmony_ci#include "d3d12_compiler.h" 26bf215546Sopenharmony_ci#include "d3d12_context.h" 27bf215546Sopenharmony_ci#include "d3d12_resource.h" 28bf215546Sopenharmony_ci#include "d3d12_screen.h" 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include "util/u_dump.h" 31bf215546Sopenharmony_ci#include "util/u_inlines.h" 32bf215546Sopenharmony_ci#include "util/u_memory.h" 33bf215546Sopenharmony_ci#include "util/u_threaded_context.h" 34bf215546Sopenharmony_ci 35bf215546Sopenharmony_ci#include <dxguids/dxguids.h> 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_ciconstexpr unsigned MAX_SUBQUERIES = 3; 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_cistruct d3d12_query_impl { 40bf215546Sopenharmony_ci ID3D12QueryHeap *query_heap; 41bf215546Sopenharmony_ci unsigned curr_query, num_queries; 42bf215546Sopenharmony_ci size_t query_size; 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci D3D12_QUERY_TYPE d3d12qtype; 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_ci pipe_resource *buffer; 47bf215546Sopenharmony_ci unsigned buffer_offset; 48bf215546Sopenharmony_ci 49bf215546Sopenharmony_ci bool active; 50bf215546Sopenharmony_ci}; 51bf215546Sopenharmony_ci 52bf215546Sopenharmony_cistruct d3d12_query { 53bf215546Sopenharmony_ci struct threaded_query base; 54bf215546Sopenharmony_ci enum pipe_query_type type; 55bf215546Sopenharmony_ci 56bf215546Sopenharmony_ci struct d3d12_query_impl subqueries[MAX_SUBQUERIES]; 57bf215546Sopenharmony_ci 58bf215546Sopenharmony_ci struct list_head active_list; 59bf215546Sopenharmony_ci struct d3d12_resource *predicate; 60bf215546Sopenharmony_ci}; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic unsigned 63bf215546Sopenharmony_cinum_sub_queries(unsigned query_type) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci switch (query_type) { 66bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_GENERATED: 67bf215546Sopenharmony_ci return 3; 68bf215546Sopenharmony_ci default: 69bf215546Sopenharmony_ci return 1; 70bf215546Sopenharmony_ci } 71bf215546Sopenharmony_ci} 72bf215546Sopenharmony_ci 73bf215546Sopenharmony_cistatic D3D12_QUERY_HEAP_TYPE 74bf215546Sopenharmony_cid3d12_query_heap_type(unsigned query_type, unsigned sub_query) 75bf215546Sopenharmony_ci{ 76bf215546Sopenharmony_ci switch (query_type) { 77bf215546Sopenharmony_ci case PIPE_QUERY_OCCLUSION_COUNTER: 78bf215546Sopenharmony_ci case PIPE_QUERY_OCCLUSION_PREDICATE: 79bf215546Sopenharmony_ci case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 80bf215546Sopenharmony_ci return D3D12_QUERY_HEAP_TYPE_OCCLUSION; 81bf215546Sopenharmony_ci case PIPE_QUERY_PIPELINE_STATISTICS: 82bf215546Sopenharmony_ci return D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS; 83bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_GENERATED: 84bf215546Sopenharmony_ci return sub_query == 0 ? 85bf215546Sopenharmony_ci D3D12_QUERY_HEAP_TYPE_SO_STATISTICS : 86bf215546Sopenharmony_ci D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS; 87bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_EMITTED: 88bf215546Sopenharmony_ci case PIPE_QUERY_SO_STATISTICS: 89bf215546Sopenharmony_ci return D3D12_QUERY_HEAP_TYPE_SO_STATISTICS; 90bf215546Sopenharmony_ci case PIPE_QUERY_TIMESTAMP: 91bf215546Sopenharmony_ci case PIPE_QUERY_TIME_ELAPSED: 92bf215546Sopenharmony_ci return D3D12_QUERY_HEAP_TYPE_TIMESTAMP; 93bf215546Sopenharmony_ci 94bf215546Sopenharmony_ci default: 95bf215546Sopenharmony_ci debug_printf("unknown query: %s\n", 96bf215546Sopenharmony_ci util_str_query_type(query_type, true)); 97bf215546Sopenharmony_ci unreachable("d3d12: unknown query type"); 98bf215546Sopenharmony_ci } 99bf215546Sopenharmony_ci} 100bf215546Sopenharmony_ci 101bf215546Sopenharmony_cistatic D3D12_QUERY_TYPE 102bf215546Sopenharmony_cid3d12_query_type(unsigned query_type, unsigned sub_query, unsigned index) 103bf215546Sopenharmony_ci{ 104bf215546Sopenharmony_ci switch (query_type) { 105bf215546Sopenharmony_ci case PIPE_QUERY_OCCLUSION_COUNTER: 106bf215546Sopenharmony_ci return D3D12_QUERY_TYPE_OCCLUSION; 107bf215546Sopenharmony_ci case PIPE_QUERY_OCCLUSION_PREDICATE: 108bf215546Sopenharmony_ci case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 109bf215546Sopenharmony_ci return D3D12_QUERY_TYPE_BINARY_OCCLUSION; 110bf215546Sopenharmony_ci case PIPE_QUERY_PIPELINE_STATISTICS: 111bf215546Sopenharmony_ci return D3D12_QUERY_TYPE_PIPELINE_STATISTICS; 112bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_GENERATED: 113bf215546Sopenharmony_ci return sub_query == 0 ? 114bf215546Sopenharmony_ci D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 : 115bf215546Sopenharmony_ci D3D12_QUERY_TYPE_PIPELINE_STATISTICS; 116bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_EMITTED: 117bf215546Sopenharmony_ci case PIPE_QUERY_SO_STATISTICS: 118bf215546Sopenharmony_ci return (D3D12_QUERY_TYPE)(D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0 + index); 119bf215546Sopenharmony_ci case PIPE_QUERY_TIMESTAMP: 120bf215546Sopenharmony_ci case PIPE_QUERY_TIME_ELAPSED: 121bf215546Sopenharmony_ci return D3D12_QUERY_TYPE_TIMESTAMP; 122bf215546Sopenharmony_ci default: 123bf215546Sopenharmony_ci debug_printf("unknown query: %s\n", 124bf215546Sopenharmony_ci util_str_query_type(query_type, true)); 125bf215546Sopenharmony_ci unreachable("d3d12: unknown query type"); 126bf215546Sopenharmony_ci } 127bf215546Sopenharmony_ci} 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_cistatic struct pipe_query * 130bf215546Sopenharmony_cid3d12_create_query(struct pipe_context *pctx, 131bf215546Sopenharmony_ci unsigned query_type, unsigned index) 132bf215546Sopenharmony_ci{ 133bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 134bf215546Sopenharmony_ci struct d3d12_screen *screen = d3d12_screen(pctx->screen); 135bf215546Sopenharmony_ci struct d3d12_query *query = CALLOC_STRUCT(d3d12_query); 136bf215546Sopenharmony_ci D3D12_QUERY_HEAP_DESC desc = {}; 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci if (!query) 139bf215546Sopenharmony_ci return NULL; 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ci query->type = (pipe_query_type)query_type; 142bf215546Sopenharmony_ci for (unsigned i = 0; i < num_sub_queries(query_type); ++i) { 143bf215546Sopenharmony_ci assert(i < MAX_SUBQUERIES); 144bf215546Sopenharmony_ci query->subqueries[i].d3d12qtype = d3d12_query_type(query_type, i, index); 145bf215546Sopenharmony_ci query->subqueries[i].num_queries = 16; 146bf215546Sopenharmony_ci 147bf215546Sopenharmony_ci /* With timer queries we want a few more queries, especially since we need two slots 148bf215546Sopenharmony_ci * per query for TIME_ELAPSED queries 149bf215546Sopenharmony_ci * For TIMESTAMP, we don't need more than one slot, since there's nothing to accumulate */ 150bf215546Sopenharmony_ci if (unlikely(query_type == PIPE_QUERY_TIME_ELAPSED)) 151bf215546Sopenharmony_ci query->subqueries[i].num_queries = 64; 152bf215546Sopenharmony_ci else if (query_type == PIPE_QUERY_TIMESTAMP) 153bf215546Sopenharmony_ci query->subqueries[i].num_queries = 1; 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_ci query->subqueries[i].curr_query = 0; 156bf215546Sopenharmony_ci desc.Count = query->subqueries[i].num_queries; 157bf215546Sopenharmony_ci desc.Type = d3d12_query_heap_type(query_type, i); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci switch (desc.Type) { 160bf215546Sopenharmony_ci case D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS: 161bf215546Sopenharmony_ci query->subqueries[i].query_size = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS); 162bf215546Sopenharmony_ci break; 163bf215546Sopenharmony_ci case D3D12_QUERY_HEAP_TYPE_SO_STATISTICS: 164bf215546Sopenharmony_ci query->subqueries[i].query_size = sizeof(D3D12_QUERY_DATA_SO_STATISTICS); 165bf215546Sopenharmony_ci break; 166bf215546Sopenharmony_ci default: 167bf215546Sopenharmony_ci query->subqueries[i].query_size = sizeof(uint64_t); 168bf215546Sopenharmony_ci break; 169bf215546Sopenharmony_ci } 170bf215546Sopenharmony_ci if (FAILED(screen->dev->CreateQueryHeap(&desc, 171bf215546Sopenharmony_ci IID_PPV_ARGS(&query->subqueries[i].query_heap)))) { 172bf215546Sopenharmony_ci FREE(query); 173bf215546Sopenharmony_ci return NULL; 174bf215546Sopenharmony_ci } 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci /* Query result goes into a readback buffer */ 177bf215546Sopenharmony_ci size_t buffer_size = query->subqueries[i].query_size * query->subqueries[i].num_queries; 178bf215546Sopenharmony_ci u_suballocator_alloc(&ctx->query_allocator, buffer_size, 256, 179bf215546Sopenharmony_ci &query->subqueries[i].buffer_offset, &query->subqueries[i].buffer); 180bf215546Sopenharmony_ci 181bf215546Sopenharmony_ci query->subqueries[i].active = (query_type == PIPE_QUERY_TIMESTAMP); 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci return (struct pipe_query *)query; 185bf215546Sopenharmony_ci} 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_cistatic void 188bf215546Sopenharmony_cid3d12_destroy_query(struct pipe_context *pctx, 189bf215546Sopenharmony_ci struct pipe_query *q) 190bf215546Sopenharmony_ci{ 191bf215546Sopenharmony_ci struct d3d12_query *query = (struct d3d12_query *)q; 192bf215546Sopenharmony_ci pipe_resource *predicate = &query->predicate->base.b; 193bf215546Sopenharmony_ci pipe_resource_reference(&predicate, NULL); 194bf215546Sopenharmony_ci for (unsigned i = 0; i < num_sub_queries(query->type); ++i) { 195bf215546Sopenharmony_ci query->subqueries[i].query_heap->Release(); 196bf215546Sopenharmony_ci pipe_resource_reference(&query->subqueries[i].buffer, NULL); 197bf215546Sopenharmony_ci } 198bf215546Sopenharmony_ci FREE(query); 199bf215546Sopenharmony_ci} 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_cistatic bool 202bf215546Sopenharmony_ciaccumulate_subresult(struct d3d12_context *ctx, struct d3d12_query *q_parent, 203bf215546Sopenharmony_ci unsigned sub_query, 204bf215546Sopenharmony_ci union pipe_query_result *result, bool write, bool wait) 205bf215546Sopenharmony_ci{ 206bf215546Sopenharmony_ci struct pipe_transfer *transfer = NULL; 207bf215546Sopenharmony_ci struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 208bf215546Sopenharmony_ci struct d3d12_query_impl *q = &q_parent->subqueries[sub_query]; 209bf215546Sopenharmony_ci unsigned access = PIPE_MAP_READ; 210bf215546Sopenharmony_ci void *results; 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci if (write) 213bf215546Sopenharmony_ci access |= PIPE_MAP_WRITE; 214bf215546Sopenharmony_ci if (!wait) 215bf215546Sopenharmony_ci access |= PIPE_MAP_DONTBLOCK; 216bf215546Sopenharmony_ci results = pipe_buffer_map_range(&ctx->base, q->buffer, q->buffer_offset, 217bf215546Sopenharmony_ci q->num_queries * q->query_size, 218bf215546Sopenharmony_ci access, &transfer); 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci if (results == NULL) 221bf215546Sopenharmony_ci return false; 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci uint64_t *results_u64 = (uint64_t *)results; 224bf215546Sopenharmony_ci D3D12_QUERY_DATA_PIPELINE_STATISTICS *results_stats = (D3D12_QUERY_DATA_PIPELINE_STATISTICS *)results; 225bf215546Sopenharmony_ci D3D12_QUERY_DATA_SO_STATISTICS *results_so = (D3D12_QUERY_DATA_SO_STATISTICS *)results; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci memset(result, 0, sizeof(*result)); 228bf215546Sopenharmony_ci for (unsigned i = 0; i < q->curr_query; ++i) { 229bf215546Sopenharmony_ci switch (q->d3d12qtype) { 230bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_BINARY_OCCLUSION: 231bf215546Sopenharmony_ci result->b |= results_u64[i] != 0; 232bf215546Sopenharmony_ci break; 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_OCCLUSION: 235bf215546Sopenharmony_ci result->u64 += results_u64[i]; 236bf215546Sopenharmony_ci break; 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_TIMESTAMP: 239bf215546Sopenharmony_ci if (q_parent->type == PIPE_QUERY_TIME_ELAPSED) 240bf215546Sopenharmony_ci result->u64 += results_u64[2 * i + 1] - results_u64[2 * i]; 241bf215546Sopenharmony_ci else 242bf215546Sopenharmony_ci result->u64 = results_u64[i]; 243bf215546Sopenharmony_ci break; 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_PIPELINE_STATISTICS: 246bf215546Sopenharmony_ci result->pipeline_statistics.ia_vertices += results_stats[i].IAVertices; 247bf215546Sopenharmony_ci result->pipeline_statistics.ia_primitives += results_stats[i].IAPrimitives; 248bf215546Sopenharmony_ci result->pipeline_statistics.vs_invocations += results_stats[i].VSInvocations; 249bf215546Sopenharmony_ci result->pipeline_statistics.gs_invocations += results_stats[i].GSInvocations; 250bf215546Sopenharmony_ci result->pipeline_statistics.gs_primitives += results_stats[i].GSPrimitives; 251bf215546Sopenharmony_ci result->pipeline_statistics.c_invocations += results_stats[i].CInvocations; 252bf215546Sopenharmony_ci result->pipeline_statistics.c_primitives += results_stats[i].CPrimitives; 253bf215546Sopenharmony_ci result->pipeline_statistics.ps_invocations += results_stats[i].PSInvocations; 254bf215546Sopenharmony_ci result->pipeline_statistics.hs_invocations += results_stats[i].HSInvocations; 255bf215546Sopenharmony_ci result->pipeline_statistics.ds_invocations += results_stats[i].DSInvocations; 256bf215546Sopenharmony_ci result->pipeline_statistics.cs_invocations += results_stats[i].CSInvocations; 257bf215546Sopenharmony_ci break; 258bf215546Sopenharmony_ci 259bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0: 260bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM1: 261bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM2: 262bf215546Sopenharmony_ci case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM3: 263bf215546Sopenharmony_ci result->so_statistics.num_primitives_written += results_so[i].NumPrimitivesWritten; 264bf215546Sopenharmony_ci result->so_statistics.primitives_storage_needed += results_so[i].PrimitivesStorageNeeded; 265bf215546Sopenharmony_ci break; 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci default: 268bf215546Sopenharmony_ci debug_printf("unsupported query type: %s\n", 269bf215546Sopenharmony_ci util_str_query_type(q_parent->type, true)); 270bf215546Sopenharmony_ci unreachable("unexpected query type"); 271bf215546Sopenharmony_ci } 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci if (write) { 275bf215546Sopenharmony_ci if (q->d3d12qtype == D3D12_QUERY_TYPE_PIPELINE_STATISTICS) { 276bf215546Sopenharmony_ci results_stats[0].IAVertices = result->pipeline_statistics.ia_vertices; 277bf215546Sopenharmony_ci results_stats[0].IAPrimitives = result->pipeline_statistics.ia_primitives; 278bf215546Sopenharmony_ci results_stats[0].VSInvocations = result->pipeline_statistics.vs_invocations; 279bf215546Sopenharmony_ci results_stats[0].GSInvocations = result->pipeline_statistics.gs_invocations; 280bf215546Sopenharmony_ci results_stats[0].GSPrimitives = result->pipeline_statistics.gs_primitives; 281bf215546Sopenharmony_ci results_stats[0].CInvocations = result->pipeline_statistics.c_invocations; 282bf215546Sopenharmony_ci results_stats[0].CPrimitives = result->pipeline_statistics.c_primitives; 283bf215546Sopenharmony_ci results_stats[0].PSInvocations = result->pipeline_statistics.ps_invocations; 284bf215546Sopenharmony_ci results_stats[0].HSInvocations = result->pipeline_statistics.hs_invocations; 285bf215546Sopenharmony_ci results_stats[0].DSInvocations = result->pipeline_statistics.ds_invocations; 286bf215546Sopenharmony_ci results_stats[0].CSInvocations = result->pipeline_statistics.cs_invocations; 287bf215546Sopenharmony_ci } else if (d3d12_query_heap_type(q_parent->type, sub_query) == D3D12_QUERY_HEAP_TYPE_SO_STATISTICS) { 288bf215546Sopenharmony_ci results_so[0].NumPrimitivesWritten = result->so_statistics.num_primitives_written; 289bf215546Sopenharmony_ci results_so[0].PrimitivesStorageNeeded = result->so_statistics.primitives_storage_needed; 290bf215546Sopenharmony_ci } else { 291bf215546Sopenharmony_ci if (unlikely(q->d3d12qtype == D3D12_QUERY_TYPE_TIMESTAMP)) { 292bf215546Sopenharmony_ci results_u64[0] = 0; 293bf215546Sopenharmony_ci results_u64[1] = result->u64; 294bf215546Sopenharmony_ci } else { 295bf215546Sopenharmony_ci results_u64[0] = result->u64; 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci } 298bf215546Sopenharmony_ci } 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci pipe_buffer_unmap(&ctx->base, transfer); 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci if (q->d3d12qtype == D3D12_QUERY_TYPE_TIMESTAMP) 303bf215546Sopenharmony_ci result->u64 = static_cast<uint64_t>(screen->timestamp_multiplier * result->u64); 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci return true; 306bf215546Sopenharmony_ci} 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_cistatic bool 309bf215546Sopenharmony_ciaccumulate_result(struct d3d12_context *ctx, struct d3d12_query *q, 310bf215546Sopenharmony_ci union pipe_query_result *result, bool write, bool wait) 311bf215546Sopenharmony_ci{ 312bf215546Sopenharmony_ci union pipe_query_result local_result; 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci switch (q->type) { 315bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_GENERATED: 316bf215546Sopenharmony_ci if (!accumulate_subresult(ctx, q, 0, &local_result, write, wait)) 317bf215546Sopenharmony_ci return false; 318bf215546Sopenharmony_ci result->u64 = local_result.so_statistics.primitives_storage_needed; 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci if (!accumulate_subresult(ctx, q, 1, &local_result, write, wait)) 321bf215546Sopenharmony_ci return false; 322bf215546Sopenharmony_ci result->u64 += local_result.pipeline_statistics.gs_primitives; 323bf215546Sopenharmony_ci 324bf215546Sopenharmony_ci if (!accumulate_subresult(ctx, q, 2, &local_result, write, wait)) 325bf215546Sopenharmony_ci return false; 326bf215546Sopenharmony_ci result->u64 += local_result.pipeline_statistics.ia_primitives; 327bf215546Sopenharmony_ci return true; 328bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_EMITTED: 329bf215546Sopenharmony_ci if (!accumulate_subresult(ctx, q, 0, &local_result, write, wait)) 330bf215546Sopenharmony_ci return false; 331bf215546Sopenharmony_ci result->u64 = local_result.so_statistics.num_primitives_written; 332bf215546Sopenharmony_ci return true; 333bf215546Sopenharmony_ci default: 334bf215546Sopenharmony_ci assert(num_sub_queries(q->type) == 1); 335bf215546Sopenharmony_ci return accumulate_subresult(ctx, q, 0, result, write, wait); 336bf215546Sopenharmony_ci } 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_cistatic bool 340bf215546Sopenharmony_cisubquery_should_be_active(struct d3d12_context *ctx, struct d3d12_query *q, unsigned sub_query) 341bf215546Sopenharmony_ci{ 342bf215546Sopenharmony_ci switch (q->type) { 343bf215546Sopenharmony_ci case PIPE_QUERY_PRIMITIVES_GENERATED: { 344bf215546Sopenharmony_ci bool has_xfb = !!ctx->gfx_pipeline_state.num_so_targets; 345bf215546Sopenharmony_ci struct d3d12_shader_selector *gs = ctx->gfx_stages[PIPE_SHADER_GEOMETRY]; 346bf215546Sopenharmony_ci bool has_gs = gs && !gs->is_variant; 347bf215546Sopenharmony_ci switch (sub_query) { 348bf215546Sopenharmony_ci case 0: return has_xfb; 349bf215546Sopenharmony_ci case 1: return !has_xfb && has_gs; 350bf215546Sopenharmony_ci case 2: return !has_xfb && !has_gs; 351bf215546Sopenharmony_ci default: unreachable("Invalid subquery for primitives generated"); 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci break; 354bf215546Sopenharmony_ci } 355bf215546Sopenharmony_ci default: 356bf215546Sopenharmony_ci return true; 357bf215546Sopenharmony_ci } 358bf215546Sopenharmony_ci} 359bf215546Sopenharmony_ci 360bf215546Sopenharmony_cistatic void 361bf215546Sopenharmony_cibegin_subquery(struct d3d12_context *ctx, struct d3d12_query *q_parent, unsigned sub_query) 362bf215546Sopenharmony_ci{ 363bf215546Sopenharmony_ci struct d3d12_query_impl *q = &q_parent->subqueries[sub_query]; 364bf215546Sopenharmony_ci if (q->curr_query == q->num_queries) { 365bf215546Sopenharmony_ci union pipe_query_result result; 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci /* Accumulate current results and store in first slot */ 368bf215546Sopenharmony_ci accumulate_subresult(ctx, q_parent, sub_query, &result, true, true); 369bf215546Sopenharmony_ci q->curr_query = 1; 370bf215546Sopenharmony_ci } 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci ctx->cmdlist->BeginQuery(q->query_heap, q->d3d12qtype, q->curr_query); 373bf215546Sopenharmony_ci q->active = true; 374bf215546Sopenharmony_ci} 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_cistatic void 377bf215546Sopenharmony_cibegin_query(struct d3d12_context *ctx, struct d3d12_query *q_parent, bool restart) 378bf215546Sopenharmony_ci{ 379bf215546Sopenharmony_ci for (unsigned i = 0; i < num_sub_queries(q_parent->type); ++i) { 380bf215546Sopenharmony_ci if (restart) 381bf215546Sopenharmony_ci q_parent->subqueries[i].curr_query = 0; 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci if (!subquery_should_be_active(ctx, q_parent, i)) 384bf215546Sopenharmony_ci continue; 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci begin_subquery(ctx, q_parent, i); 387bf215546Sopenharmony_ci } 388bf215546Sopenharmony_ci} 389bf215546Sopenharmony_ci 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_cistatic void 392bf215546Sopenharmony_cibegin_timer_query(struct d3d12_context *ctx, struct d3d12_query *q_parent, bool restart) 393bf215546Sopenharmony_ci{ 394bf215546Sopenharmony_ci struct d3d12_query_impl *q = &q_parent->subqueries[0]; 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci /* For PIPE_QUERY_TIME_ELAPSED we record one time with BeginQuery and one in 397bf215546Sopenharmony_ci * EndQuery, so we need two query slots */ 398bf215546Sopenharmony_ci unsigned query_index = 2 * q->curr_query; 399bf215546Sopenharmony_ci 400bf215546Sopenharmony_ci if (restart) { 401bf215546Sopenharmony_ci q->curr_query = 0; 402bf215546Sopenharmony_ci query_index = 0; 403bf215546Sopenharmony_ci } else if (query_index == q->num_queries) { 404bf215546Sopenharmony_ci union pipe_query_result result; 405bf215546Sopenharmony_ci 406bf215546Sopenharmony_ci /* Accumulate current results and store in first slot */ 407bf215546Sopenharmony_ci d3d12_flush_cmdlist_and_wait(ctx); 408bf215546Sopenharmony_ci accumulate_subresult(ctx, q_parent, 0, &result, true, true); 409bf215546Sopenharmony_ci q->curr_query = 2; 410bf215546Sopenharmony_ci } 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci ctx->cmdlist->EndQuery(q->query_heap, q->d3d12qtype, query_index); 413bf215546Sopenharmony_ci q->active = true; 414bf215546Sopenharmony_ci} 415bf215546Sopenharmony_ci 416bf215546Sopenharmony_cistatic bool 417bf215546Sopenharmony_cid3d12_begin_query(struct pipe_context *pctx, 418bf215546Sopenharmony_ci struct pipe_query *q) 419bf215546Sopenharmony_ci{ 420bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 421bf215546Sopenharmony_ci struct d3d12_query *query = (struct d3d12_query *)q; 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci assert(query->type != PIPE_QUERY_TIMESTAMP); 424bf215546Sopenharmony_ci 425bf215546Sopenharmony_ci if (unlikely(query->type == PIPE_QUERY_TIME_ELAPSED)) 426bf215546Sopenharmony_ci begin_timer_query(ctx, query, true); 427bf215546Sopenharmony_ci else { 428bf215546Sopenharmony_ci begin_query(ctx, query, true); 429bf215546Sopenharmony_ci list_addtail(&query->active_list, &ctx->active_queries); 430bf215546Sopenharmony_ci } 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci return true; 433bf215546Sopenharmony_ci} 434bf215546Sopenharmony_ci 435bf215546Sopenharmony_cistatic void 436bf215546Sopenharmony_ciend_subquery(struct d3d12_context *ctx, struct d3d12_query *q_parent, unsigned sub_query) 437bf215546Sopenharmony_ci{ 438bf215546Sopenharmony_ci struct d3d12_query_impl *q = &q_parent->subqueries[sub_query]; 439bf215546Sopenharmony_ci 440bf215546Sopenharmony_ci uint64_t offset = 0; 441bf215546Sopenharmony_ci struct d3d12_batch *batch = d3d12_current_batch(ctx); 442bf215546Sopenharmony_ci struct d3d12_resource *res = (struct d3d12_resource *)q->buffer; 443bf215546Sopenharmony_ci ID3D12Resource *d3d12_res = d3d12_resource_underlying(res, &offset); 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci /* For TIMESTAMP, there's only one slot */ 446bf215546Sopenharmony_ci if (q_parent->type == PIPE_QUERY_TIMESTAMP) 447bf215546Sopenharmony_ci q->curr_query = 0; 448bf215546Sopenharmony_ci 449bf215546Sopenharmony_ci /* With QUERY_TIME_ELAPSED we have recorded one value at 450bf215546Sopenharmony_ci * (2 * q->curr_query), and now we record a value at (2 * q->curr_query + 1) 451bf215546Sopenharmony_ci * and when resolving the query we subtract the latter from the former */ 452bf215546Sopenharmony_ci 453bf215546Sopenharmony_ci unsigned resolve_count = q_parent->type == PIPE_QUERY_TIME_ELAPSED ? 2 : 1; 454bf215546Sopenharmony_ci unsigned resolve_index = resolve_count * q->curr_query; 455bf215546Sopenharmony_ci unsigned end_index = resolve_index + resolve_count - 1; 456bf215546Sopenharmony_ci 457bf215546Sopenharmony_ci offset += q->buffer_offset + resolve_index * q->query_size; 458bf215546Sopenharmony_ci ctx->cmdlist->EndQuery(q->query_heap, q->d3d12qtype, end_index); 459bf215546Sopenharmony_ci d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 460bf215546Sopenharmony_ci d3d12_apply_resource_states(ctx, false); 461bf215546Sopenharmony_ci ctx->cmdlist->ResolveQueryData(q->query_heap, q->d3d12qtype, resolve_index, 462bf215546Sopenharmony_ci resolve_count, d3d12_res, offset); 463bf215546Sopenharmony_ci 464bf215546Sopenharmony_ci d3d12_batch_reference_object(batch, q->query_heap); 465bf215546Sopenharmony_ci d3d12_batch_reference_resource(batch, res, true); 466bf215546Sopenharmony_ci 467bf215546Sopenharmony_ci assert(q->curr_query < q->num_queries); 468bf215546Sopenharmony_ci q->curr_query++; 469bf215546Sopenharmony_ci q->active = (q_parent->type == PIPE_QUERY_TIMESTAMP); 470bf215546Sopenharmony_ci} 471bf215546Sopenharmony_ci 472bf215546Sopenharmony_cistatic void 473bf215546Sopenharmony_ciend_query(struct d3d12_context *ctx, struct d3d12_query *q_parent) 474bf215546Sopenharmony_ci{ 475bf215546Sopenharmony_ci for (unsigned i = 0; i < num_sub_queries(q_parent->type); ++i) { 476bf215546Sopenharmony_ci struct d3d12_query_impl *q = &q_parent->subqueries[i]; 477bf215546Sopenharmony_ci if (!q->active) 478bf215546Sopenharmony_ci continue; 479bf215546Sopenharmony_ci 480bf215546Sopenharmony_ci end_subquery(ctx, q_parent, i); 481bf215546Sopenharmony_ci } 482bf215546Sopenharmony_ci} 483bf215546Sopenharmony_ci 484bf215546Sopenharmony_cistatic bool 485bf215546Sopenharmony_cid3d12_end_query(struct pipe_context *pctx, 486bf215546Sopenharmony_ci struct pipe_query *q) 487bf215546Sopenharmony_ci{ 488bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 489bf215546Sopenharmony_ci struct d3d12_query *query = (struct d3d12_query *)q; 490bf215546Sopenharmony_ci 491bf215546Sopenharmony_ci end_query(ctx, query); 492bf215546Sopenharmony_ci 493bf215546Sopenharmony_ci if (query->type != PIPE_QUERY_TIMESTAMP && 494bf215546Sopenharmony_ci query->type != PIPE_QUERY_TIME_ELAPSED) 495bf215546Sopenharmony_ci list_delinit(&query->active_list); 496bf215546Sopenharmony_ci return true; 497bf215546Sopenharmony_ci} 498bf215546Sopenharmony_ci 499bf215546Sopenharmony_cistatic bool 500bf215546Sopenharmony_cid3d12_get_query_result(struct pipe_context *pctx, 501bf215546Sopenharmony_ci struct pipe_query *q, 502bf215546Sopenharmony_ci bool wait, 503bf215546Sopenharmony_ci union pipe_query_result *result) 504bf215546Sopenharmony_ci{ 505bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 506bf215546Sopenharmony_ci struct d3d12_query *query = (struct d3d12_query *)q; 507bf215546Sopenharmony_ci 508bf215546Sopenharmony_ci return accumulate_result(ctx, query, result, false, wait); 509bf215546Sopenharmony_ci} 510bf215546Sopenharmony_ci 511bf215546Sopenharmony_civoid 512bf215546Sopenharmony_cid3d12_suspend_queries(struct d3d12_context *ctx) 513bf215546Sopenharmony_ci{ 514bf215546Sopenharmony_ci list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) { 515bf215546Sopenharmony_ci end_query(ctx, query); 516bf215546Sopenharmony_ci } 517bf215546Sopenharmony_ci} 518bf215546Sopenharmony_ci 519bf215546Sopenharmony_civoid 520bf215546Sopenharmony_cid3d12_resume_queries(struct d3d12_context *ctx) 521bf215546Sopenharmony_ci{ 522bf215546Sopenharmony_ci list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) { 523bf215546Sopenharmony_ci begin_query(ctx, query, false); 524bf215546Sopenharmony_ci } 525bf215546Sopenharmony_ci} 526bf215546Sopenharmony_ci 527bf215546Sopenharmony_civoid 528bf215546Sopenharmony_cid3d12_validate_queries(struct d3d12_context *ctx) 529bf215546Sopenharmony_ci{ 530bf215546Sopenharmony_ci /* Nothing to do, all queries are suspended */ 531bf215546Sopenharmony_ci if (ctx->queries_disabled) 532bf215546Sopenharmony_ci return; 533bf215546Sopenharmony_ci 534bf215546Sopenharmony_ci list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) { 535bf215546Sopenharmony_ci for (unsigned i = 0; i < num_sub_queries(query->type); ++i) { 536bf215546Sopenharmony_ci if (query->subqueries[i].active && !subquery_should_be_active(ctx, query, i)) 537bf215546Sopenharmony_ci end_subquery(ctx, query, i); 538bf215546Sopenharmony_ci else if (!query->subqueries[i].active && subquery_should_be_active(ctx, query, i)) 539bf215546Sopenharmony_ci begin_subquery(ctx, query, i); 540bf215546Sopenharmony_ci } 541bf215546Sopenharmony_ci } 542bf215546Sopenharmony_ci} 543bf215546Sopenharmony_ci 544bf215546Sopenharmony_cistatic void 545bf215546Sopenharmony_cid3d12_set_active_query_state(struct pipe_context *pctx, bool enable) 546bf215546Sopenharmony_ci{ 547bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 548bf215546Sopenharmony_ci ctx->queries_disabled = !enable; 549bf215546Sopenharmony_ci 550bf215546Sopenharmony_ci if (enable) 551bf215546Sopenharmony_ci d3d12_resume_queries(ctx); 552bf215546Sopenharmony_ci else 553bf215546Sopenharmony_ci d3d12_suspend_queries(ctx); 554bf215546Sopenharmony_ci} 555bf215546Sopenharmony_ci 556bf215546Sopenharmony_cistatic void 557bf215546Sopenharmony_cid3d12_render_condition(struct pipe_context *pctx, 558bf215546Sopenharmony_ci struct pipe_query *pquery, 559bf215546Sopenharmony_ci bool condition, 560bf215546Sopenharmony_ci enum pipe_render_cond_flag mode) 561bf215546Sopenharmony_ci{ 562bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 563bf215546Sopenharmony_ci struct d3d12_query *query = (struct d3d12_query *)pquery; 564bf215546Sopenharmony_ci 565bf215546Sopenharmony_ci if (query == nullptr) { 566bf215546Sopenharmony_ci ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO); 567bf215546Sopenharmony_ci ctx->current_predication = nullptr; 568bf215546Sopenharmony_ci return; 569bf215546Sopenharmony_ci } 570bf215546Sopenharmony_ci 571bf215546Sopenharmony_ci assert(num_sub_queries(query->type) == 1); 572bf215546Sopenharmony_ci if (!query->predicate) 573bf215546Sopenharmony_ci query->predicate = d3d12_resource(pipe_buffer_create(pctx->screen, 0, 574bf215546Sopenharmony_ci PIPE_USAGE_DEFAULT, sizeof(uint64_t))); 575bf215546Sopenharmony_ci 576bf215546Sopenharmony_ci if (mode == PIPE_RENDER_COND_WAIT) { 577bf215546Sopenharmony_ci d3d12_flush_cmdlist_and_wait(ctx); 578bf215546Sopenharmony_ci union pipe_query_result result; 579bf215546Sopenharmony_ci accumulate_result(ctx, (d3d12_query *)pquery, &result, true, true); 580bf215546Sopenharmony_ci } 581bf215546Sopenharmony_ci 582bf215546Sopenharmony_ci struct d3d12_resource *res = (struct d3d12_resource *)query->subqueries[0].buffer; 583bf215546Sopenharmony_ci uint64_t source_offset = 0; 584bf215546Sopenharmony_ci ID3D12Resource *source = d3d12_resource_underlying(res, &source_offset); 585bf215546Sopenharmony_ci source_offset += query->subqueries[0].buffer_offset; 586bf215546Sopenharmony_ci d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS); 587bf215546Sopenharmony_ci d3d12_transition_resource_state(ctx, query->predicate, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_TRANSITION_FLAG_NONE); 588bf215546Sopenharmony_ci d3d12_apply_resource_states(ctx, false); 589bf215546Sopenharmony_ci ctx->cmdlist->CopyBufferRegion(d3d12_resource_resource(query->predicate), 0, 590bf215546Sopenharmony_ci source, source_offset, 591bf215546Sopenharmony_ci sizeof(uint64_t)); 592bf215546Sopenharmony_ci 593bf215546Sopenharmony_ci d3d12_transition_resource_state(ctx, query->predicate, D3D12_RESOURCE_STATE_PREDICATION, D3D12_TRANSITION_FLAG_NONE); 594bf215546Sopenharmony_ci d3d12_apply_resource_states(ctx, false); 595bf215546Sopenharmony_ci 596bf215546Sopenharmony_ci ctx->current_predication = query->predicate; 597bf215546Sopenharmony_ci ctx->predication_condition = condition; 598bf215546Sopenharmony_ci d3d12_enable_predication(ctx); 599bf215546Sopenharmony_ci} 600bf215546Sopenharmony_ci 601bf215546Sopenharmony_civoid 602bf215546Sopenharmony_cid3d12_enable_predication(struct d3d12_context *ctx) 603bf215546Sopenharmony_ci{ 604bf215546Sopenharmony_ci /* documentation of ID3D12GraphicsCommandList::SetPredication method: 605bf215546Sopenharmony_ci * "resource manipulation commands are _not_ actually performed 606bf215546Sopenharmony_ci * if the resulting predicate data of the predicate is equal to 607bf215546Sopenharmony_ci * the operation specified." 608bf215546Sopenharmony_ci */ 609bf215546Sopenharmony_ci ctx->cmdlist->SetPredication(d3d12_resource_resource(ctx->current_predication), 0, 610bf215546Sopenharmony_ci ctx->predication_condition ? D3D12_PREDICATION_OP_NOT_EQUAL_ZERO : 611bf215546Sopenharmony_ci D3D12_PREDICATION_OP_EQUAL_ZERO); 612bf215546Sopenharmony_ci} 613bf215546Sopenharmony_ci 614bf215546Sopenharmony_civoid 615bf215546Sopenharmony_cid3d12_context_query_init(struct pipe_context *pctx) 616bf215546Sopenharmony_ci{ 617bf215546Sopenharmony_ci struct d3d12_context *ctx = d3d12_context(pctx); 618bf215546Sopenharmony_ci list_inithead(&ctx->active_queries); 619bf215546Sopenharmony_ci 620bf215546Sopenharmony_ci u_suballocator_init(&ctx->query_allocator, &ctx->base, 4096, 0, PIPE_USAGE_STAGING, 621bf215546Sopenharmony_ci 0, true); 622bf215546Sopenharmony_ci 623bf215546Sopenharmony_ci pctx->create_query = d3d12_create_query; 624bf215546Sopenharmony_ci pctx->destroy_query = d3d12_destroy_query; 625bf215546Sopenharmony_ci pctx->begin_query = d3d12_begin_query; 626bf215546Sopenharmony_ci pctx->end_query = d3d12_end_query; 627bf215546Sopenharmony_ci pctx->get_query_result = d3d12_get_query_result; 628bf215546Sopenharmony_ci pctx->set_active_query_state = d3d12_set_active_query_state; 629bf215546Sopenharmony_ci pctx->render_condition = d3d12_render_condition; 630bf215546Sopenharmony_ci} 631