lp_query.c revision 848b8605
1/**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
4 * Copyright 2010 VMware, Inc.
5 * All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29/* Authors:
30 *    Keith Whitwell, Qicheng Christopher Li, Brian Paul
31 */
32
33#include "draw/draw_context.h"
34#include "pipe/p_defines.h"
35#include "util/u_memory.h"
36#include "os/os_time.h"
37#include "lp_context.h"
38#include "lp_flush.h"
39#include "lp_fence.h"
40#include "lp_query.h"
41#include "lp_screen.h"
42#include "lp_state.h"
43#include "lp_rast.h"
44
45
46static struct llvmpipe_query *llvmpipe_query( struct pipe_query *p )
47{
48   return (struct llvmpipe_query *)p;
49}
50
51static struct pipe_query *
52llvmpipe_create_query(struct pipe_context *pipe,
53                      unsigned type,
54                      unsigned index)
55{
56   struct llvmpipe_query *pq;
57
58   assert(type < PIPE_QUERY_TYPES);
59
60   pq = CALLOC_STRUCT( llvmpipe_query );
61
62   if (pq) {
63      pq->type = type;
64   }
65
66   return (struct pipe_query *) pq;
67}
68
69
70static void
71llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
72{
73   struct llvmpipe_query *pq = llvmpipe_query(q);
74
75   /* Ideally we would refcount queries & not get destroyed until the
76    * last scene had finished with us.
77    */
78   if (pq->fence) {
79      if (!lp_fence_issued(pq->fence))
80         llvmpipe_flush(pipe, NULL, __FUNCTION__);
81
82      if (!lp_fence_signalled(pq->fence))
83         lp_fence_wait(pq->fence);
84
85      lp_fence_reference(&pq->fence, NULL);
86   }
87
88   FREE(pq);
89}
90
91
92static boolean
93llvmpipe_get_query_result(struct pipe_context *pipe,
94                          struct pipe_query *q,
95                          boolean wait,
96                          union pipe_query_result *vresult)
97{
98   struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
99   unsigned num_threads = MAX2(1, screen->num_threads);
100   struct llvmpipe_query *pq = llvmpipe_query(q);
101   uint64_t *result = (uint64_t *)vresult;
102   int i;
103
104   if (pq->fence) {
105      /* only have a fence if there was a scene */
106      if (!lp_fence_signalled(pq->fence)) {
107         if (!lp_fence_issued(pq->fence))
108            llvmpipe_flush(pipe, NULL, __FUNCTION__);
109
110         if (!wait)
111            return FALSE;
112
113         lp_fence_wait(pq->fence);
114      }
115   }
116
117   /* Sum the results from each of the threads:
118    */
119   *result = 0;
120
121   switch (pq->type) {
122   case PIPE_QUERY_OCCLUSION_COUNTER:
123      for (i = 0; i < num_threads; i++) {
124         *result += pq->end[i];
125      }
126      break;
127   case PIPE_QUERY_OCCLUSION_PREDICATE:
128      for (i = 0; i < num_threads; i++) {
129         /* safer (still not guaranteed) when there's an overflow */
130         vresult->b = vresult->b || pq->end[i];
131      }
132      break;
133   case PIPE_QUERY_TIMESTAMP:
134      for (i = 0; i < num_threads; i++) {
135         if (pq->end[i] > *result) {
136            *result = pq->end[i];
137         }
138      }
139      break;
140   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
141      struct pipe_query_data_timestamp_disjoint *td =
142         (struct pipe_query_data_timestamp_disjoint *)vresult;
143      /* os_get_time_nano return nanoseconds */
144      td->frequency = UINT64_C(1000000000);
145      td->disjoint = FALSE;
146   }
147      break;
148   case PIPE_QUERY_GPU_FINISHED:
149      vresult->b = TRUE;
150      break;
151   case PIPE_QUERY_PRIMITIVES_GENERATED:
152      *result = pq->num_primitives_generated;
153      break;
154   case PIPE_QUERY_PRIMITIVES_EMITTED:
155      *result = pq->num_primitives_written;
156      break;
157   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
158      vresult->b = pq->num_primitives_generated > pq->num_primitives_written;
159      break;
160   case PIPE_QUERY_SO_STATISTICS: {
161      struct pipe_query_data_so_statistics *stats =
162         (struct pipe_query_data_so_statistics *)vresult;
163      stats->num_primitives_written = pq->num_primitives_written;
164      stats->primitives_storage_needed = pq->num_primitives_generated;
165   }
166      break;
167   case PIPE_QUERY_PIPELINE_STATISTICS: {
168      struct pipe_query_data_pipeline_statistics *stats =
169         (struct pipe_query_data_pipeline_statistics *)vresult;
170      /* only ps_invocations come from binned query */
171      for (i = 0; i < num_threads; i++) {
172         pq->stats.ps_invocations += pq->end[i];
173      }
174      pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
175      *stats = pq->stats;
176   }
177      break;
178   default:
179      assert(0);
180      break;
181   }
182
183   return TRUE;
184}
185
186
187static void
188llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
189{
190   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
191   struct llvmpipe_query *pq = llvmpipe_query(q);
192
193   /* Check if the query is already in the scene.  If so, we need to
194    * flush the scene now.  Real apps shouldn't re-use a query in a
195    * frame of rendering.
196    */
197   if (pq->fence && !lp_fence_issued(pq->fence)) {
198      llvmpipe_finish(pipe, __FUNCTION__);
199   }
200
201
202   memset(pq->start, 0, sizeof(pq->start));
203   memset(pq->end, 0, sizeof(pq->end));
204   lp_setup_begin_query(llvmpipe->setup, pq);
205
206   switch (pq->type) {
207   case PIPE_QUERY_PRIMITIVES_EMITTED:
208      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
209      break;
210   case PIPE_QUERY_PRIMITIVES_GENERATED:
211      pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
212      break;
213   case PIPE_QUERY_SO_STATISTICS:
214      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
215      pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
216      break;
217   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
218      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
219      pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
220      break;
221   case PIPE_QUERY_PIPELINE_STATISTICS:
222      /* reset our cache */
223      if (llvmpipe->active_statistics_queries == 0) {
224         memset(&llvmpipe->pipeline_statistics, 0,
225                sizeof(llvmpipe->pipeline_statistics));
226      }
227      memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
228      llvmpipe->active_statistics_queries++;
229      break;
230   case PIPE_QUERY_OCCLUSION_COUNTER:
231   case PIPE_QUERY_OCCLUSION_PREDICATE:
232      llvmpipe->active_occlusion_queries++;
233      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
234      break;
235   default:
236      break;
237   }
238}
239
240
241static void
242llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
243{
244   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
245   struct llvmpipe_query *pq = llvmpipe_query(q);
246
247   lp_setup_end_query(llvmpipe->setup, pq);
248
249   switch (pq->type) {
250
251   case PIPE_QUERY_PRIMITIVES_EMITTED:
252      pq->num_primitives_written =
253         llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
254      break;
255   case PIPE_QUERY_PRIMITIVES_GENERATED:
256      pq->num_primitives_generated =
257         llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
258      break;
259   case PIPE_QUERY_SO_STATISTICS:
260      pq->num_primitives_written =
261         llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
262      pq->num_primitives_generated =
263         llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
264      break;
265   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
266      pq->num_primitives_written =
267         llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
268      pq->num_primitives_generated =
269         llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
270      break;
271   case PIPE_QUERY_PIPELINE_STATISTICS:
272      pq->stats.ia_vertices =
273         llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
274      pq->stats.ia_primitives =
275         llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
276      pq->stats.vs_invocations =
277         llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
278      pq->stats.gs_invocations =
279         llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
280      pq->stats.gs_primitives =
281         llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
282      pq->stats.c_invocations =
283         llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
284      pq->stats.c_primitives =
285         llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
286      pq->stats.ps_invocations =
287         llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
288
289      llvmpipe->active_statistics_queries--;
290      break;
291   case PIPE_QUERY_OCCLUSION_COUNTER:
292   case PIPE_QUERY_OCCLUSION_PREDICATE:
293      assert(llvmpipe->active_occlusion_queries);
294      llvmpipe->active_occlusion_queries--;
295      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
296      break;
297   default:
298      break;
299   }
300}
301
302boolean
303llvmpipe_check_render_cond(struct llvmpipe_context *lp)
304{
305   struct pipe_context *pipe = &lp->pipe;
306   boolean b, wait;
307   uint64_t result;
308
309   if (!lp->render_cond_query)
310      return TRUE; /* no query predicate, draw normally */
311
312   wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
313           lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
314
315   b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
316   if (b)
317      return (!result == lp->render_cond_cond);
318   else
319      return TRUE;
320}
321
322void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
323{
324   llvmpipe->pipe.create_query = llvmpipe_create_query;
325   llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
326   llvmpipe->pipe.begin_query = llvmpipe_begin_query;
327   llvmpipe->pipe.end_query = llvmpipe_end_query;
328   llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
329}
330
331
332