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      pq->index = index;
65   }
66
67   return (struct pipe_query *) pq;
68}
69
70
71static void
72llvmpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
73{
74   struct llvmpipe_query *pq = llvmpipe_query(q);
75
76   /* Ideally we would refcount queries & not get destroyed until the
77    * last scene had finished with us.
78    */
79   if (pq->fence) {
80      if (!lp_fence_issued(pq->fence))
81         llvmpipe_flush(pipe, NULL, __FUNCTION__);
82
83      if (!lp_fence_signalled(pq->fence))
84         lp_fence_wait(pq->fence);
85
86      lp_fence_reference(&pq->fence, NULL);
87   }
88
89   FREE(pq);
90}
91
92
93static bool
94llvmpipe_get_query_result(struct pipe_context *pipe,
95                          struct pipe_query *q,
96                          bool wait,
97                          union pipe_query_result *vresult)
98{
99   struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
100   unsigned num_threads = MAX2(1, screen->num_threads);
101   struct llvmpipe_query *pq = llvmpipe_query(q);
102   uint64_t *result = (uint64_t *)vresult;
103   int i;
104
105   if (pq->fence) {
106      /* only have a fence if there was a scene */
107      if (!lp_fence_signalled(pq->fence)) {
108         if (!lp_fence_issued(pq->fence))
109            llvmpipe_flush(pipe, NULL, __FUNCTION__);
110
111         if (!wait)
112            return false;
113
114         lp_fence_wait(pq->fence);
115      }
116   }
117
118   /* Sum the results from each of the threads:
119    */
120   *result = 0;
121
122   switch (pq->type) {
123   case PIPE_QUERY_OCCLUSION_COUNTER:
124      for (i = 0; i < num_threads; i++) {
125         *result += pq->end[i];
126      }
127      break;
128   case PIPE_QUERY_OCCLUSION_PREDICATE:
129   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
130      for (i = 0; i < num_threads; i++) {
131         /* safer (still not guaranteed) when there's an overflow */
132         vresult->b = vresult->b || pq->end[i];
133      }
134      break;
135   case PIPE_QUERY_TIMESTAMP:
136      for (i = 0; i < num_threads; i++) {
137         if (pq->end[i] > *result) {
138            *result = pq->end[i];
139         }
140      }
141      break;
142   case PIPE_QUERY_TIME_ELAPSED: {
143      uint64_t start = (uint64_t)-1, end = 0;
144      for (i = 0; i < num_threads; i++) {
145         if (pq->start[i] && pq->start[i] < start)
146            start = pq->start[i];
147         if (pq->end[i] && pq->end[i] > end)
148            end = pq->end[i];
149      }
150      *result = end - start;
151      break;
152   }
153   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
154      struct pipe_query_data_timestamp_disjoint *td =
155         (struct pipe_query_data_timestamp_disjoint *)vresult;
156      /* os_get_time_nano return nanoseconds */
157      td->frequency = UINT64_C(1000000000);
158      td->disjoint = false;
159   }
160      break;
161   case PIPE_QUERY_GPU_FINISHED:
162      vresult->b = true;
163      break;
164   case PIPE_QUERY_PRIMITIVES_GENERATED:
165      *result = pq->num_primitives_generated[0];
166      break;
167   case PIPE_QUERY_PRIMITIVES_EMITTED:
168      *result = pq->num_primitives_written[0];
169      break;
170   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
171      vresult->b = false;
172      for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)
173         vresult->b |= pq->num_primitives_generated[s] > pq->num_primitives_written[s];
174      break;
175   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
176      vresult->b = pq->num_primitives_generated[0] > pq->num_primitives_written[0];
177      break;
178   case PIPE_QUERY_SO_STATISTICS: {
179      struct pipe_query_data_so_statistics *stats =
180         (struct pipe_query_data_so_statistics *)vresult;
181      stats->num_primitives_written = pq->num_primitives_written[0];
182      stats->primitives_storage_needed = pq->num_primitives_generated[0];
183   }
184      break;
185   case PIPE_QUERY_PIPELINE_STATISTICS: {
186      struct pipe_query_data_pipeline_statistics *stats =
187         (struct pipe_query_data_pipeline_statistics *)vresult;
188      /* only ps_invocations come from binned query */
189      for (i = 0; i < num_threads; i++) {
190         pq->stats.ps_invocations += pq->end[i];
191      }
192      pq->stats.ps_invocations *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
193      *stats = pq->stats;
194   }
195      break;
196   default:
197      assert(0);
198      break;
199   }
200
201   return true;
202}
203
204static void
205llvmpipe_get_query_result_resource(struct pipe_context *pipe,
206                                   struct pipe_query *q,
207                                   bool wait,
208                                   enum pipe_query_value_type result_type,
209                                   int index,
210                                   struct pipe_resource *resource,
211                                   unsigned offset)
212{
213   struct llvmpipe_screen *screen = llvmpipe_screen(pipe->screen);
214   unsigned num_threads = MAX2(1, screen->num_threads);
215   struct llvmpipe_query *pq = llvmpipe_query(q);
216   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
217   bool unsignalled = false;
218   if (pq->fence) {
219      /* only have a fence if there was a scene */
220      if (!lp_fence_signalled(pq->fence)) {
221         if (!lp_fence_issued(pq->fence))
222            llvmpipe_flush(pipe, NULL, __FUNCTION__);
223
224         if (wait)
225            lp_fence_wait(pq->fence);
226      }
227      unsignalled = !lp_fence_signalled(pq->fence);
228   }
229
230
231   uint64_t value = 0, value2 = 0;
232   unsigned num_values = 1;
233   if (index == -1)
234      if (unsignalled)
235         value = 0;
236      else
237         value = 1;
238   else {
239      unsigned i;
240
241      switch (pq->type) {
242      case PIPE_QUERY_OCCLUSION_COUNTER:
243         for (i = 0; i < num_threads; i++) {
244            value += pq->end[i];
245         }
246         break;
247      case PIPE_QUERY_OCCLUSION_PREDICATE:
248      case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
249         for (i = 0; i < num_threads; i++) {
250            /* safer (still not guaranteed) when there's an overflow */
251            value = value || pq->end[i];
252         }
253         break;
254      case PIPE_QUERY_PRIMITIVES_GENERATED:
255         value = pq->num_primitives_generated[0];
256         break;
257      case PIPE_QUERY_PRIMITIVES_EMITTED:
258         value = pq->num_primitives_written[0];
259         break;
260      case PIPE_QUERY_TIMESTAMP:
261         for (i = 0; i < num_threads; i++) {
262            if (pq->end[i] > value) {
263               value = pq->end[i];
264            }
265         }
266         break;
267      case PIPE_QUERY_TIME_ELAPSED: {
268         uint64_t start = (uint64_t)-1, end = 0;
269         for (i = 0; i < num_threads; i++) {
270            if (pq->start[i] && pq->start[i] < start)
271               start = pq->start[i];
272            if (pq->end[i] && pq->end[i] > end)
273               end = pq->end[i];
274         }
275         value = end - start;
276         break;
277      }
278      case PIPE_QUERY_SO_STATISTICS:
279         value = pq->num_primitives_written[0];
280         value2 = pq->num_primitives_generated[0];
281         num_values = 2;
282         break;
283      case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
284         value = 0;
285         for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++)
286            value |= !!(pq->num_primitives_generated[s] > pq->num_primitives_written[s]);
287         break;
288      case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
289         value = !!(pq->num_primitives_generated[0] > pq->num_primitives_written[0]);
290         break;
291      case PIPE_QUERY_PIPELINE_STATISTICS:
292         switch ((enum pipe_statistics_query_index)index) {
293         case PIPE_STAT_QUERY_IA_VERTICES:
294            value = pq->stats.ia_vertices;
295            break;
296         case PIPE_STAT_QUERY_IA_PRIMITIVES:
297            value = pq->stats.ia_primitives;
298            break;
299         case PIPE_STAT_QUERY_VS_INVOCATIONS:
300            value = pq->stats.vs_invocations;
301            break;
302         case PIPE_STAT_QUERY_GS_INVOCATIONS:
303            value = pq->stats.gs_invocations;
304            break;
305         case PIPE_STAT_QUERY_GS_PRIMITIVES:
306            value = pq->stats.gs_primitives;
307            break;
308         case PIPE_STAT_QUERY_C_INVOCATIONS:
309            value = pq->stats.c_invocations;
310            break;
311         case PIPE_STAT_QUERY_C_PRIMITIVES:
312            value = pq->stats.c_primitives;
313            break;
314         case PIPE_STAT_QUERY_PS_INVOCATIONS:
315            value = 0;
316            for (i = 0; i < num_threads; i++) {
317               value += pq->end[i];
318            }
319            value *= LP_RASTER_BLOCK_SIZE * LP_RASTER_BLOCK_SIZE;
320            break;
321         case PIPE_STAT_QUERY_HS_INVOCATIONS:
322            value = pq->stats.hs_invocations;
323            break;
324         case PIPE_STAT_QUERY_DS_INVOCATIONS:
325            value = pq->stats.ds_invocations;
326            break;
327         case PIPE_STAT_QUERY_CS_INVOCATIONS:
328            value = pq->stats.cs_invocations;
329            break;
330         }
331         break;
332      default:
333         fprintf(stderr, "Unknown query type %d\n", pq->type);
334         break;
335      }
336   }
337
338   void *dst = (uint8_t *)lpr->data + offset;
339
340   for (unsigned i = 0; i < num_values; i++) {
341
342      if (i == 1) {
343         value = value2;
344         dst = (char *)dst + ((result_type == PIPE_QUERY_TYPE_I64 ||
345                               result_type == PIPE_QUERY_TYPE_U64) ? 8 : 4);
346      }
347      switch (result_type) {
348      case PIPE_QUERY_TYPE_I32: {
349         int32_t *iptr = (int32_t *)dst;
350         if (value > 0x7fffffff)
351            *iptr = 0x7fffffff;
352         else
353            *iptr = (int32_t)value;
354         break;
355      }
356      case PIPE_QUERY_TYPE_U32: {
357         uint32_t *uptr = (uint32_t *)dst;
358         if (value > 0xffffffff)
359            *uptr = 0xffffffff;
360         else
361            *uptr = (uint32_t)value;
362         break;
363      }
364      case PIPE_QUERY_TYPE_I64: {
365         int64_t *iptr = (int64_t *)dst;
366         *iptr = (int64_t)value;
367         break;
368      }
369      case PIPE_QUERY_TYPE_U64: {
370         uint64_t *uptr = (uint64_t *)dst;
371         *uptr = (uint64_t)value;
372         break;
373      }
374      }
375   }
376}
377
378static bool
379llvmpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
380{
381   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
382   struct llvmpipe_query *pq = llvmpipe_query(q);
383
384   /* Check if the query is already in the scene.  If so, we need to
385    * flush the scene now.  Real apps shouldn't re-use a query in a
386    * frame of rendering.
387    */
388   if (pq->fence && !lp_fence_issued(pq->fence)) {
389      llvmpipe_finish(pipe, __FUNCTION__);
390   }
391
392
393   memset(pq->start, 0, sizeof(pq->start));
394   memset(pq->end, 0, sizeof(pq->end));
395   lp_setup_begin_query(llvmpipe->setup, pq);
396
397   switch (pq->type) {
398   case PIPE_QUERY_PRIMITIVES_EMITTED:
399      pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
400      break;
401   case PIPE_QUERY_PRIMITIVES_GENERATED:
402      pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
403      llvmpipe->active_primgen_queries++;
404      break;
405   case PIPE_QUERY_SO_STATISTICS:
406      pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
407      pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
408      break;
409   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
410      for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {
411         pq->num_primitives_written[s] = llvmpipe->so_stats[s].num_primitives_written;
412         pq->num_primitives_generated[s] = llvmpipe->so_stats[s].primitives_storage_needed;
413      }
414      break;
415   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
416      pq->num_primitives_written[0] = llvmpipe->so_stats[pq->index].num_primitives_written;
417      pq->num_primitives_generated[0] = llvmpipe->so_stats[pq->index].primitives_storage_needed;
418      break;
419   case PIPE_QUERY_PIPELINE_STATISTICS:
420      /* reset our cache */
421      if (llvmpipe->active_statistics_queries == 0) {
422         memset(&llvmpipe->pipeline_statistics, 0,
423                sizeof(llvmpipe->pipeline_statistics));
424      }
425      memcpy(&pq->stats, &llvmpipe->pipeline_statistics, sizeof(pq->stats));
426      llvmpipe->active_statistics_queries++;
427      break;
428   case PIPE_QUERY_OCCLUSION_COUNTER:
429   case PIPE_QUERY_OCCLUSION_PREDICATE:
430   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
431      llvmpipe->active_occlusion_queries++;
432      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
433      break;
434   default:
435      break;
436   }
437   return true;
438}
439
440
441static bool
442llvmpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
443{
444   struct llvmpipe_context *llvmpipe = llvmpipe_context( pipe );
445   struct llvmpipe_query *pq = llvmpipe_query(q);
446
447   lp_setup_end_query(llvmpipe->setup, pq);
448
449   switch (pq->type) {
450
451   case PIPE_QUERY_PRIMITIVES_EMITTED:
452      pq->num_primitives_written[0] =
453         llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
454      break;
455   case PIPE_QUERY_PRIMITIVES_GENERATED:
456      assert(llvmpipe->active_primgen_queries);
457      llvmpipe->active_primgen_queries--;
458      pq->num_primitives_generated[0] =
459         llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
460      break;
461   case PIPE_QUERY_SO_STATISTICS:
462      pq->num_primitives_written[0] =
463         llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
464      pq->num_primitives_generated[0] =
465         llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
466      break;
467   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
468      for (unsigned s = 0; s < PIPE_MAX_VERTEX_STREAMS; s++) {
469         pq->num_primitives_written[s] =
470            llvmpipe->so_stats[s].num_primitives_written - pq->num_primitives_written[s];
471         pq->num_primitives_generated[s] =
472            llvmpipe->so_stats[s].primitives_storage_needed - pq->num_primitives_generated[s];
473      }
474      break;
475   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
476      pq->num_primitives_written[0] =
477         llvmpipe->so_stats[pq->index].num_primitives_written - pq->num_primitives_written[0];
478      pq->num_primitives_generated[0] =
479         llvmpipe->so_stats[pq->index].primitives_storage_needed - pq->num_primitives_generated[0];
480      break;
481   case PIPE_QUERY_PIPELINE_STATISTICS:
482      pq->stats.ia_vertices =
483         llvmpipe->pipeline_statistics.ia_vertices - pq->stats.ia_vertices;
484      pq->stats.ia_primitives =
485         llvmpipe->pipeline_statistics.ia_primitives - pq->stats.ia_primitives;
486      pq->stats.vs_invocations =
487         llvmpipe->pipeline_statistics.vs_invocations - pq->stats.vs_invocations;
488      pq->stats.gs_invocations =
489         llvmpipe->pipeline_statistics.gs_invocations - pq->stats.gs_invocations;
490      pq->stats.gs_primitives =
491         llvmpipe->pipeline_statistics.gs_primitives - pq->stats.gs_primitives;
492      pq->stats.c_invocations =
493         llvmpipe->pipeline_statistics.c_invocations - pq->stats.c_invocations;
494      pq->stats.c_primitives =
495         llvmpipe->pipeline_statistics.c_primitives - pq->stats.c_primitives;
496      pq->stats.ps_invocations =
497         llvmpipe->pipeline_statistics.ps_invocations - pq->stats.ps_invocations;
498      pq->stats.cs_invocations =
499         llvmpipe->pipeline_statistics.cs_invocations - pq->stats.cs_invocations;
500      pq->stats.hs_invocations =
501         llvmpipe->pipeline_statistics.hs_invocations - pq->stats.hs_invocations;
502      pq->stats.ds_invocations =
503         llvmpipe->pipeline_statistics.ds_invocations - pq->stats.ds_invocations;
504      llvmpipe->active_statistics_queries--;
505      break;
506   case PIPE_QUERY_OCCLUSION_COUNTER:
507   case PIPE_QUERY_OCCLUSION_PREDICATE:
508   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
509      assert(llvmpipe->active_occlusion_queries);
510      llvmpipe->active_occlusion_queries--;
511      llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
512      break;
513   default:
514      break;
515   }
516
517   return true;
518}
519
520boolean
521llvmpipe_check_render_cond(struct llvmpipe_context *lp)
522{
523   struct pipe_context *pipe = &lp->pipe;
524   boolean b, wait;
525   uint64_t result;
526
527   if (lp->render_cond_buffer) {
528      uint32_t data = *(uint32_t *)((char *)lp->render_cond_buffer->data + lp->render_cond_offset);
529      return (!data) == lp->render_cond_cond;
530   }
531   if (!lp->render_cond_query)
532      return TRUE; /* no query predicate, draw normally */
533
534   wait = (lp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
535           lp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
536
537   b = pipe->get_query_result(pipe, lp->render_cond_query, wait, (void*)&result);
538   if (b)
539      return ((!result) == lp->render_cond_cond);
540   else
541      return TRUE;
542}
543
544static void
545llvmpipe_set_active_query_state(struct pipe_context *pipe, bool enable)
546{
547   struct llvmpipe_context *llvmpipe = llvmpipe_context(pipe);
548
549   llvmpipe->queries_disabled = !enable;
550   /* for OQs we need to regenerate the fragment shader */
551   llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
552}
553
554void llvmpipe_init_query_funcs(struct llvmpipe_context *llvmpipe )
555{
556   llvmpipe->pipe.create_query = llvmpipe_create_query;
557   llvmpipe->pipe.destroy_query = llvmpipe_destroy_query;
558   llvmpipe->pipe.begin_query = llvmpipe_begin_query;
559   llvmpipe->pipe.end_query = llvmpipe_end_query;
560   llvmpipe->pipe.get_query_result = llvmpipe_get_query_result;
561   llvmpipe->pipe.get_query_result_resource = llvmpipe_get_query_result_resource;
562   llvmpipe->pipe.set_active_query_state = llvmpipe_set_active_query_state;
563}
564
565
566