st/mesa: enable OES_texture_buffer when all components available
[mesa.git] / src / mesa / state_tracker / st_cb_queryobj.c
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
29 /**
30 * glBegin/EndQuery interface to pipe
31 *
32 * \author Brian Paul
33 */
34
35
36 #include "main/imports.h"
37 #include "main/context.h"
38
39 #include "pipe/p_context.h"
40 #include "pipe/p_defines.h"
41 #include "pipe/p_screen.h"
42 #include "util/u_inlines.h"
43 #include "st_context.h"
44 #include "st_cb_queryobj.h"
45 #include "st_cb_bitmap.h"
46 #include "st_cb_bufferobjects.h"
47
48
49 static struct gl_query_object *
50 st_NewQueryObject(struct gl_context *ctx, GLuint id)
51 {
52 struct st_query_object *stq = ST_CALLOC_STRUCT(st_query_object);
53 if (stq) {
54 stq->base.Id = id;
55 stq->base.Ready = GL_TRUE;
56 stq->pq = NULL;
57 stq->type = PIPE_QUERY_TYPES; /* an invalid value */
58 return &stq->base;
59 }
60 return NULL;
61 }
62
63
64
65 static void
66 st_DeleteQuery(struct gl_context *ctx, struct gl_query_object *q)
67 {
68 struct pipe_context *pipe = st_context(ctx)->pipe;
69 struct st_query_object *stq = st_query_object(q);
70
71 if (stq->pq) {
72 pipe->destroy_query(pipe, stq->pq);
73 stq->pq = NULL;
74 }
75
76 if (stq->pq_begin) {
77 pipe->destroy_query(pipe, stq->pq_begin);
78 stq->pq_begin = NULL;
79 }
80
81 free(stq);
82 }
83
84
85 static void
86 st_BeginQuery(struct gl_context *ctx, struct gl_query_object *q)
87 {
88 struct st_context *st = st_context(ctx);
89 struct pipe_context *pipe = st->pipe;
90 struct st_query_object *stq = st_query_object(q);
91 unsigned type;
92
93 st_flush_bitmap_cache(st_context(ctx));
94
95 /* convert GL query type to Gallium query type */
96 switch (q->Target) {
97 case GL_ANY_SAMPLES_PASSED:
98 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
99 type = PIPE_QUERY_OCCLUSION_PREDICATE;
100 break;
101 case GL_SAMPLES_PASSED_ARB:
102 type = PIPE_QUERY_OCCLUSION_COUNTER;
103 break;
104 case GL_PRIMITIVES_GENERATED:
105 type = PIPE_QUERY_PRIMITIVES_GENERATED;
106 break;
107 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
108 type = PIPE_QUERY_PRIMITIVES_EMITTED;
109 break;
110 case GL_TIME_ELAPSED:
111 if (st->has_time_elapsed)
112 type = PIPE_QUERY_TIME_ELAPSED;
113 else
114 type = PIPE_QUERY_TIMESTAMP;
115 break;
116 case GL_VERTICES_SUBMITTED_ARB:
117 case GL_PRIMITIVES_SUBMITTED_ARB:
118 case GL_VERTEX_SHADER_INVOCATIONS_ARB:
119 case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
120 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
121 case GL_GEOMETRY_SHADER_INVOCATIONS:
122 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
123 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
124 case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
125 case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
126 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
127 type = PIPE_QUERY_PIPELINE_STATISTICS;
128 break;
129 default:
130 assert(0 && "unexpected query target in st_BeginQuery()");
131 return;
132 }
133
134 if (stq->type != type) {
135 /* free old query of different type */
136 if (stq->pq) {
137 pipe->destroy_query(pipe, stq->pq);
138 stq->pq = NULL;
139 }
140 if (stq->pq_begin) {
141 pipe->destroy_query(pipe, stq->pq_begin);
142 stq->pq_begin = NULL;
143 }
144 stq->type = PIPE_QUERY_TYPES; /* an invalid value */
145 }
146
147 if (q->Target == GL_TIME_ELAPSED &&
148 type == PIPE_QUERY_TIMESTAMP) {
149 /* Determine time elapsed by emitting two timestamp queries. */
150 if (!stq->pq_begin) {
151 stq->pq_begin = pipe->create_query(pipe, type, 0);
152 stq->type = type;
153 }
154 pipe->end_query(pipe, stq->pq_begin);
155 } else {
156 if (!stq->pq) {
157 stq->pq = pipe->create_query(pipe, type, q->Stream);
158 stq->type = type;
159 }
160 if (stq->pq) {
161 pipe->begin_query(pipe, stq->pq);
162 }
163 else {
164 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery");
165 return;
166 }
167 }
168 assert(stq->type == type);
169 }
170
171
172 static void
173 st_EndQuery(struct gl_context *ctx, struct gl_query_object *q)
174 {
175 struct pipe_context *pipe = st_context(ctx)->pipe;
176 struct st_query_object *stq = st_query_object(q);
177
178 st_flush_bitmap_cache(st_context(ctx));
179
180 if ((q->Target == GL_TIMESTAMP ||
181 q->Target == GL_TIME_ELAPSED) &&
182 !stq->pq) {
183 stq->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP, 0);
184 stq->type = PIPE_QUERY_TIMESTAMP;
185 }
186
187 if (stq->pq)
188 pipe->end_query(pipe, stq->pq);
189 }
190
191
192 static boolean
193 get_query_result(struct pipe_context *pipe,
194 struct st_query_object *stq,
195 boolean wait)
196 {
197 union pipe_query_result data;
198
199 if (!stq->pq) {
200 /* Only needed in case we failed to allocate the gallium query earlier.
201 * Return TRUE so we don't spin on this forever.
202 */
203 return TRUE;
204 }
205
206 if (!pipe->get_query_result(pipe, stq->pq, wait, &data))
207 return FALSE;
208
209 switch (stq->base.Target) {
210 case GL_VERTICES_SUBMITTED_ARB:
211 stq->base.Result = data.pipeline_statistics.ia_vertices;
212 break;
213 case GL_PRIMITIVES_SUBMITTED_ARB:
214 stq->base.Result = data.pipeline_statistics.ia_primitives;
215 break;
216 case GL_VERTEX_SHADER_INVOCATIONS_ARB:
217 stq->base.Result = data.pipeline_statistics.vs_invocations;
218 break;
219 case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
220 stq->base.Result = data.pipeline_statistics.hs_invocations;
221 break;
222 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
223 stq->base.Result = data.pipeline_statistics.ds_invocations;
224 break;
225 case GL_GEOMETRY_SHADER_INVOCATIONS:
226 stq->base.Result = data.pipeline_statistics.gs_invocations;
227 break;
228 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
229 stq->base.Result = data.pipeline_statistics.gs_primitives;
230 break;
231 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
232 stq->base.Result = data.pipeline_statistics.ps_invocations;
233 break;
234 case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
235 stq->base.Result = data.pipeline_statistics.cs_invocations;
236 break;
237 case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
238 stq->base.Result = data.pipeline_statistics.c_invocations;
239 break;
240 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
241 stq->base.Result = data.pipeline_statistics.c_primitives;
242 break;
243 default:
244 switch (stq->type) {
245 case PIPE_QUERY_OCCLUSION_PREDICATE:
246 stq->base.Result = !!data.b;
247 break;
248 default:
249 stq->base.Result = data.u64;
250 break;
251 }
252 break;
253 }
254
255 if (stq->base.Target == GL_TIME_ELAPSED &&
256 stq->type == PIPE_QUERY_TIMESTAMP) {
257 /* Calculate the elapsed time from the two timestamp queries */
258 GLuint64EXT Result0 = 0;
259 assert(stq->pq_begin);
260 pipe->get_query_result(pipe, stq->pq_begin, TRUE, (void *)&Result0);
261 stq->base.Result -= Result0;
262 } else {
263 assert(!stq->pq_begin);
264 }
265
266 return TRUE;
267 }
268
269
270 static void
271 st_WaitQuery(struct gl_context *ctx, struct gl_query_object *q)
272 {
273 struct pipe_context *pipe = st_context(ctx)->pipe;
274 struct st_query_object *stq = st_query_object(q);
275
276 /* this function should only be called if we don't have a ready result */
277 assert(!stq->base.Ready);
278
279 while (!stq->base.Ready &&
280 !get_query_result(pipe, stq, TRUE))
281 {
282 /* nothing */
283 }
284
285 q->Ready = GL_TRUE;
286 }
287
288
289 static void
290 st_CheckQuery(struct gl_context *ctx, struct gl_query_object *q)
291 {
292 struct pipe_context *pipe = st_context(ctx)->pipe;
293 struct st_query_object *stq = st_query_object(q);
294 assert(!q->Ready); /* we should not get called if Ready is TRUE */
295 q->Ready = get_query_result(pipe, stq, FALSE);
296 }
297
298
299 static uint64_t
300 st_GetTimestamp(struct gl_context *ctx)
301 {
302 struct pipe_context *pipe = st_context(ctx)->pipe;
303 struct pipe_screen *screen = pipe->screen;
304
305 /* Prefer the per-screen function */
306 if (screen->get_timestamp) {
307 return screen->get_timestamp(screen);
308 }
309 else {
310 /* Fall back to the per-context function */
311 assert(pipe->get_timestamp);
312 return pipe->get_timestamp(pipe);
313 }
314 }
315
316 static void
317 st_StoreQueryResult(struct gl_context *ctx, struct gl_query_object *q,
318 struct gl_buffer_object *buf, intptr_t offset,
319 GLenum pname, GLenum ptype)
320 {
321 struct pipe_context *pipe = st_context(ctx)->pipe;
322 struct st_query_object *stq = st_query_object(q);
323 struct st_buffer_object *stObj = st_buffer_object(buf);
324 boolean wait = pname == GL_QUERY_RESULT;
325 enum pipe_query_value_type result_type;
326 int index;
327
328 /* GL_QUERY_TARGET is a bit of an extension since it has nothing to
329 * do with the GPU end of the query. Write it in "by hand".
330 */
331 if (pname == GL_QUERY_TARGET) {
332 /* Assume that the data must be LE. The endianness situation wrt CPU and
333 * GPU is incredibly confusing, but the vast majority of GPUs are
334 * LE. When a BE one comes along, this needs some form of resolution.
335 */
336 unsigned data[2] = { CPU_TO_LE32(q->Target), 0 };
337 pipe_buffer_write(pipe, stObj->buffer, offset,
338 (ptype == GL_INT64_ARB ||
339 ptype == GL_UNSIGNED_INT64_ARB) ? 8 : 4,
340 data);
341 return;
342 }
343
344 switch (ptype) {
345 case GL_INT:
346 result_type = PIPE_QUERY_TYPE_I32;
347 break;
348 case GL_UNSIGNED_INT:
349 result_type = PIPE_QUERY_TYPE_U32;
350 break;
351 case GL_INT64_ARB:
352 result_type = PIPE_QUERY_TYPE_I64;
353 break;
354 case GL_UNSIGNED_INT64_ARB:
355 result_type = PIPE_QUERY_TYPE_U64;
356 break;
357 default:
358 unreachable("Unexpected result type");
359 }
360
361 if (pname == GL_QUERY_RESULT_AVAILABLE) {
362 index = -1;
363 } else if (stq->type == PIPE_QUERY_PIPELINE_STATISTICS) {
364 switch (q->Target) {
365 case GL_VERTICES_SUBMITTED_ARB:
366 index = 0;
367 break;
368 case GL_PRIMITIVES_SUBMITTED_ARB:
369 index = 1;
370 break;
371 case GL_VERTEX_SHADER_INVOCATIONS_ARB:
372 index = 2;
373 break;
374 case GL_GEOMETRY_SHADER_INVOCATIONS:
375 index = 3;
376 break;
377 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
378 index = 4;
379 break;
380 case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
381 index = 5;
382 break;
383 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
384 index = 6;
385 break;
386 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
387 index = 7;
388 break;
389 case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
390 index = 8;
391 break;
392 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
393 index = 9;
394 break;
395 case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
396 index = 10;
397 break;
398 default:
399 unreachable("Unexpected target");
400 }
401 } else {
402 index = 0;
403 }
404
405 pipe->get_query_result_resource(pipe, stq->pq, wait, result_type, index,
406 stObj->buffer, offset);
407 }
408
409 void st_init_query_functions(struct dd_function_table *functions)
410 {
411 functions->NewQueryObject = st_NewQueryObject;
412 functions->DeleteQuery = st_DeleteQuery;
413 functions->BeginQuery = st_BeginQuery;
414 functions->EndQuery = st_EndQuery;
415 functions->WaitQuery = st_WaitQuery;
416 functions->CheckQuery = st_CheckQuery;
417 functions->GetTimestamp = st_GetTimestamp;
418 functions->StoreQueryResult = st_StoreQueryResult;
419 }