sp_query.c revision 01e04c3f
1/**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/* Author:
29 *    Keith Whitwell <keithw@vmware.com>
30 */
31
32#include "draw/draw_context.h"
33#include "util/os_time.h"
34#include "pipe/p_defines.h"
35#include "util/u_memory.h"
36#include "sp_context.h"
37#include "sp_query.h"
38#include "sp_state.h"
39
40struct softpipe_query {
41   unsigned type;
42   uint64_t start;
43   uint64_t end;
44   struct pipe_query_data_so_statistics so;
45   struct pipe_query_data_pipeline_statistics stats;
46};
47
48
49static struct softpipe_query *softpipe_query( struct pipe_query *p )
50{
51   return (struct softpipe_query *)p;
52}
53
54static struct pipe_query *
55softpipe_create_query(struct pipe_context *pipe,
56		      unsigned type,
57		      unsigned index)
58{
59   struct softpipe_query* sq;
60
61   assert(type == PIPE_QUERY_OCCLUSION_COUNTER ||
62          type == PIPE_QUERY_OCCLUSION_PREDICATE ||
63          type == PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE ||
64          type == PIPE_QUERY_TIME_ELAPSED ||
65          type == PIPE_QUERY_SO_STATISTICS ||
66          type == PIPE_QUERY_SO_OVERFLOW_PREDICATE ||
67          type == PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE ||
68          type == PIPE_QUERY_PRIMITIVES_EMITTED ||
69          type == PIPE_QUERY_PRIMITIVES_GENERATED ||
70          type == PIPE_QUERY_PIPELINE_STATISTICS ||
71          type == PIPE_QUERY_GPU_FINISHED ||
72          type == PIPE_QUERY_TIMESTAMP ||
73          type == PIPE_QUERY_TIMESTAMP_DISJOINT);
74   sq = CALLOC_STRUCT( softpipe_query );
75   sq->type = type;
76
77   return (struct pipe_query *)sq;
78}
79
80
81static void
82softpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
83{
84   FREE(q);
85}
86
87
88static boolean
89softpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
90{
91   struct softpipe_context *softpipe = softpipe_context( pipe );
92   struct softpipe_query *sq = softpipe_query(q);
93
94   switch (sq->type) {
95   case PIPE_QUERY_OCCLUSION_COUNTER:
96   case PIPE_QUERY_OCCLUSION_PREDICATE:
97   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
98      sq->start = softpipe->occlusion_count;
99      break;
100   case PIPE_QUERY_TIME_ELAPSED:
101      sq->start = os_time_get_nano();
102      break;
103   case PIPE_QUERY_SO_STATISTICS:
104      sq->so.num_primitives_written = softpipe->so_stats.num_primitives_written;
105      sq->so.primitives_storage_needed = softpipe->so_stats.primitives_storage_needed;
106      break;
107   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
108   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
109      sq->so.num_primitives_written = softpipe->so_stats.num_primitives_written;
110      sq->so.primitives_storage_needed = softpipe->so_stats.primitives_storage_needed;
111      break;
112   case PIPE_QUERY_PRIMITIVES_EMITTED:
113      sq->so.num_primitives_written = softpipe->so_stats.num_primitives_written;
114      break;
115   case PIPE_QUERY_PRIMITIVES_GENERATED:
116      sq->so.primitives_storage_needed = softpipe->so_stats.primitives_storage_needed;
117      break;
118   case PIPE_QUERY_TIMESTAMP:
119   case PIPE_QUERY_GPU_FINISHED:
120   case PIPE_QUERY_TIMESTAMP_DISJOINT:
121      break;
122   case PIPE_QUERY_PIPELINE_STATISTICS:
123      /* reset our cache */
124      if (softpipe->active_statistics_queries == 0) {
125         memset(&softpipe->pipeline_statistics, 0,
126                sizeof(softpipe->pipeline_statistics));
127      }
128      memcpy(&sq->stats, &softpipe->pipeline_statistics,
129             sizeof(sq->stats));
130      softpipe->active_statistics_queries++;
131      break;
132   default:
133      assert(0);
134      break;
135   }
136   softpipe->active_query_count++;
137   softpipe->dirty |= SP_NEW_QUERY;
138   return true;
139}
140
141
142static bool
143softpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
144{
145   struct softpipe_context *softpipe = softpipe_context( pipe );
146   struct softpipe_query *sq = softpipe_query(q);
147
148   softpipe->active_query_count--;
149   switch (sq->type) {
150   case PIPE_QUERY_OCCLUSION_COUNTER:
151   case PIPE_QUERY_OCCLUSION_PREDICATE:
152   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
153      sq->end = softpipe->occlusion_count;
154      break;
155   case PIPE_QUERY_TIMESTAMP:
156      sq->start = 0;
157      /* fall through */
158   case PIPE_QUERY_TIME_ELAPSED:
159      sq->end = os_time_get_nano();
160      break;
161   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
162   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
163      sq->so.num_primitives_written =
164         softpipe->so_stats.num_primitives_written - sq->so.num_primitives_written;
165      sq->so.primitives_storage_needed =
166         softpipe->so_stats.primitives_storage_needed - sq->so.primitives_storage_needed;
167      sq->end = sq->so.primitives_storage_needed > sq->so.num_primitives_written;
168      break;
169   case PIPE_QUERY_SO_STATISTICS:
170      sq->so.num_primitives_written =
171         softpipe->so_stats.num_primitives_written - sq->so.num_primitives_written;
172      sq->so.primitives_storage_needed =
173         softpipe->so_stats.primitives_storage_needed - sq->so.primitives_storage_needed;
174      break;
175   case PIPE_QUERY_PRIMITIVES_EMITTED:
176      sq->so.num_primitives_written =
177         softpipe->so_stats.num_primitives_written - sq->so.num_primitives_written;
178      break;
179   case PIPE_QUERY_PRIMITIVES_GENERATED:
180      sq->so.primitives_storage_needed =
181         softpipe->so_stats.primitives_storage_needed - sq->so.primitives_storage_needed;
182      break;
183   case PIPE_QUERY_GPU_FINISHED:
184   case PIPE_QUERY_TIMESTAMP_DISJOINT:
185      break;
186   case PIPE_QUERY_PIPELINE_STATISTICS:
187      sq->stats.ia_vertices =
188         softpipe->pipeline_statistics.ia_vertices - sq->stats.ia_vertices;
189      sq->stats.ia_primitives =
190         softpipe->pipeline_statistics.ia_primitives - sq->stats.ia_primitives;
191      sq->stats.vs_invocations =
192         softpipe->pipeline_statistics.vs_invocations - sq->stats.vs_invocations;
193      sq->stats.gs_invocations =
194         softpipe->pipeline_statistics.gs_invocations - sq->stats.gs_invocations;
195      sq->stats.gs_primitives =
196         softpipe->pipeline_statistics.gs_primitives - sq->stats.gs_primitives;
197      sq->stats.c_invocations =
198         softpipe->pipeline_statistics.c_invocations - sq->stats.c_invocations;
199      sq->stats.c_primitives =
200         softpipe->pipeline_statistics.c_primitives - sq->stats.c_primitives;
201      sq->stats.ps_invocations =
202         softpipe->pipeline_statistics.ps_invocations - sq->stats.ps_invocations;
203
204      softpipe->active_statistics_queries--;
205      break;
206   default:
207      assert(0);
208      break;
209   }
210   softpipe->dirty |= SP_NEW_QUERY;
211   return true;
212}
213
214
215static boolean
216softpipe_get_query_result(struct pipe_context *pipe,
217                          struct pipe_query *q,
218                          boolean wait,
219                          union pipe_query_result *vresult)
220{
221   struct softpipe_query *sq = softpipe_query(q);
222   uint64_t *result = (uint64_t*)vresult;
223
224   switch (sq->type) {
225   case PIPE_QUERY_SO_STATISTICS: {
226      struct pipe_query_data_so_statistics *stats =
227         (struct pipe_query_data_so_statistics *)vresult;
228      stats->num_primitives_written = sq->so.num_primitives_written;
229      stats->primitives_storage_needed = sq->so.primitives_storage_needed;
230   }
231      break;
232   case PIPE_QUERY_PIPELINE_STATISTICS:
233      memcpy(vresult, &sq->stats,
234             sizeof(struct pipe_query_data_pipeline_statistics));
235      break;
236   case PIPE_QUERY_GPU_FINISHED:
237      vresult->b = TRUE;
238      break;
239   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
240   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
241      vresult->b = sq->end != 0;
242      break;
243   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
244      struct pipe_query_data_timestamp_disjoint *td =
245          (struct pipe_query_data_timestamp_disjoint *)vresult;
246      /* os_get_time_nano return nanoseconds */
247      td->frequency = UINT64_C(1000000000);
248      td->disjoint = FALSE;
249   }
250      break;
251   case PIPE_QUERY_PRIMITIVES_EMITTED:
252      *result = sq->so.num_primitives_written;
253      break;
254   case PIPE_QUERY_PRIMITIVES_GENERATED:
255      *result = sq->so.primitives_storage_needed;
256      break;
257   case PIPE_QUERY_OCCLUSION_PREDICATE:
258   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
259      vresult->b = sq->end - sq->start != 0;
260      break;
261   default:
262      *result = sq->end - sq->start;
263      break;
264   }
265   return TRUE;
266}
267
268
269/**
270 * Called by rendering function to check rendering is conditional.
271 * \return TRUE if we should render, FALSE if we should skip rendering
272 */
273boolean
274softpipe_check_render_cond(struct softpipe_context *sp)
275{
276   struct pipe_context *pipe = &sp->pipe;
277   boolean b, wait;
278   uint64_t result;
279
280   if (!sp->render_cond_query) {
281      return TRUE;  /* no query predicate, draw normally */
282   }
283
284   wait = (sp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
285           sp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
286
287   b = pipe->get_query_result(pipe, sp->render_cond_query, wait,
288                              (void*)&result);
289   if (b)
290      return (!result) == sp->render_cond_cond;
291   else
292      return TRUE;
293}
294
295
296static void
297softpipe_set_active_query_state(struct pipe_context *pipe, boolean enable)
298{
299}
300
301
302void softpipe_init_query_funcs(struct softpipe_context *softpipe )
303{
304   softpipe->pipe.create_query = softpipe_create_query;
305   softpipe->pipe.destroy_query = softpipe_destroy_query;
306   softpipe->pipe.begin_query = softpipe_begin_query;
307   softpipe->pipe.end_query = softpipe_end_query;
308   softpipe->pipe.get_query_result = softpipe_get_query_result;
309   softpipe->pipe.set_active_query_state = softpipe_set_active_query_state;
310}
311
312
313