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