1/**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 TUNGSTEN GRAPHICS 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 <keith@tungstengraphics.com>
30 */
31
32#include "draw/draw_context.h"
33#include "os/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   unsigned num_primitives_generated;
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{
58   struct softpipe_query* sq;
59
60   assert(type == PIPE_QUERY_OCCLUSION_COUNTER ||
61          type == PIPE_QUERY_TIME_ELAPSED ||
62          type == PIPE_QUERY_SO_STATISTICS ||
63          type == PIPE_QUERY_PRIMITIVES_EMITTED ||
64          type == PIPE_QUERY_PRIMITIVES_GENERATED ||
65          type == PIPE_QUERY_GPU_FINISHED ||
66          type == PIPE_QUERY_TIMESTAMP ||
67          type == PIPE_QUERY_TIMESTAMP_DISJOINT);
68   sq = CALLOC_STRUCT( softpipe_query );
69   sq->type = type;
70
71   return (struct pipe_query *)sq;
72}
73
74
75static void
76softpipe_destroy_query(struct pipe_context *pipe, struct pipe_query *q)
77{
78   FREE(q);
79}
80
81
82static void
83softpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
84{
85   struct softpipe_context *softpipe = softpipe_context( pipe );
86   struct softpipe_query *sq = softpipe_query(q);
87
88   switch (sq->type) {
89   case PIPE_QUERY_OCCLUSION_COUNTER:
90      sq->start = softpipe->occlusion_count;
91      break;
92   case PIPE_QUERY_TIMESTAMP_DISJOINT:
93   case PIPE_QUERY_TIME_ELAPSED:
94      sq->start = 1000*os_time_get();
95      break;
96   case PIPE_QUERY_SO_STATISTICS:
97      sq->so.primitives_storage_needed = 0;
98   case PIPE_QUERY_PRIMITIVES_EMITTED:
99      sq->so.num_primitives_written = 0;
100      softpipe->so_stats.num_primitives_written = 0;
101      break;
102   case PIPE_QUERY_PRIMITIVES_GENERATED:
103      sq->num_primitives_generated = 0;
104      softpipe->num_primitives_generated = 0;
105      break;
106   case PIPE_QUERY_TIMESTAMP:
107   case PIPE_QUERY_GPU_FINISHED:
108      break;
109   default:
110      assert(0);
111      break;
112   }
113   softpipe->active_query_count++;
114   softpipe->dirty |= SP_NEW_QUERY;
115}
116
117
118static void
119softpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
120{
121   struct softpipe_context *softpipe = softpipe_context( pipe );
122   struct softpipe_query *sq = softpipe_query(q);
123
124   softpipe->active_query_count--;
125   switch (sq->type) {
126   case PIPE_QUERY_OCCLUSION_COUNTER:
127      sq->end = softpipe->occlusion_count;
128      break;
129   case PIPE_QUERY_TIMESTAMP:
130      sq->start = 0;
131      /* fall through */
132   case PIPE_QUERY_TIMESTAMP_DISJOINT:
133   case PIPE_QUERY_TIME_ELAPSED:
134      sq->end = 1000*os_time_get();
135      break;
136   case PIPE_QUERY_SO_STATISTICS:
137      sq->so.primitives_storage_needed =
138         softpipe->so_stats.primitives_storage_needed;
139   case PIPE_QUERY_PRIMITIVES_EMITTED:
140      sq->so.num_primitives_written =
141         softpipe->so_stats.num_primitives_written;
142      break;
143   case PIPE_QUERY_PRIMITIVES_GENERATED:
144      sq->num_primitives_generated = softpipe->num_primitives_generated;
145      break;
146   case PIPE_QUERY_GPU_FINISHED:
147      break;
148   default:
149      assert(0);
150      break;
151   }
152   softpipe->dirty |= SP_NEW_QUERY;
153}
154
155
156static boolean
157softpipe_get_query_result(struct pipe_context *pipe,
158			  struct pipe_query *q,
159			  boolean wait,
160			  union pipe_query_result *vresult)
161{
162   struct softpipe_query *sq = softpipe_query(q);
163   uint64_t *result = (uint64_t*)vresult;
164
165   switch (sq->type) {
166   case PIPE_QUERY_SO_STATISTICS:
167      memcpy(vresult, &sq->so,
168             sizeof(struct pipe_query_data_so_statistics));
169      break;
170   case PIPE_QUERY_GPU_FINISHED:
171      *result = TRUE;
172      break;
173   case PIPE_QUERY_TIMESTAMP_DISJOINT: {
174      struct pipe_query_data_timestamp_disjoint td;
175      /*os_get_time is in microseconds*/
176      td.frequency = 1000000;
177      td.disjoint = sq->end != sq->start;
178      memcpy(vresult, &td,
179             sizeof(struct pipe_query_data_timestamp_disjoint));
180   }
181      break;
182   case PIPE_QUERY_PRIMITIVES_EMITTED:
183      *result = sq->so.num_primitives_written;
184      break;
185   case PIPE_QUERY_PRIMITIVES_GENERATED:
186      *result = sq->num_primitives_generated;
187      break;
188   default:
189      *result = sq->end - sq->start;
190      break;
191   }
192   return TRUE;
193}
194
195
196/**
197 * Called by rendering function to check rendering is conditional.
198 * \return TRUE if we should render, FALSE if we should skip rendering
199 */
200boolean
201softpipe_check_render_cond(struct softpipe_context *sp)
202{
203   struct pipe_context *pipe = &sp->pipe;
204   boolean b, wait;
205   uint64_t result;
206
207   if (!sp->render_cond_query) {
208      return TRUE;  /* no query predicate, draw normally */
209   }
210
211   wait = (sp->render_cond_mode == PIPE_RENDER_COND_WAIT ||
212           sp->render_cond_mode == PIPE_RENDER_COND_BY_REGION_WAIT);
213
214   b = pipe->get_query_result(pipe, sp->render_cond_query, wait,
215                              (void*)&result);
216   if (b)
217      return result > 0;
218   else
219      return TRUE;
220}
221
222
223void softpipe_init_query_funcs(struct softpipe_context *softpipe )
224{
225   softpipe->pipe.create_query = softpipe_create_query;
226   softpipe->pipe.destroy_query = softpipe_destroy_query;
227   softpipe->pipe.begin_query = softpipe_begin_query;
228   softpipe->pipe.end_query = softpipe_end_query;
229   softpipe->pipe.get_query_result = softpipe_get_query_result;
230}
231
232
233