swr_query.cpp revision 5815c8b3d3b7fe3311ac51533438f24f09768ad6
1/****************************************************************************
2 * Copyright (C) 2015 Intel Corporation.   All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 ***************************************************************************/
23
24#include "pipe/p_defines.h"
25#include "util/u_memory.h"
26#include "os/os_time.h"
27#include "swr_context.h"
28#include "swr_fence.h"
29#include "swr_query.h"
30#include "swr_screen.h"
31#include "swr_state.h"
32
33
34static struct swr_query *
35swr_query(struct pipe_query *p)
36{
37   return (struct swr_query *)p;
38}
39
40static struct pipe_query *
41swr_create_query(struct pipe_context *pipe, unsigned type, unsigned index)
42{
43   struct swr_query *pq;
44
45   assert(type < PIPE_QUERY_TYPES);
46   assert(index < MAX_SO_STREAMS);
47
48   pq = CALLOC_STRUCT(swr_query);
49
50   if (pq) {
51      pq->type = type;
52      pq->index = index;
53   }
54
55   return (struct pipe_query *)pq;
56}
57
58
59static void
60swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
61{
62   struct swr_query *pq = swr_query(q);
63
64   if (pq->fence) {
65      if (!swr_is_fence_pending(pq->fence)) {
66         swr_fence_submit(swr_context(pipe), pq->fence);
67         swr_fence_finish(pipe->screen, pq->fence, 0);
68      }
69      swr_fence_reference(pipe->screen, &pq->fence, NULL);
70   }
71
72   FREE(pq);
73}
74
75
76// XXX Create a fence callback, rather than stalling SwrWaitForIdle
77static void
78swr_gather_stats(struct pipe_context *pipe, struct swr_query *pq)
79{
80   struct swr_context *ctx = swr_context(pipe);
81
82   assert(pq->result);
83   union pipe_query_result *result = pq->result;
84   boolean enable_stats = pq->enable_stats;
85   SWR_STATS swr_stats = {0};
86
87   if (pq->fence) {
88      if (!swr_is_fence_pending(pq->fence)) {
89         swr_fence_submit(ctx, pq->fence);
90         swr_fence_finish(pipe->screen, pq->fence, 0);
91      }
92      swr_fence_reference(pipe->screen, &pq->fence, NULL);
93   }
94
95   /*
96    * These queries don't need SWR Stats enabled in the core
97    * Set and return.
98    */
99   switch (pq->type) {
100   case PIPE_QUERY_TIMESTAMP:
101   case PIPE_QUERY_TIME_ELAPSED:
102      result->u64 = swr_get_timestamp(pipe->screen);
103      return;
104      break;
105   case PIPE_QUERY_TIMESTAMP_DISJOINT:
106      /* nothing to do here */
107      return;
108      break;
109   case PIPE_QUERY_GPU_FINISHED:
110      result->b = TRUE; /* XXX TODO Add an api func to SWR to compare drawId
111                           vs LastRetiredId? */
112      return;
113      break;
114   default:
115      /* Any query that needs SwrCore stats */
116      break;
117   }
118
119   /*
120    * All other results are collected from SwrCore counters
121    */
122
123   /* XXX, Should turn this into a fence callback and skip the stall */
124   SwrGetStats(ctx->swrContext, &swr_stats);
125   /* SwrGetStats returns immediately, wait for collection */
126   SwrWaitForIdle(ctx->swrContext);
127
128   switch (pq->type) {
129   case PIPE_QUERY_OCCLUSION_PREDICATE:
130   case PIPE_QUERY_OCCLUSION_COUNTER:
131      result->u64 = swr_stats.DepthPassCount;
132      break;
133   case PIPE_QUERY_PRIMITIVES_GENERATED:
134      result->u64 = swr_stats.IaPrimitives;
135      break;
136   case PIPE_QUERY_PRIMITIVES_EMITTED:
137      result->u64 = swr_stats.SoNumPrimsWritten[pq->index];
138      break;
139   case PIPE_QUERY_SO_STATISTICS:
140   case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
141      struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
142      so_stats->num_primitives_written =
143         swr_stats.SoNumPrimsWritten[pq->index];
144      so_stats->primitives_storage_needed =
145         swr_stats.SoPrimStorageNeeded[pq->index];
146   } break;
147   case PIPE_QUERY_PIPELINE_STATISTICS: {
148      struct pipe_query_data_pipeline_statistics *p_stats =
149         &result->pipeline_statistics;
150      p_stats->ia_vertices = swr_stats.IaVertices;
151      p_stats->ia_primitives = swr_stats.IaPrimitives;
152      p_stats->vs_invocations = swr_stats.VsInvocations;
153      p_stats->gs_invocations = swr_stats.GsInvocations;
154      p_stats->gs_primitives = swr_stats.GsPrimitives;
155      p_stats->c_invocations = swr_stats.CPrimitives;
156      p_stats->c_primitives = swr_stats.CPrimitives;
157      p_stats->ps_invocations = swr_stats.PsInvocations;
158      p_stats->hs_invocations = swr_stats.HsInvocations;
159      p_stats->ds_invocations = swr_stats.DsInvocations;
160      p_stats->cs_invocations = swr_stats.CsInvocations;
161   } break;
162   default:
163      assert(0 && "Unsupported query");
164      break;
165   }
166
167   /* Only change stat collection if there are no active queries */
168   if (ctx->active_queries == 0)
169      SwrEnableStats(ctx->swrContext, enable_stats);
170}
171
172
173static boolean
174swr_get_query_result(struct pipe_context *pipe,
175                     struct pipe_query *q,
176                     boolean wait,
177                     union pipe_query_result *result)
178{
179   struct swr_context *ctx = swr_context(pipe);
180   struct swr_query *pq = swr_query(q);
181
182   if (pq->fence) {
183      if (!swr_is_fence_pending(pq->fence)) {
184         swr_fence_submit(ctx, pq->fence);
185         if (!wait)
186            return FALSE;
187         swr_fence_finish(pipe->screen, pq->fence, 0);
188      }
189      swr_fence_reference(pipe->screen, &pq->fence, NULL);
190   }
191
192   /* XXX: Need to handle counter rollover */
193
194   switch (pq->type) {
195   /* Booleans */
196   case PIPE_QUERY_OCCLUSION_PREDICATE:
197      result->b = pq->end.u64 != pq->start.u64 ? TRUE : FALSE;
198      break;
199   case PIPE_QUERY_GPU_FINISHED:
200      result->b = pq->end.b;
201      break;
202   /* Counters */
203   case PIPE_QUERY_OCCLUSION_COUNTER:
204   case PIPE_QUERY_TIMESTAMP:
205   case PIPE_QUERY_TIME_ELAPSED:
206   case PIPE_QUERY_PRIMITIVES_GENERATED:
207   case PIPE_QUERY_PRIMITIVES_EMITTED:
208      result->u64 = pq->end.u64 - pq->start.u64;
209      break;
210   /* Structures */
211   case PIPE_QUERY_SO_STATISTICS: {
212      struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
213      struct pipe_query_data_so_statistics *start = &pq->start.so_statistics;
214      struct pipe_query_data_so_statistics *end = &pq->end.so_statistics;
215      so_stats->num_primitives_written =
216         end->num_primitives_written - start->num_primitives_written;
217      so_stats->primitives_storage_needed =
218         end->primitives_storage_needed - start->primitives_storage_needed;
219   } break;
220   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
221      /* os_get_time_nano returns nanoseconds */
222      result->timestamp_disjoint.frequency = UINT64_C(1000000000);
223      result->timestamp_disjoint.disjoint = FALSE;
224   } break;
225   case PIPE_QUERY_PIPELINE_STATISTICS: {
226      struct pipe_query_data_pipeline_statistics *p_stats =
227         &result->pipeline_statistics;
228      struct pipe_query_data_pipeline_statistics *start =
229         &pq->start.pipeline_statistics;
230      struct pipe_query_data_pipeline_statistics *end =
231         &pq->end.pipeline_statistics;
232      p_stats->ia_vertices = end->ia_vertices - start->ia_vertices;
233      p_stats->ia_primitives = end->ia_primitives - start->ia_primitives;
234      p_stats->vs_invocations = end->vs_invocations - start->vs_invocations;
235      p_stats->gs_invocations = end->gs_invocations - start->gs_invocations;
236      p_stats->gs_primitives = end->gs_primitives - start->gs_primitives;
237      p_stats->c_invocations = end->c_invocations - start->c_invocations;
238      p_stats->c_primitives = end->c_primitives - start->c_primitives;
239      p_stats->ps_invocations = end->ps_invocations - start->ps_invocations;
240      p_stats->hs_invocations = end->hs_invocations - start->hs_invocations;
241      p_stats->ds_invocations = end->ds_invocations - start->ds_invocations;
242      p_stats->cs_invocations = end->cs_invocations - start->cs_invocations;
243   } break;
244   case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
245      struct pipe_query_data_so_statistics *start = &pq->start.so_statistics;
246      struct pipe_query_data_so_statistics *end = &pq->end.so_statistics;
247      uint64_t num_primitives_written =
248         end->num_primitives_written - start->num_primitives_written;
249      uint64_t primitives_storage_needed =
250         end->primitives_storage_needed - start->primitives_storage_needed;
251      result->b = num_primitives_written > primitives_storage_needed;
252   } break;
253   default:
254      assert(0 && "Unsupported query");
255      break;
256   }
257
258   return TRUE;
259}
260
261static boolean
262swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
263{
264   struct swr_context *ctx = swr_context(pipe);
265   struct swr_query *pq = swr_query(q);
266
267   /* Initialize Results */
268   memset(&pq->start, 0, sizeof(pq->start));
269   memset(&pq->end, 0, sizeof(pq->end));
270
271   /* Gather start stats and enable SwrCore counters */
272   pq->result = &pq->start;
273   pq->enable_stats = TRUE;
274   swr_gather_stats(pipe, pq);
275   ctx->active_queries++;
276
277   /* override start timestamp to 0 for TIMESTAMP query */
278   if (pq->type == PIPE_QUERY_TIMESTAMP)
279      pq->start.u64 = 0;
280
281   return true;
282}
283
284static bool
285swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
286{
287   struct swr_context *ctx = swr_context(pipe);
288   struct swr_query *pq = swr_query(q);
289
290   assert(ctx->active_queries
291          && "swr_end_query, there are no active queries!");
292   ctx->active_queries--;
293
294   /* Gather end stats and disable SwrCore counters */
295   pq->result = &pq->end;
296   pq->enable_stats = FALSE;
297   swr_gather_stats(pipe, pq);
298   return true;
299}
300
301
302boolean
303swr_check_render_cond(struct pipe_context *pipe)
304{
305   struct swr_context *ctx = swr_context(pipe);
306   boolean b, wait;
307   uint64_t result;
308
309   if (!ctx->render_cond_query)
310      return TRUE; /* no query predicate, draw normally */
311
312   wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
313           || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
314
315   b = pipe->get_query_result(
316      pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
317   if (b)
318      return ((!result) == ctx->render_cond_cond);
319   else
320      return TRUE;
321}
322
323
324static void
325swr_set_active_query_state(struct pipe_context *pipe, boolean enable)
326{
327}
328
329void
330swr_query_init(struct pipe_context *pipe)
331{
332   struct swr_context *ctx = swr_context(pipe);
333
334   pipe->create_query = swr_create_query;
335   pipe->destroy_query = swr_destroy_query;
336   pipe->begin_query = swr_begin_query;
337   pipe->end_query = swr_end_query;
338   pipe->get_query_result = swr_get_query_result;
339   pipe->set_active_query_state = swr_set_active_query_state;
340
341   ctx->active_queries = 0;
342}
343