14a49301eSmrg/**************************************************************************
24a49301eSmrg *
3af69d88dSmrg * Copyright 2007 VMware, Inc.
44a49301eSmrg * All Rights Reserved.
54a49301eSmrg *
64a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
74a49301eSmrg * copy of this software and associated documentation files (the
84a49301eSmrg * "Software"), to deal in the Software without restriction, including
94a49301eSmrg * without limitation the rights to use, copy, modify, merge, publish,
104a49301eSmrg * distribute, sub license, and/or sell copies of the Software, and to
114a49301eSmrg * permit persons to whom the Software is furnished to do so, subject to
124a49301eSmrg * the following conditions:
134a49301eSmrg *
144a49301eSmrg * The above copyright notice and this permission notice (including the
154a49301eSmrg * next paragraph) shall be included in all copies or substantial portions
164a49301eSmrg * of the Software.
174a49301eSmrg *
184a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
194a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
204a49301eSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21af69d88dSmrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
224a49301eSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
234a49301eSmrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
244a49301eSmrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
254a49301eSmrg *
264a49301eSmrg **************************************************************************/
274a49301eSmrg
284a49301eSmrg/* Author:
29af69d88dSmrg *    Keith Whitwell <keithw@vmware.com>
304a49301eSmrg */
314a49301eSmrg
324a49301eSmrg#include "draw/draw_context.h"
3301e04c3fSmrg#include "util/os_time.h"
344a49301eSmrg#include "pipe/p_defines.h"
354a49301eSmrg#include "util/u_memory.h"
364a49301eSmrg#include "sp_context.h"
374a49301eSmrg#include "sp_query.h"
384a49301eSmrg#include "sp_state.h"
394a49301eSmrg
404a49301eSmrgstruct softpipe_query {
413464ebd5Sriastradh   unsigned type;
429f464c52Smaya   unsigned index;
434a49301eSmrg   uint64_t start;
444a49301eSmrg   uint64_t end;
457ec681f3Smrg   struct pipe_query_data_so_statistics so[PIPE_MAX_VERTEX_STREAMS];
46af69d88dSmrg   struct pipe_query_data_pipeline_statistics stats;
474a49301eSmrg};
484a49301eSmrg
494a49301eSmrg
504a49301eSmrgstatic struct softpipe_query *softpipe_query( struct pipe_query *p )
514a49301eSmrg{
524a49301eSmrg   return (struct softpipe_query *)p;
534a49301eSmrg}
544a49301eSmrg
554a49301eSmrgstatic struct pipe_query *
564a49301eSmrgsoftpipe_create_query(struct pipe_context *pipe,
57af69d88dSmrg		      unsigned type,
58af69d88dSmrg		      unsigned index)
594a49301eSmrg{
603464ebd5Sriastradh   struct softpipe_query* sq;
613464ebd5Sriastradh
623464ebd5Sriastradh   assert(type == PIPE_QUERY_OCCLUSION_COUNTER ||
63af69d88dSmrg          type == PIPE_QUERY_OCCLUSION_PREDICATE ||
6401e04c3fSmrg          type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE ||
653464ebd5Sriastradh          type == PIPE_QUERY_TIME_ELAPSED ||
663464ebd5Sriastradh          type == PIPE_QUERY_SO_STATISTICS ||
67af69d88dSmrg          type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
6801e04c3fSmrg          type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE ||
69af69d88dSmrg          type == PIPE_QUERY_PRIMITIVES_EMITTED ||
70af69d88dSmrg          type == PIPE_QUERY_PRIMITIVES_GENERATED ||
71af69d88dSmrg          type == PIPE_QUERY_PIPELINE_STATISTICS ||
723464ebd5Sriastradh          type == PIPE_QUERY_GPU_FINISHED ||
73af69d88dSmrg          type == PIPE_QUERY_TIMESTAMP ||
743464ebd5Sriastradh          type == PIPE_QUERY_TIMESTAMP_DISJOINT);
753464ebd5Sriastradh   sq = CALLOC_STRUCT( softpipe_query );
763464ebd5Sriastradh   sq->type = type;
779f464c52Smaya   sq->index = index;
783464ebd5Sriastradh   return (struct pipe_query *)sq;
794a49301eSmrg}
804a49301eSmrg
814a49301eSmrg
824a49301eSmrgstatic void
834a49301eSmrgsoftpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
844a49301eSmrg{
854a49301eSmrg   FREE(q);
864a49301eSmrg}
874a49301eSmrg
884a49301eSmrg
897ec681f3Smrgstatic bool
904a49301eSmrgsoftpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
914a49301eSmrg{
924a49301eSmrg   struct softpipe_context *softpipe = softpipe_context( pipe );
934a49301eSmrg   struct softpipe_query *sq = softpipe_query(q);
943464ebd5Sriastradh
953464ebd5Sriastradh   switch (sq->type) {
963464ebd5Sriastradh   case PIPE_QUERY_OCCLUSION_COUNTER:
97af69d88dSmrg   case PIPE_QUERY_OCCLUSION_PREDICATE:
9801e04c3fSmrg   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
993464ebd5Sriastradh      sq->start = softpipe->occlusion_count;
1003464ebd5Sriastradh      break;
1013464ebd5Sriastradh   case PIPE_QUERY_TIME_ELAPSED:
102af69d88dSmrg      sq->start = os_time_get_nano();
1033464ebd5Sriastradh      break;
1043464ebd5Sriastradh   case PIPE_QUERY_SO_STATISTICS:
1057ec681f3Smrg      sq->so[sq->index].num_primitives_written = softpipe->so_stats[sq->index].num_primitives_written;
1067ec681f3Smrg      sq->so[sq->index].primitives_storage_needed = softpipe->so_stats[sq->index].primitives_storage_needed;
1073464ebd5Sriastradh      break;
108af69d88dSmrg   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
1097ec681f3Smrg      sq->so[sq->index].num_primitives_written = softpipe->so_stats[sq->index].num_primitives_written;
1107ec681f3Smrg      sq->so[sq->index].primitives_storage_needed = softpipe->so_stats[sq->index].primitives_storage_needed;
1117ec681f3Smrg      break;
11201e04c3fSmrg   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
1137ec681f3Smrg      for (unsigned i = 0; i < PIPE_MAX_VERTEX_STREAMS; i++) {
1147ec681f3Smrg         sq->so[i].num_primitives_written = softpipe->so_stats[i].num_primitives_written;
1157ec681f3Smrg         sq->so[i].primitives_storage_needed = softpipe->so_stats[i].primitives_storage_needed;
1167ec681f3Smrg      }
117af69d88dSmrg      break;
118af69d88dSmrg   case PIPE_QUERY_PRIMITIVES_EMITTED:
1197ec681f3Smrg      sq->so[sq->index].num_primitives_written = softpipe->so_stats[sq->index].num_primitives_written;
120af69d88dSmrg      break;
121af69d88dSmrg   case PIPE_QUERY_PRIMITIVES_GENERATED:
1227ec681f3Smrg      sq->so[sq->index].primitives_storage_needed = softpipe->so_stats[sq->index].primitives_storage_needed;
1233464ebd5Sriastradh      break;
124af69d88dSmrg   case PIPE_QUERY_TIMESTAMP:
125af69d88dSmrg   case PIPE_QUERY_GPU_FINISHED:
1263464ebd5Sriastradh   case PIPE_QUERY_TIMESTAMP_DISJOINT:
127af69d88dSmrg      break;
128af69d88dSmrg   case PIPE_QUERY_PIPELINE_STATISTICS:
129af69d88dSmrg      /* reset our cache */
130af69d88dSmrg      if (softpipe->active_statistics_queries == 0) {
131af69d88dSmrg         memset(&softpipe->pipeline_statistics, 0,
132af69d88dSmrg                sizeof(softpipe->pipeline_statistics));
133af69d88dSmrg      }
134af69d88dSmrg      memcpy(&sq->stats, &softpipe->pipeline_statistics,
135af69d88dSmrg             sizeof(sq->stats));
136af69d88dSmrg      softpipe->active_statistics_queries++;
137af69d88dSmrg      break;
1383464ebd5Sriastradh   default:
1393464ebd5Sriastradh      assert(0);
1403464ebd5Sriastradh      break;
1413464ebd5Sriastradh   }
1424a49301eSmrg   softpipe->active_query_count++;
1434a49301eSmrg   softpipe->dirty |= SP_NEW_QUERY;
14401e04c3fSmrg   return true;
1454a49301eSmrg}
1464a49301eSmrg
1474a49301eSmrg
14801e04c3fSmrgstatic bool
1494a49301eSmrgsoftpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
1504a49301eSmrg{
1514a49301eSmrg   struct softpipe_context *softpipe = softpipe_context( pipe );
1524a49301eSmrg   struct softpipe_query *sq = softpipe_query(q);
1534a49301eSmrg
1544a49301eSmrg   softpipe->active_query_count--;
1553464ebd5Sriastradh   switch (sq->type) {
1563464ebd5Sriastradh   case PIPE_QUERY_OCCLUSION_COUNTER:
157af69d88dSmrg   case PIPE_QUERY_OCCLUSION_PREDICATE:
15801e04c3fSmrg   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
1593464ebd5Sriastradh      sq->end = softpipe->occlusion_count;
1603464ebd5Sriastradh      break;
161af69d88dSmrg   case PIPE_QUERY_TIMESTAMP:
162af69d88dSmrg      sq->start = 0;
1637ec681f3Smrg      FALLTHROUGH;
1643464ebd5Sriastradh   case PIPE_QUERY_TIME_ELAPSED:
165af69d88dSmrg      sq->end = os_time_get_nano();
166af69d88dSmrg      break;
167af69d88dSmrg   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
1687ec681f3Smrg      sq->so[sq->index].num_primitives_written =
1697ec681f3Smrg         softpipe->so_stats[sq->index].num_primitives_written - sq->so[sq->index].num_primitives_written;
1707ec681f3Smrg      sq->so[sq->index].primitives_storage_needed =
1717ec681f3Smrg         softpipe->so_stats[sq->index].primitives_storage_needed - sq->so[sq->index].primitives_storage_needed;
1727ec681f3Smrg      sq->end = sq->so[sq->index].primitives_storage_needed > sq->so[sq->index].num_primitives_written;
1737ec681f3Smrg      break;
17401e04c3fSmrg   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
1757ec681f3Smrg      sq->end = 0;
1767ec681f3Smrg      for (unsigned i = 0; i < PIPE_MAX_VERTEX_STREAMS; i++) {
1777ec681f3Smrg         sq->so[i].num_primitives_written =
1787ec681f3Smrg            softpipe->so_stats[i].num_primitives_written - sq->so[i].num_primitives_written;
1797ec681f3Smrg         sq->so[i].primitives_storage_needed =
1807ec681f3Smrg            softpipe->so_stats[i].primitives_storage_needed - sq->so[i].primitives_storage_needed;
1817ec681f3Smrg         sq->end |= sq->so[i].primitives_storage_needed > sq->so[i].num_primitives_written;
1827ec681f3Smrg      }
1833464ebd5Sriastradh      break;
1843464ebd5Sriastradh   case PIPE_QUERY_SO_STATISTICS:
1857ec681f3Smrg      sq->so[sq->index].num_primitives_written =
1867ec681f3Smrg         softpipe->so_stats[sq->index].num_primitives_written - sq->so[sq->index].num_primitives_written;
1877ec681f3Smrg      sq->so[sq->index].primitives_storage_needed =
1887ec681f3Smrg         softpipe->so_stats[sq->index].primitives_storage_needed - sq->so[sq->index].primitives_storage_needed;
189af69d88dSmrg      break;
190af69d88dSmrg   case PIPE_QUERY_PRIMITIVES_EMITTED:
1917ec681f3Smrg      sq->so[sq->index].num_primitives_written =
1927ec681f3Smrg         softpipe->so_stats[sq->index].num_primitives_written - sq->so[sq->index].num_primitives_written;
193af69d88dSmrg      break;
194af69d88dSmrg   case PIPE_QUERY_PRIMITIVES_GENERATED:
1957ec681f3Smrg      sq->so[sq->index].primitives_storage_needed =
1967ec681f3Smrg         softpipe->so_stats[sq->index].primitives_storage_needed - sq->so[sq->index].primitives_storage_needed;
1973464ebd5Sriastradh      break;
1983464ebd5Sriastradh   case PIPE_QUERY_GPU_FINISHED:
1993464ebd5Sriastradh   case PIPE_QUERY_TIMESTAMP_DISJOINT:
2003464ebd5Sriastradh      break;
201af69d88dSmrg   case PIPE_QUERY_PIPELINE_STATISTICS:
202af69d88dSmrg      sq->stats.ia_vertices =
203af69d88dSmrg         softpipe->pipeline_statistics.ia_vertices - sq->stats.ia_vertices;
204af69d88dSmrg      sq->stats.ia_primitives =
205af69d88dSmrg         softpipe->pipeline_statistics.ia_primitives - sq->stats.ia_primitives;
206af69d88dSmrg      sq->stats.vs_invocations =
207af69d88dSmrg         softpipe->pipeline_statistics.vs_invocations - sq->stats.vs_invocations;
208af69d88dSmrg      sq->stats.gs_invocations =
209af69d88dSmrg         softpipe->pipeline_statistics.gs_invocations - sq->stats.gs_invocations;
210af69d88dSmrg      sq->stats.gs_primitives =
211af69d88dSmrg         softpipe->pipeline_statistics.gs_primitives - sq->stats.gs_primitives;
212af69d88dSmrg      sq->stats.c_invocations =
213af69d88dSmrg         softpipe->pipeline_statistics.c_invocations - sq->stats.c_invocations;
214af69d88dSmrg      sq->stats.c_primitives =
215af69d88dSmrg         softpipe->pipeline_statistics.c_primitives - sq->stats.c_primitives;
216af69d88dSmrg      sq->stats.ps_invocations =
217af69d88dSmrg         softpipe->pipeline_statistics.ps_invocations - sq->stats.ps_invocations;
2187ec681f3Smrg      sq->stats.cs_invocations =
2197ec681f3Smrg         softpipe->pipeline_statistics.cs_invocations - sq->stats.cs_invocations;
220af69d88dSmrg
221af69d88dSmrg      softpipe->active_statistics_queries--;
222af69d88dSmrg      break;
2233464ebd5Sriastradh   default:
2243464ebd5Sriastradh      assert(0);
2253464ebd5Sriastradh      break;
2263464ebd5Sriastradh   }
2274a49301eSmrg   softpipe->dirty |= SP_NEW_QUERY;
22801e04c3fSmrg   return true;
2294a49301eSmrg}
2304a49301eSmrg
2314a49301eSmrg
2327ec681f3Smrgstatic bool
2334a49301eSmrgsoftpipe_get_query_result(struct pipe_context *pipe,
234af69d88dSmrg                          struct pipe_query *q,
2357ec681f3Smrg                          bool wait,
236af69d88dSmrg                          union pipe_query_result *vresult)
2374a49301eSmrg{
2384a49301eSmrg   struct softpipe_query *sq = softpipe_query(q);
2393464ebd5Sriastradh   uint64_t *result = (uint64_t*)vresult;
2403464ebd5Sriastradh
2413464ebd5Sriastradh   switch (sq->type) {
242af69d88dSmrg   case PIPE_QUERY_SO_STATISTICS: {
243af69d88dSmrg      struct pipe_query_data_so_statistics *stats =
244af69d88dSmrg         (struct pipe_query_data_so_statistics *)vresult;
2457ec681f3Smrg      stats->num_primitives_written = sq->so[sq->index].num_primitives_written;
2467ec681f3Smrg      stats->primitives_storage_needed = sq->so[sq->index].primitives_storage_needed;
247af69d88dSmrg   }
248af69d88dSmrg      break;
249af69d88dSmrg   case PIPE_QUERY_PIPELINE_STATISTICS:
250af69d88dSmrg      memcpy(vresult, &sq->stats,
25101e04c3fSmrg             sizeof(struct pipe_query_data_pipeline_statistics));
2523464ebd5Sriastradh      break;
2533464ebd5Sriastradh   case PIPE_QUERY_GPU_FINISHED:
2547ec681f3Smrg      vresult->b = true;
255af69d88dSmrg      break;
256af69d88dSmrg   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
25701e04c3fSmrg   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
258af69d88dSmrg      vresult->b = sq->end != 0;
2593464ebd5Sriastradh      break;
2603464ebd5Sriastradh   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
261af69d88dSmrg      struct pipe_query_data_timestamp_disjoint *td =
262af69d88dSmrg          (struct pipe_query_data_timestamp_disjoint *)vresult;
263af69d88dSmrg      /* os_get_time_nano return nanoseconds */
264af69d88dSmrg      td->frequency = UINT64_C(1000000000);
2657ec681f3Smrg      td->disjoint = false;
2663464ebd5Sriastradh   }
2673464ebd5Sriastradh      break;
268af69d88dSmrg   case PIPE_QUERY_PRIMITIVES_EMITTED:
2697ec681f3Smrg      *result = sq->so[sq->index].num_primitives_written;
270af69d88dSmrg      break;
271af69d88dSmrg   case PIPE_QUERY_PRIMITIVES_GENERATED:
2727ec681f3Smrg      *result = sq->so[sq->index].primitives_storage_needed;
273af69d88dSmrg      break;
274af69d88dSmrg   case PIPE_QUERY_OCCLUSION_PREDICATE:
27501e04c3fSmrg   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
276af69d88dSmrg      vresult->b = sq->end - sq->start != 0;
277af69d88dSmrg      break;
2783464ebd5Sriastradh   default:
2793464ebd5Sriastradh      *result = sq->end - sq->start;
2803464ebd5Sriastradh      break;
2813464ebd5Sriastradh   }
2827ec681f3Smrg   return true;
2834a49301eSmrg}
2844a49301eSmrg
2857ec681f3Smrgstatic bool
2867ec681f3Smrgis_result_nonzero(struct pipe_query *q,
2877ec681f3Smrg                  union pipe_query_result *vresult)
2887ec681f3Smrg{
2897ec681f3Smrg   struct softpipe_query *sq = softpipe_query(q);
2907ec681f3Smrg
2917ec681f3Smrg   switch (sq->type) {
2927ec681f3Smrg   case PIPE_QUERY_TIMESTAMP_DISJOINT:
2937ec681f3Smrg   case PIPE_QUERY_SO_STATISTICS:
2947ec681f3Smrg   case PIPE_QUERY_PIPELINE_STATISTICS:
2957ec681f3Smrg      unreachable("unpossible");
2967ec681f3Smrg      break;
2977ec681f3Smrg   case PIPE_QUERY_GPU_FINISHED:
2987ec681f3Smrg   case PIPE_QUERY_OCCLUSION_PREDICATE:
2997ec681f3Smrg   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
3007ec681f3Smrg   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
3017ec681f3Smrg   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
3027ec681f3Smrg      return vresult->b;
3037ec681f3Smrg   default:
3047ec681f3Smrg      return !!vresult->u64;
3057ec681f3Smrg   }
3067ec681f3Smrg   return false;
3077ec681f3Smrg}
3084a49301eSmrg
309cdc920a0Smrg/**
310cdc920a0Smrg * Called by rendering function to check rendering is conditional.
311cdc920a0Smrg * \return TRUE if we should render, FALSE if we should skip rendering
312cdc920a0Smrg */
313cdc920a0Smrgboolean
314cdc920a0Smrgsoftpipe_check_render_cond(struct softpipe_context *sp)
315cdc920a0Smrg{
316cdc920a0Smrg   struct pipe_context *pipe = &sp->pipe;
317cdc920a0Smrg   boolean b, wait;
3187ec681f3Smrg   union pipe_query_result result;
3197ec681f3Smrg   memset(&result, 0, sizeof(union pipe_query_result));
320cdc920a0Smrg
321cdc920a0Smrg   if (!sp->render_cond_query) {
322cdc920a0Smrg      return TRUE;  /* no query predicate, draw normally */
323cdc920a0Smrg   }
324cdc920a0Smrg
325cdc920a0Smrg   wait = (sp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
326cdc920a0Smrg           sp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
327cdc920a0Smrg
328af69d88dSmrg   b = pipe->get_query_result(pipe, sp->render_cond_query, wait,
3297ec681f3Smrg                              &result);
330cdc920a0Smrg   if (b)
3317ec681f3Smrg      return !is_result_nonzero(sp->render_cond_query, &result) == sp->render_cond_cond;
332cdc920a0Smrg   else
333cdc920a0Smrg      return TRUE;
334cdc920a0Smrg}
335cdc920a0Smrg
336cdc920a0Smrg
33701e04c3fSmrgstatic void
3387ec681f3Smrgsoftpipe_set_active_query_state(struct pipe_context *pipe, bool enable)
33901e04c3fSmrg{
34001e04c3fSmrg}
34101e04c3fSmrg
34201e04c3fSmrg
3434a49301eSmrgvoid softpipe_init_query_funcs(struct softpipe_context *softpipe )
3444a49301eSmrg{
3454a49301eSmrg   softpipe->pipe.create_query = softpipe_create_query;
3464a49301eSmrg   softpipe->pipe.destroy_query = softpipe_destroy_query;
3474a49301eSmrg   softpipe->pipe.begin_query = softpipe_begin_query;
3484a49301eSmrg   softpipe->pipe.end_query = softpipe_end_query;
3494a49301eSmrg   softpipe->pipe.get_query_result = softpipe_get_query_result;
35001e04c3fSmrg   softpipe->pipe.set_active_query_state = softpipe_set_active_query_state;
3514a49301eSmrg}
3524a49301eSmrg
3534a49301eSmrg
354