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