swr_query.cpp revision e35cfa15cf2aa894dd267309eed250f6bc3c68c6
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#include "common/os.h"
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 = (struct swr_query *) AlignedMalloc(sizeof(struct swr_query), 64);
49   memset(pq, 0, sizeof(*pq));
50
51   if (pq) {
52      pq->type = type;
53      pq->index = index;
54   }
55
56   return (struct pipe_query *)pq;
57}
58
59
60static void
61swr_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
62{
63   struct swr_query *pq = swr_query(q);
64
65   if (pq->fence) {
66      if (swr_is_fence_pending(pq->fence))
67         swr_fence_finish(pipe->screen, NULL, pq->fence, 0);
68      swr_fence_reference(pipe->screen, &pq->fence, NULL);
69   }
70
71   AlignedFree(pq);
72}
73
74
75static boolean
76swr_get_query_result(struct pipe_context *pipe,
77                     struct pipe_query *q,
78                     boolean wait,
79                     union pipe_query_result *result)
80{
81   struct swr_query *pq = swr_query(q);
82   unsigned index = pq->index;
83
84   if (pq->fence) {
85      if (!wait && !swr_is_fence_done(pq->fence))
86         return FALSE;
87
88      swr_fence_finish(pipe->screen, NULL, pq->fence, 0);
89      swr_fence_reference(pipe->screen, &pq->fence, NULL);
90   }
91
92   /* All values are reset to 0 at swr_begin_query, except starting timestamp.
93    * Counters become simply end values.  */
94   switch (pq->type) {
95   /* Booleans */
96   case PIPE_QUERY_OCCLUSION_PREDICATE:
97      result->b = pq->result.core.DepthPassCount != 0;
98      break;
99   case PIPE_QUERY_GPU_FINISHED:
100      result->b = TRUE;
101      break;
102   /* Counters */
103   case PIPE_QUERY_OCCLUSION_COUNTER:
104      result->u64 = pq->result.core.DepthPassCount;
105      break;
106   case PIPE_QUERY_TIMESTAMP:
107   case PIPE_QUERY_TIME_ELAPSED:
108      result->u64 = pq->result.timestamp_end - pq->result.timestamp_start;
109      break;
110   case PIPE_QUERY_PRIMITIVES_GENERATED:
111      result->u64 = pq->result.coreFE.IaPrimitives;
112      break;
113   case PIPE_QUERY_PRIMITIVES_EMITTED:
114      result->u64 = pq->result.coreFE.SoNumPrimsWritten[index];
115      break;
116   /* Structures */
117   case PIPE_QUERY_SO_STATISTICS: {
118      struct pipe_query_data_so_statistics *so_stats = &result->so_statistics;
119      so_stats->num_primitives_written =
120         pq->result.coreFE.SoNumPrimsWritten[index];
121      so_stats->primitives_storage_needed =
122         pq->result.coreFE.SoPrimStorageNeeded[index];
123   } break;
124   case PIPE_QUERY_TIMESTAMP_DISJOINT:
125      /* os_get_time_nano returns nanoseconds */
126      result->timestamp_disjoint.frequency = UINT64_C(1000000000);
127      result->timestamp_disjoint.disjoint = FALSE;
128      break;
129   case PIPE_QUERY_PIPELINE_STATISTICS: {
130      struct pipe_query_data_pipeline_statistics *p_stats =
131         &result->pipeline_statistics;
132      p_stats->ia_vertices = pq->result.coreFE.IaVertices;
133      p_stats->ia_primitives = pq->result.coreFE.IaPrimitives;
134      p_stats->vs_invocations = pq->result.coreFE.VsInvocations;
135      p_stats->gs_invocations = pq->result.coreFE.GsInvocations;
136      p_stats->gs_primitives = pq->result.coreFE.GsPrimitives;
137      p_stats->c_invocations = pq->result.coreFE.CPrimitives;
138      p_stats->c_primitives = pq->result.coreFE.CPrimitives;
139      p_stats->ps_invocations = pq->result.core.PsInvocations;
140      p_stats->hs_invocations = pq->result.coreFE.HsInvocations;
141      p_stats->ds_invocations = pq->result.coreFE.DsInvocations;
142      p_stats->cs_invocations = pq->result.core.CsInvocations;
143    } break;
144   case PIPE_QUERY_SO_OVERFLOW_PREDICATE: {
145      uint64_t num_primitives_written =
146         pq->result.coreFE.SoNumPrimsWritten[index];
147      uint64_t primitives_storage_needed =
148         pq->result.coreFE.SoPrimStorageNeeded[index];
149      result->b = num_primitives_written > primitives_storage_needed;
150   }
151      break;
152   default:
153      assert(0 && "Unsupported query");
154      break;
155   }
156
157   return TRUE;
158}
159
160static boolean
161swr_begin_query(struct pipe_context *pipe, struct pipe_query *q)
162{
163   struct swr_context *ctx = swr_context(pipe);
164   struct swr_query *pq = swr_query(q);
165
166   /* Initialize Results */
167   memset(&pq->result, 0, sizeof(pq->result));
168   switch (pq->type) {
169   case PIPE_QUERY_GPU_FINISHED:
170   case PIPE_QUERY_TIMESTAMP:
171      /* nothing to do, but don't want the default */
172      break;
173   case PIPE_QUERY_TIME_ELAPSED:
174      pq->result.timestamp_start = swr_get_timestamp(pipe->screen);
175      break;
176   default:
177      /* Core counters required.  Update draw context with location to
178       * store results. */
179      swr_update_draw_context(ctx, &pq->result);
180
181      /* Only change stat collection if there are no active queries */
182      if (ctx->active_queries == 0) {
183         SwrEnableStatsFE(ctx->swrContext, TRUE);
184         SwrEnableStatsBE(ctx->swrContext, TRUE);
185      }
186      ctx->active_queries++;
187      break;
188   }
189
190
191   return true;
192}
193
194static bool
195swr_end_query(struct pipe_context *pipe, struct pipe_query *q)
196{
197   struct swr_context *ctx = swr_context(pipe);
198   struct swr_query *pq = swr_query(q);
199
200   switch (pq->type) {
201   case PIPE_QUERY_GPU_FINISHED:
202      /* nothing to do, but don't want the default */
203      break;
204   case PIPE_QUERY_TIMESTAMP:
205   case PIPE_QUERY_TIME_ELAPSED:
206      pq->result.timestamp_end = swr_get_timestamp(pipe->screen);
207      break;
208   default:
209      /* Stats are updated asynchronously, a fence is used to signal
210       * completion. */
211      if (!pq->fence) {
212         struct swr_screen *screen = swr_screen(pipe->screen);
213         swr_fence_reference(pipe->screen, &pq->fence, screen->flush_fence);
214      }
215      swr_fence_submit(ctx, pq->fence);
216
217      /* Only change stat collection if there are no active queries */
218      ctx->active_queries--;
219      if (ctx->active_queries == 0) {
220         SwrEnableStatsFE(ctx->swrContext, FALSE);
221         SwrEnableStatsBE(ctx->swrContext, FALSE);
222      }
223
224      break;
225   }
226
227   return true;
228}
229
230
231boolean
232swr_check_render_cond(struct pipe_context *pipe)
233{
234   struct swr_context *ctx = swr_context(pipe);
235   boolean b, wait;
236   uint64_t result;
237
238   if (!ctx->render_cond_query)
239      return TRUE; /* no query predicate, draw normally */
240
241   wait = (ctx->render_cond_mode == PIPE_RENDER_COND_WAIT
242           || ctx->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
243
244   b = pipe->get_query_result(
245      pipe, ctx->render_cond_query, wait, (union pipe_query_result *)&result);
246   if (b)
247      return ((!result) == ctx->render_cond_cond);
248   else
249      return TRUE;
250}
251
252
253static void
254swr_set_active_query_state(struct pipe_context *pipe, boolean enable)
255{
256}
257
258void
259swr_query_init(struct pipe_context *pipe)
260{
261   struct swr_context *ctx = swr_context(pipe);
262
263   pipe->create_query = swr_create_query;
264   pipe->destroy_query = swr_destroy_query;
265   pipe->begin_query = swr_begin_query;
266   pipe->end_query = swr_end_query;
267   pipe->get_query_result = swr_get_query_result;
268   pipe->set_active_query_state = swr_set_active_query_state;
269
270   ctx->active_queries = 0;
271}
272