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 "util/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   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
129      for (i = 0; i < num_threads; i++) {
130         /* safer (still not guaranteed) when there's an overflow */
131         vresult->b = vresult->b || pq->end[i];
132      }
133      break;
134   case PIPE_QUERY_TIMESTAMP:
135      for (i = 0; i < num_threads; i++) {
136         if (pq->end[i] > *result) {
137            *result = pq->end[i];
138         }
139      }
140      break;
141   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
142      struct pipe_query_data_timestamp_disjoint *td =
143         (struct pipe_query_data_timestamp_disjoint *)vresult;
144      /* os_get_time_nano return nanoseconds */
145      td->frequency = UINT64_C(1000000000);
146      td->disjoint = FALSE;
147   }
148      break;
149   case PIPE_QUERY_GPU_FINISHED:
150      vresult->b = TRUE;
151      break;
152   case PIPE_QUERY_PRIMITIVES_GENERATED:
153      *result = pq->num_primitives_generated;
154      break;
155   case PIPE_QUERY_PRIMITIVES_EMITTED:
156      *result = pq->num_primitives_written;
157      break;
158   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
159   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
160      vresult->b = pq->num_primitives_generated > pq->num_primitives_written;
161      break;
162   case PIPE_QUERY_SO_STATISTICS: {
163      struct pipe_query_data_so_statistics *stats =
164         (struct pipe_query_data_so_statistics *)vresult;
165      stats->num_primitives_written = pq->num_primitives_written;
166      stats->primitives_storage_needed = pq->num_primitives_generated;
167   }
168      break;
169   case PIPE_QUERY_PIPELINE_STATISTICS: {
170      struct pipe_query_data_pipeline_statistics *stats =
171         (struct pipe_query_data_pipeline_statistics *)vresult;
172      /* only ps_invocations come from binned query */
173      for (i = 0; i < num_threads; i++) {
174         pq->stats.ps_invocations += pq->end[i];
175      }
176      pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
177      *stats = pq->stats;
178   }
179      break;
180   default:
181      assert(0);
182      break;
183   }
184
185   return TRUE;
186}
187
188
189static boolean
190llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
191{
192   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
193   struct llvmpipe_query *pq = llvmpipe_query(q);
194
195   /* Check if the query is already in the scene.  If so, we need to
196    * flush the scene now.  Real apps shouldn't re-use a query in a
197    * frame of rendering.
198    */
199   if (pq->fence && !lp_fence_issued(pq->fence)) {
200      llvmpipe_finish(pipe, __FUNCTION__);
201   }
202
203
204   memset(pq->start, 0, sizeof(pq->start));
205   memset(pq->end, 0, sizeof(pq->end));
206   lp_setup_begin_query(llvmpipe->setup, pq);
207
208   switch (pq->type) {
209   case PIPE_QUERY_PRIMITIVES_EMITTED:
210      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
211      break;
212   case PIPE_QUERY_PRIMITIVES_GENERATED:
213      pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
214      break;
215   case PIPE_QUERY_SO_STATISTICS:
216      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
217      pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
218      break;
219   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
220   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
221      pq->num_primitives_written = llvmpipe->so_stats.num_primitives_written;
222      pq->num_primitives_generated = llvmpipe->so_stats.primitives_storage_needed;
223      break;
224   case PIPE_QUERY_PIPELINE_STATISTICS:
225      /* reset our cache */
226      if (llvmpipe->active_statistics_queries == 0) {
227         memset(&llvmpipe->pipeline_statistics, 0,
228                sizeof(llvmpipe->pipeline_statistics));
229      }
230      memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
231      llvmpipe->active_statistics_queries++;
232      break;
233   case PIPE_QUERY_OCCLUSION_COUNTER:
234   case PIPE_QUERY_OCCLUSION_PREDICATE:
235   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
236      llvmpipe->active_occlusion_queries++;
237      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
238      break;
239   default:
240      break;
241   }
242   return true;
243}
244
245
246static bool
247llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
248{
249   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
250   struct llvmpipe_query *pq = llvmpipe_query(q);
251
252   lp_setup_end_query(llvmpipe->setup, pq);
253
254   switch (pq->type) {
255
256   case PIPE_QUERY_PRIMITIVES_EMITTED:
257      pq->num_primitives_written =
258         llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
259      break;
260   case PIPE_QUERY_PRIMITIVES_GENERATED:
261      pq->num_primitives_generated =
262         llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
263      break;
264   case PIPE_QUERY_SO_STATISTICS:
265      pq->num_primitives_written =
266         llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
267      pq->num_primitives_generated =
268         llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
269      break;
270   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
271   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
272      pq->num_primitives_written =
273         llvmpipe->so_stats.num_primitives_written - pq->num_primitives_written;
274      pq->num_primitives_generated =
275         llvmpipe->so_stats.primitives_storage_needed - pq->num_primitives_generated;
276      break;
277   case PIPE_QUERY_PIPELINE_STATISTICS:
278      pq->stats.ia_vertices =
279         llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
280      pq->stats.ia_primitives =
281         llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
282      pq->stats.vs_invocations =
283         llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
284      pq->stats.gs_invocations =
285         llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
286      pq->stats.gs_primitives =
287         llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
288      pq->stats.c_invocations =
289         llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
290      pq->stats.c_primitives =
291         llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
292      pq->stats.ps_invocations =
293         llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
294
295      llvmpipe->active_statistics_queries--;
296      break;
297   case PIPE_QUERY_OCCLUSION_COUNTER:
298   case PIPE_QUERY_OCCLUSION_PREDICATE:
299   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
300      assert(llvmpipe->active_occlusion_queries);
301      llvmpipe->active_occlusion_queries--;
302      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
303      break;
304   default:
305      break;
306   }
307
308   return true;
309}
310
311boolean
312llvmpipe_check_render_cond(struct llvmpipe_context *lp)
313{
314   struct pipe_context *pipe = &lp->pipe;
315   boolean b, wait;
316   uint64_t result;
317
318   if (!lp->render_cond_query)
319      return TRUE; /* no query predicate, draw normally */
320
321   wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
322           lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
323
324   b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
325   if (b)
326      return ((!result) == lp->render_cond_cond);
327   else
328      return TRUE;
329}
330
331static void
332llvmpipe_set_active_query_state(struct pipe_context *pipe, boolean enable)
333{
334}
335
336void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
337{
338   llvmpipe->pipe.create_query = llvmpipe_create_query;
339   llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
340   llvmpipe->pipe.begin_query = llvmpipe_begin_query;
341   llvmpipe->pipe.end_query = llvmpipe_end_query;
342   llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
343   llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;
344}
345
346
347