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