17ec681f3Smrg/* 27ec681f3Smrg * Copyright © Microsoft Corporation 37ec681f3Smrg * 47ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg * copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg * to deal in the Software without restriction, including without limitation 77ec681f3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg * and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg * Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg * 117ec681f3Smrg * The above copyright notice and this permission notice (including the next 127ec681f3Smrg * paragraph) shall be included in all copies or substantial portions of the 137ec681f3Smrg * Software. 147ec681f3Smrg * 157ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167ec681f3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177ec681f3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187ec681f3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197ec681f3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 207ec681f3Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 217ec681f3Smrg * IN THE SOFTWARE. 227ec681f3Smrg */ 237ec681f3Smrg 247ec681f3Smrg#include "d3d12_query.h" 257ec681f3Smrg#include "d3d12_context.h" 267ec681f3Smrg#include "d3d12_resource.h" 277ec681f3Smrg#include "d3d12_screen.h" 287ec681f3Smrg 297ec681f3Smrg#include "util/u_dump.h" 307ec681f3Smrg#include "util/u_inlines.h" 317ec681f3Smrg#include "util/u_memory.h" 327ec681f3Smrg 337ec681f3Smrg#include <dxguids/dxguids.h> 347ec681f3Smrg 357ec681f3Smrgstruct d3d12_query { 367ec681f3Smrg enum pipe_query_type type; 377ec681f3Smrg 387ec681f3Smrg ID3D12QueryHeap *query_heap; 397ec681f3Smrg unsigned curr_query, num_queries; 407ec681f3Smrg size_t query_size; 417ec681f3Smrg struct d3d12_query *subquery; 427ec681f3Smrg 437ec681f3Smrg D3D12_QUERY_TYPE d3d12qtype; 447ec681f3Smrg 457ec681f3Smrg pipe_resource *buffer; 467ec681f3Smrg unsigned buffer_offset; 477ec681f3Smrg uint64_t fence_value; 487ec681f3Smrg 497ec681f3Smrg struct list_head active_list; 507ec681f3Smrg struct d3d12_resource *predicate; 517ec681f3Smrg}; 527ec681f3Smrg 537ec681f3Smrgstatic D3D12_QUERY_HEAP_TYPE 547ec681f3Smrgd3d12_query_heap_type(unsigned query_type) 557ec681f3Smrg{ 567ec681f3Smrg switch (query_type) { 577ec681f3Smrg case PIPE_QUERY_OCCLUSION_COUNTER: 587ec681f3Smrg case PIPE_QUERY_OCCLUSION_PREDICATE: 597ec681f3Smrg case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 607ec681f3Smrg return D3D12_QUERY_HEAP_TYPE_OCCLUSION; 617ec681f3Smrg case PIPE_QUERY_PIPELINE_STATISTICS: 627ec681f3Smrg return D3D12_QUERY_HEAP_TYPE_PIPELINE_STATISTICS; 637ec681f3Smrg case PIPE_QUERY_PRIMITIVES_GENERATED: 647ec681f3Smrg case PIPE_QUERY_PRIMITIVES_EMITTED: 657ec681f3Smrg case PIPE_QUERY_SO_STATISTICS: 667ec681f3Smrg return D3D12_QUERY_HEAP_TYPE_SO_STATISTICS; 677ec681f3Smrg case PIPE_QUERY_TIMESTAMP: 687ec681f3Smrg case PIPE_QUERY_TIME_ELAPSED: 697ec681f3Smrg return D3D12_QUERY_HEAP_TYPE_TIMESTAMP; 707ec681f3Smrg 717ec681f3Smrg default: 727ec681f3Smrg debug_printf("unknown query: %s\n", 737ec681f3Smrg util_str_query_type(query_type, true)); 747ec681f3Smrg unreachable("d3d12: unknown query type"); 757ec681f3Smrg } 767ec681f3Smrg} 777ec681f3Smrg 787ec681f3Smrgstatic D3D12_QUERY_TYPE 797ec681f3Smrgd3d12_query_type(unsigned query_type) 807ec681f3Smrg{ 817ec681f3Smrg switch (query_type) { 827ec681f3Smrg case PIPE_QUERY_OCCLUSION_COUNTER: 837ec681f3Smrg return D3D12_QUERY_TYPE_OCCLUSION; 847ec681f3Smrg case PIPE_QUERY_OCCLUSION_PREDICATE: 857ec681f3Smrg case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 867ec681f3Smrg return D3D12_QUERY_TYPE_BINARY_OCCLUSION; 877ec681f3Smrg case PIPE_QUERY_PIPELINE_STATISTICS: 887ec681f3Smrg return D3D12_QUERY_TYPE_PIPELINE_STATISTICS; 897ec681f3Smrg case PIPE_QUERY_PRIMITIVES_GENERATED: 907ec681f3Smrg case PIPE_QUERY_PRIMITIVES_EMITTED: 917ec681f3Smrg case PIPE_QUERY_SO_STATISTICS: 927ec681f3Smrg return D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0; 937ec681f3Smrg case PIPE_QUERY_TIMESTAMP: 947ec681f3Smrg case PIPE_QUERY_TIME_ELAPSED: 957ec681f3Smrg return D3D12_QUERY_TYPE_TIMESTAMP; 967ec681f3Smrg default: 977ec681f3Smrg debug_printf("unknown query: %s\n", 987ec681f3Smrg util_str_query_type(query_type, true)); 997ec681f3Smrg unreachable("d3d12: unknown query type"); 1007ec681f3Smrg } 1017ec681f3Smrg} 1027ec681f3Smrg 1037ec681f3Smrgstatic struct pipe_query * 1047ec681f3Smrgd3d12_create_query(struct pipe_context *pctx, 1057ec681f3Smrg unsigned query_type, unsigned index) 1067ec681f3Smrg{ 1077ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 1087ec681f3Smrg struct d3d12_screen *screen = d3d12_screen(pctx->screen); 1097ec681f3Smrg struct d3d12_query *query = CALLOC_STRUCT(d3d12_query); 1107ec681f3Smrg D3D12_QUERY_HEAP_DESC desc = {}; 1117ec681f3Smrg 1127ec681f3Smrg if (!query) 1137ec681f3Smrg return NULL; 1147ec681f3Smrg 1157ec681f3Smrg query->type = (pipe_query_type)query_type; 1167ec681f3Smrg query->d3d12qtype = d3d12_query_type(query_type); 1177ec681f3Smrg query->num_queries = 16; 1187ec681f3Smrg 1197ec681f3Smrg /* With timer queries we want a few more queries, especially since we need two slots 1207ec681f3Smrg * per query for TIME_ELAPSED queries */ 1217ec681f3Smrg if (unlikely(query->d3d12qtype == D3D12_QUERY_TYPE_TIMESTAMP)) 1227ec681f3Smrg query->num_queries = 64; 1237ec681f3Smrg 1247ec681f3Smrg query->curr_query = 0; 1257ec681f3Smrg 1267ec681f3Smrg switch (query->d3d12qtype) { 1277ec681f3Smrg case D3D12_QUERY_TYPE_PIPELINE_STATISTICS: 1287ec681f3Smrg query->query_size = sizeof(D3D12_QUERY_DATA_PIPELINE_STATISTICS); 1297ec681f3Smrg break; 1307ec681f3Smrg case D3D12_QUERY_TYPE_SO_STATISTICS_STREAM0: 1317ec681f3Smrg query->query_size = sizeof(D3D12_QUERY_DATA_SO_STATISTICS); 1327ec681f3Smrg break; 1337ec681f3Smrg default: 1347ec681f3Smrg query->query_size = sizeof(uint64_t); 1357ec681f3Smrg break; 1367ec681f3Smrg } 1377ec681f3Smrg 1387ec681f3Smrg desc.Count = query->num_queries; 1397ec681f3Smrg desc.Type = d3d12_query_heap_type(query_type); 1407ec681f3Smrg if (FAILED(screen->dev->CreateQueryHeap(&desc, 1417ec681f3Smrg IID_PPV_ARGS(&query->query_heap)))) { 1427ec681f3Smrg FREE(query); 1437ec681f3Smrg return NULL; 1447ec681f3Smrg } 1457ec681f3Smrg 1467ec681f3Smrg /* Query result goes into a readback buffer */ 1477ec681f3Smrg size_t buffer_size = query->query_size * query->num_queries; 1487ec681f3Smrg u_suballocator_alloc(&ctx->query_allocator, buffer_size, 256, 1497ec681f3Smrg &query->buffer_offset, &query->buffer); 1507ec681f3Smrg 1517ec681f3Smrg return (struct pipe_query *)query; 1527ec681f3Smrg} 1537ec681f3Smrg 1547ec681f3Smrgstatic void 1557ec681f3Smrgd3d12_destroy_query(struct pipe_context *pctx, 1567ec681f3Smrg struct pipe_query *q) 1577ec681f3Smrg{ 1587ec681f3Smrg struct d3d12_query *query = (struct d3d12_query *)q; 1597ec681f3Smrg pipe_resource *predicate = &query->predicate->base; 1607ec681f3Smrg if (query->subquery) 1617ec681f3Smrg d3d12_destroy_query(pctx, (struct pipe_query *)query->subquery); 1627ec681f3Smrg pipe_resource_reference(&predicate, NULL); 1637ec681f3Smrg query->query_heap->Release(); 1647ec681f3Smrg FREE(query); 1657ec681f3Smrg} 1667ec681f3Smrg 1677ec681f3Smrgstatic bool 1687ec681f3Smrgaccumulate_result(struct d3d12_context *ctx, struct d3d12_query *q, 1697ec681f3Smrg union pipe_query_result *result, bool write) 1707ec681f3Smrg{ 1717ec681f3Smrg struct pipe_transfer *transfer = NULL; 1727ec681f3Smrg struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 1737ec681f3Smrg unsigned access = PIPE_MAP_READ; 1747ec681f3Smrg void *results; 1757ec681f3Smrg 1767ec681f3Smrg if (write) 1777ec681f3Smrg access |= PIPE_MAP_WRITE; 1787ec681f3Smrg results = pipe_buffer_map_range(&ctx->base, q->buffer, q->buffer_offset, 1797ec681f3Smrg q->num_queries * q->query_size, 1807ec681f3Smrg access, &transfer); 1817ec681f3Smrg 1827ec681f3Smrg if (results == NULL) 1837ec681f3Smrg return false; 1847ec681f3Smrg 1857ec681f3Smrg uint64_t *results_u64 = (uint64_t *)results; 1867ec681f3Smrg D3D12_QUERY_DATA_PIPELINE_STATISTICS *results_stats = (D3D12_QUERY_DATA_PIPELINE_STATISTICS *)results; 1877ec681f3Smrg D3D12_QUERY_DATA_SO_STATISTICS *results_so = (D3D12_QUERY_DATA_SO_STATISTICS *)results; 1887ec681f3Smrg 1897ec681f3Smrg util_query_clear_result(result, q->type); 1907ec681f3Smrg for (unsigned i = 0; i < q->curr_query; ++i) { 1917ec681f3Smrg switch (q->type) { 1927ec681f3Smrg case PIPE_QUERY_OCCLUSION_PREDICATE: 1937ec681f3Smrg case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: 1947ec681f3Smrg result->b |= results_u64[i] != 0; 1957ec681f3Smrg break; 1967ec681f3Smrg 1977ec681f3Smrg case PIPE_QUERY_OCCLUSION_COUNTER: 1987ec681f3Smrg result->u64 += results_u64[i]; 1997ec681f3Smrg break; 2007ec681f3Smrg case PIPE_QUERY_TIMESTAMP: 2017ec681f3Smrg result->u64 = results_u64[i]; 2027ec681f3Smrg break; 2037ec681f3Smrg 2047ec681f3Smrg case PIPE_QUERY_PIPELINE_STATISTICS: 2057ec681f3Smrg result->pipeline_statistics.ia_vertices += results_stats[i].IAVertices; 2067ec681f3Smrg result->pipeline_statistics.ia_primitives += results_stats[i].IAPrimitives; 2077ec681f3Smrg result->pipeline_statistics.vs_invocations += results_stats[i].VSInvocations; 2087ec681f3Smrg result->pipeline_statistics.gs_invocations += results_stats[i].GSInvocations; 2097ec681f3Smrg result->pipeline_statistics.gs_primitives += results_stats[i].GSPrimitives; 2107ec681f3Smrg result->pipeline_statistics.c_invocations += results_stats[i].CInvocations; 2117ec681f3Smrg result->pipeline_statistics.c_primitives += results_stats[i].CPrimitives; 2127ec681f3Smrg result->pipeline_statistics.ps_invocations += results_stats[i].PSInvocations; 2137ec681f3Smrg result->pipeline_statistics.hs_invocations += results_stats[i].HSInvocations; 2147ec681f3Smrg result->pipeline_statistics.ds_invocations += results_stats[i].DSInvocations; 2157ec681f3Smrg result->pipeline_statistics.cs_invocations += results_stats[i].CSInvocations; 2167ec681f3Smrg break; 2177ec681f3Smrg 2187ec681f3Smrg case PIPE_QUERY_PRIMITIVES_GENERATED: 2197ec681f3Smrg result->u64 += results_so[i].PrimitivesStorageNeeded; 2207ec681f3Smrg break; 2217ec681f3Smrg 2227ec681f3Smrg case PIPE_QUERY_PRIMITIVES_EMITTED: 2237ec681f3Smrg result->u64 += results_so[i].NumPrimitivesWritten; 2247ec681f3Smrg break; 2257ec681f3Smrg 2267ec681f3Smrg case PIPE_QUERY_TIME_ELAPSED: 2277ec681f3Smrg result->u64 += results_u64[2 * i + 1] - results_u64[2 * i]; 2287ec681f3Smrg break; 2297ec681f3Smrg 2307ec681f3Smrg case PIPE_QUERY_SO_STATISTICS: 2317ec681f3Smrg result->so_statistics.num_primitives_written += results_so[i].NumPrimitivesWritten; 2327ec681f3Smrg result->so_statistics.primitives_storage_needed += results_so[i].PrimitivesStorageNeeded; 2337ec681f3Smrg break; 2347ec681f3Smrg 2357ec681f3Smrg default: 2367ec681f3Smrg debug_printf("unsupported query type: %s\n", 2377ec681f3Smrg util_str_query_type(q->type, true)); 2387ec681f3Smrg unreachable("unexpected query type"); 2397ec681f3Smrg } 2407ec681f3Smrg } 2417ec681f3Smrg 2427ec681f3Smrg if (q->subquery) { 2437ec681f3Smrg union pipe_query_result subresult; 2447ec681f3Smrg 2457ec681f3Smrg accumulate_result(ctx, q->subquery, &subresult, false); 2467ec681f3Smrg q->subquery->curr_query = 0; 2477ec681f3Smrg if (q->type == PIPE_QUERY_PRIMITIVES_GENERATED) 2487ec681f3Smrg result->u64 += subresult.pipeline_statistics.ia_primitives; 2497ec681f3Smrg } 2507ec681f3Smrg 2517ec681f3Smrg if (write) { 2527ec681f3Smrg if (q->type == PIPE_QUERY_PIPELINE_STATISTICS) { 2537ec681f3Smrg results_stats[0].IAVertices = result->pipeline_statistics.ia_vertices; 2547ec681f3Smrg results_stats[0].IAPrimitives = result->pipeline_statistics.ia_primitives; 2557ec681f3Smrg results_stats[0].VSInvocations = result->pipeline_statistics.vs_invocations; 2567ec681f3Smrg results_stats[0].GSInvocations = result->pipeline_statistics.gs_invocations; 2577ec681f3Smrg results_stats[0].GSPrimitives = result->pipeline_statistics.gs_primitives; 2587ec681f3Smrg results_stats[0].CInvocations = result->pipeline_statistics.c_invocations; 2597ec681f3Smrg results_stats[0].CPrimitives = result->pipeline_statistics.c_primitives; 2607ec681f3Smrg results_stats[0].PSInvocations = result->pipeline_statistics.ps_invocations; 2617ec681f3Smrg results_stats[0].HSInvocations = result->pipeline_statistics.hs_invocations; 2627ec681f3Smrg results_stats[0].DSInvocations = result->pipeline_statistics.ds_invocations; 2637ec681f3Smrg results_stats[0].CSInvocations = result->pipeline_statistics.cs_invocations; 2647ec681f3Smrg } else if (q->type == PIPE_QUERY_SO_STATISTICS) { 2657ec681f3Smrg results_so[0].NumPrimitivesWritten = result->so_statistics.num_primitives_written; 2667ec681f3Smrg results_so[0].PrimitivesStorageNeeded = result->so_statistics.primitives_storage_needed; 2677ec681f3Smrg } else { 2687ec681f3Smrg if (unlikely(q->d3d12qtype == D3D12_QUERY_TYPE_TIMESTAMP)) { 2697ec681f3Smrg results_u64[0] = 0; 2707ec681f3Smrg results_u64[1] = result->u64; 2717ec681f3Smrg } else { 2727ec681f3Smrg results_u64[0] = result->u64; 2737ec681f3Smrg } 2747ec681f3Smrg } 2757ec681f3Smrg } 2767ec681f3Smrg 2777ec681f3Smrg pipe_buffer_unmap(&ctx->base, transfer); 2787ec681f3Smrg 2797ec681f3Smrg if (q->type == PIPE_QUERY_TIME_ELAPSED || 2807ec681f3Smrg q->type == PIPE_QUERY_TIMESTAMP) 2817ec681f3Smrg result->u64 = static_cast<uint64_t>(screen->timestamp_multiplier * result->u64); 2827ec681f3Smrg 2837ec681f3Smrg return true; 2847ec681f3Smrg} 2857ec681f3Smrg 2867ec681f3Smrgstatic void 2877ec681f3Smrgbegin_query(struct d3d12_context *ctx, struct d3d12_query *q, bool restart) 2887ec681f3Smrg{ 2897ec681f3Smrg if (restart) { 2907ec681f3Smrg q->curr_query = 0; 2917ec681f3Smrg } else if (q->curr_query == q->num_queries) { 2927ec681f3Smrg union pipe_query_result result; 2937ec681f3Smrg 2947ec681f3Smrg /* Accumulate current results and store in first slot */ 2957ec681f3Smrg d3d12_flush_cmdlist_and_wait(ctx); 2967ec681f3Smrg accumulate_result(ctx, q, &result, true); 2977ec681f3Smrg q->curr_query = 1; 2987ec681f3Smrg } 2997ec681f3Smrg 3007ec681f3Smrg if (q->subquery) 3017ec681f3Smrg begin_query(ctx, q->subquery, restart); 3027ec681f3Smrg 3037ec681f3Smrg ctx->cmdlist->BeginQuery(q->query_heap, q->d3d12qtype, q->curr_query); 3047ec681f3Smrg} 3057ec681f3Smrg 3067ec681f3Smrg 3077ec681f3Smrgstatic void 3087ec681f3Smrgbegin_timer_query(struct d3d12_context *ctx, struct d3d12_query *q, bool restart) 3097ec681f3Smrg{ 3107ec681f3Smrg /* For PIPE_QUERY_TIME_ELAPSED we record one time with BeginQuery and one in 3117ec681f3Smrg * EndQuery, so we need two query slots */ 3127ec681f3Smrg unsigned query_index = 2 * q->curr_query; 3137ec681f3Smrg 3147ec681f3Smrg if (restart) { 3157ec681f3Smrg q->curr_query = 0; 3167ec681f3Smrg query_index = 0; 3177ec681f3Smrg } else if (query_index == q->num_queries) { 3187ec681f3Smrg union pipe_query_result result; 3197ec681f3Smrg 3207ec681f3Smrg /* Accumulate current results and store in first slot */ 3217ec681f3Smrg d3d12_flush_cmdlist_and_wait(ctx); 3227ec681f3Smrg accumulate_result(ctx, q, &result, true); 3237ec681f3Smrg q->curr_query = 2; 3247ec681f3Smrg } 3257ec681f3Smrg 3267ec681f3Smrg ctx->cmdlist->EndQuery(q->query_heap, q->d3d12qtype, query_index); 3277ec681f3Smrg} 3287ec681f3Smrg 3297ec681f3Smrgstatic bool 3307ec681f3Smrgd3d12_begin_query(struct pipe_context *pctx, 3317ec681f3Smrg struct pipe_query *q) 3327ec681f3Smrg{ 3337ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 3347ec681f3Smrg struct d3d12_query *query = (struct d3d12_query *)q; 3357ec681f3Smrg 3367ec681f3Smrg assert(query->type != PIPE_QUERY_TIMESTAMP); 3377ec681f3Smrg 3387ec681f3Smrg if (unlikely(query->type == PIPE_QUERY_TIME_ELAPSED)) 3397ec681f3Smrg begin_timer_query(ctx, query, true); 3407ec681f3Smrg else { 3417ec681f3Smrg begin_query(ctx, query, true); 3427ec681f3Smrg list_addtail(&query->active_list, &ctx->active_queries); 3437ec681f3Smrg } 3447ec681f3Smrg 3457ec681f3Smrg return true; 3467ec681f3Smrg} 3477ec681f3Smrg 3487ec681f3Smrgstatic void 3497ec681f3Smrgend_query(struct d3d12_context *ctx, struct d3d12_query *q) 3507ec681f3Smrg{ 3517ec681f3Smrg uint64_t offset = 0; 3527ec681f3Smrg struct d3d12_batch *batch = d3d12_current_batch(ctx); 3537ec681f3Smrg struct d3d12_resource *res = (struct d3d12_resource *)q->buffer; 3547ec681f3Smrg ID3D12Resource *d3d12_res = d3d12_resource_underlying(res, &offset); 3557ec681f3Smrg 3567ec681f3Smrg /* End subquery first so that we can use fence value from parent */ 3577ec681f3Smrg if (q->subquery) 3587ec681f3Smrg end_query(ctx, q->subquery); 3597ec681f3Smrg 3607ec681f3Smrg /* With QUERY_TIME_ELAPSED we have recorded one value at 3617ec681f3Smrg * (2 * q->curr_query), and now we record a value at (2 * q->curr_query + 1) 3627ec681f3Smrg * and when resolving the query we subtract the latter from the former */ 3637ec681f3Smrg 3647ec681f3Smrg unsigned resolve_count = q->type == PIPE_QUERY_TIME_ELAPSED ? 2 : 1; 3657ec681f3Smrg unsigned resolve_index = resolve_count * q->curr_query; 3667ec681f3Smrg unsigned end_index = resolve_index + resolve_count - 1; 3677ec681f3Smrg 3687ec681f3Smrg offset += q->buffer_offset + resolve_index * q->query_size; 3697ec681f3Smrg ctx->cmdlist->EndQuery(q->query_heap, q->d3d12qtype, end_index); 3707ec681f3Smrg d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_BIND_INVALIDATE_FULL); 3717ec681f3Smrg d3d12_apply_resource_states(ctx); 3727ec681f3Smrg ctx->cmdlist->ResolveQueryData(q->query_heap, q->d3d12qtype, resolve_index, 3737ec681f3Smrg resolve_count, d3d12_res, offset); 3747ec681f3Smrg 3757ec681f3Smrg d3d12_batch_reference_object(batch, q->query_heap); 3767ec681f3Smrg d3d12_batch_reference_resource(batch, res); 3777ec681f3Smrg 3787ec681f3Smrg assert(q->curr_query < q->num_queries); 3797ec681f3Smrg q->curr_query++; 3807ec681f3Smrg} 3817ec681f3Smrg 3827ec681f3Smrgstatic bool 3837ec681f3Smrgd3d12_end_query(struct pipe_context *pctx, 3847ec681f3Smrg struct pipe_query *q) 3857ec681f3Smrg{ 3867ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 3877ec681f3Smrg struct d3d12_query *query = (struct d3d12_query *)q; 3887ec681f3Smrg 3897ec681f3Smrg end_query(ctx, query); 3907ec681f3Smrg 3917ec681f3Smrg if (query->type != PIPE_QUERY_TIMESTAMP && 3927ec681f3Smrg query->type != PIPE_QUERY_TIME_ELAPSED) 3937ec681f3Smrg list_delinit(&query->active_list); 3947ec681f3Smrg 3957ec681f3Smrg query->fence_value = ctx->fence_value; 3967ec681f3Smrg return true; 3977ec681f3Smrg} 3987ec681f3Smrg 3997ec681f3Smrgstatic bool 4007ec681f3Smrgd3d12_get_query_result(struct pipe_context *pctx, 4017ec681f3Smrg struct pipe_query *q, 4027ec681f3Smrg bool wait, 4037ec681f3Smrg union pipe_query_result *result) 4047ec681f3Smrg{ 4057ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 4067ec681f3Smrg struct d3d12_query *query = (struct d3d12_query *)q; 4077ec681f3Smrg 4087ec681f3Smrg if (ctx->cmdqueue_fence->GetCompletedValue() < query->fence_value) { 4097ec681f3Smrg if (!wait) 4107ec681f3Smrg return false; 4117ec681f3Smrg d3d12_flush_cmdlist_and_wait(ctx); 4127ec681f3Smrg } 4137ec681f3Smrg 4147ec681f3Smrg return accumulate_result(ctx, query, result, false); 4157ec681f3Smrg} 4167ec681f3Smrg 4177ec681f3Smrgvoid 4187ec681f3Smrgd3d12_suspend_queries(struct d3d12_context *ctx) 4197ec681f3Smrg{ 4207ec681f3Smrg list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) { 4217ec681f3Smrg end_query(ctx, query); 4227ec681f3Smrg } 4237ec681f3Smrg} 4247ec681f3Smrg 4257ec681f3Smrgvoid 4267ec681f3Smrgd3d12_resume_queries(struct d3d12_context *ctx) 4277ec681f3Smrg{ 4287ec681f3Smrg list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) { 4297ec681f3Smrg begin_query(ctx, query, false); 4307ec681f3Smrg } 4317ec681f3Smrg} 4327ec681f3Smrg 4337ec681f3Smrgvoid 4347ec681f3Smrgd3d12_validate_queries(struct d3d12_context *ctx) 4357ec681f3Smrg{ 4367ec681f3Smrg bool have_xfb = !!ctx->gfx_pipeline_state.num_so_targets; 4377ec681f3Smrg 4387ec681f3Smrg list_for_each_entry(struct d3d12_query, query, &ctx->active_queries, active_list) { 4397ec681f3Smrg if (query->type == PIPE_QUERY_PRIMITIVES_GENERATED && !have_xfb && !query->subquery) { 4407ec681f3Smrg struct pipe_query *subquery = d3d12_create_query(&ctx->base, PIPE_QUERY_PIPELINE_STATISTICS, 0); 4417ec681f3Smrg query->subquery = (struct d3d12_query *)subquery; 4427ec681f3Smrg if (!ctx->queries_disabled) 4437ec681f3Smrg begin_query(ctx, query->subquery, true); 4447ec681f3Smrg } 4457ec681f3Smrg } 4467ec681f3Smrg} 4477ec681f3Smrg 4487ec681f3Smrgstatic void 4497ec681f3Smrgd3d12_set_active_query_state(struct pipe_context *pctx, bool enable) 4507ec681f3Smrg{ 4517ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 4527ec681f3Smrg ctx->queries_disabled = !enable; 4537ec681f3Smrg 4547ec681f3Smrg if (enable) 4557ec681f3Smrg d3d12_resume_queries(ctx); 4567ec681f3Smrg else 4577ec681f3Smrg d3d12_suspend_queries(ctx); 4587ec681f3Smrg} 4597ec681f3Smrg 4607ec681f3Smrgstatic void 4617ec681f3Smrgd3d12_render_condition(struct pipe_context *pctx, 4627ec681f3Smrg struct pipe_query *pquery, 4637ec681f3Smrg bool condition, 4647ec681f3Smrg enum pipe_render_cond_flag mode) 4657ec681f3Smrg{ 4667ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 4677ec681f3Smrg struct d3d12_query *query = (struct d3d12_query *)pquery; 4687ec681f3Smrg 4697ec681f3Smrg if (query == nullptr) { 4707ec681f3Smrg ctx->cmdlist->SetPredication(nullptr, 0, D3D12_PREDICATION_OP_EQUAL_ZERO); 4717ec681f3Smrg ctx->current_predication = nullptr; 4727ec681f3Smrg return; 4737ec681f3Smrg } 4747ec681f3Smrg 4757ec681f3Smrg if (!query->predicate) 4767ec681f3Smrg query->predicate = d3d12_resource(pipe_buffer_create(pctx->screen, 0, 4777ec681f3Smrg PIPE_USAGE_DEFAULT, sizeof(uint64_t))); 4787ec681f3Smrg 4797ec681f3Smrg if (mode == PIPE_RENDER_COND_WAIT) { 4807ec681f3Smrg d3d12_flush_cmdlist_and_wait(ctx); 4817ec681f3Smrg union pipe_query_result result; 4827ec681f3Smrg accumulate_result(ctx, (d3d12_query *)pquery, &result, true); 4837ec681f3Smrg } 4847ec681f3Smrg 4857ec681f3Smrg struct d3d12_resource *res = (struct d3d12_resource *)query->buffer; 4867ec681f3Smrg d3d12_transition_resource_state(ctx, res, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_BIND_INVALIDATE_FULL); 4877ec681f3Smrg d3d12_transition_resource_state(ctx, query->predicate, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_BIND_INVALIDATE_NONE); 4887ec681f3Smrg d3d12_apply_resource_states(ctx); 4897ec681f3Smrg ctx->cmdlist->CopyBufferRegion(d3d12_resource_resource(query->predicate), 0, 4907ec681f3Smrg d3d12_resource_resource(res), 0, 4917ec681f3Smrg sizeof(uint64_t)); 4927ec681f3Smrg 4937ec681f3Smrg d3d12_transition_resource_state(ctx, query->predicate, D3D12_RESOURCE_STATE_PREDICATION, D3D12_BIND_INVALIDATE_NONE); 4947ec681f3Smrg d3d12_apply_resource_states(ctx); 4957ec681f3Smrg 4967ec681f3Smrg ctx->current_predication = query->predicate; 4977ec681f3Smrg /* documentation of ID3D12GraphicsCommandList::SetPredication method: 4987ec681f3Smrg * "resource manipulation commands are _not_ actually performed 4997ec681f3Smrg * if the resulting predicate data of the predicate is equal to 5007ec681f3Smrg * the operation specified." 5017ec681f3Smrg */ 5027ec681f3Smrg ctx->cmdlist->SetPredication(d3d12_resource_resource(query->predicate), 0, 5037ec681f3Smrg condition ? D3D12_PREDICATION_OP_NOT_EQUAL_ZERO : 5047ec681f3Smrg D3D12_PREDICATION_OP_EQUAL_ZERO); 5057ec681f3Smrg} 5067ec681f3Smrg 5077ec681f3Smrgvoid 5087ec681f3Smrgd3d12_context_query_init(struct pipe_context *pctx) 5097ec681f3Smrg{ 5107ec681f3Smrg struct d3d12_context *ctx = d3d12_context(pctx); 5117ec681f3Smrg list_inithead(&ctx->active_queries); 5127ec681f3Smrg 5137ec681f3Smrg u_suballocator_init(&ctx->query_allocator, &ctx->base, 4096, 0, PIPE_USAGE_STAGING, 5147ec681f3Smrg 0, true); 5157ec681f3Smrg 5167ec681f3Smrg pctx->create_query = d3d12_create_query; 5177ec681f3Smrg pctx->destroy_query = d3d12_destroy_query; 5187ec681f3Smrg pctx->begin_query = d3d12_begin_query; 5197ec681f3Smrg pctx->end_query = d3d12_end_query; 5207ec681f3Smrg pctx->get_query_result = d3d12_get_query_result; 5217ec681f3Smrg pctx->set_active_query_state = d3d12_set_active_query_state; 5227ec681f3Smrg pctx->render_condition = d3d12_render_condition; 5237ec681f3Smrg} 524