1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 1999-2007 Brian Paul 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 "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 #include "bufferobj.h"
27 #include "glheader.h"
28 #include "context.h"
29 #include "enums.h"
30 #include "hash.h"
31
32 #include "queryobj.h"
33 #include "mtypes.h"
34 #include "pipe/p_context.h"
35 #include "pipe/p_screen.h"
36 #include "util/u_memory.h"
37
38 #include "api_exec_decl.h"
39 #include "pipe/p_context.h"
40 #include "pipe/p_screen.h"
41 #include "state_tracker/st_context.h"
42 #include "state_tracker/st_cb_bitmap.h"
43
44
45 static struct gl_query_object *
new_query_object(struct gl_context * ctx,GLuint id)46 new_query_object(struct gl_context *ctx, GLuint id)
47 {
48 struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
49 if (q) {
50 q->Id = id;
51 q->Ready = GL_TRUE;
52 q->pq = NULL;
53 q->type = PIPE_QUERY_TYPES; /* an invalid value */
54 return q;
55 }
56 return NULL;
57 }
58
59
60 static void
free_queries(struct pipe_context * pipe,struct gl_query_object * q)61 free_queries(struct pipe_context *pipe, struct gl_query_object *q)
62 {
63 if (q->pq) {
64 pipe->destroy_query(pipe, q->pq);
65 q->pq = NULL;
66 }
67
68 if (q->pq_begin) {
69 pipe->destroy_query(pipe, q->pq_begin);
70 q->pq_begin = NULL;
71 }
72 }
73
74
75 static void
delete_query(struct gl_context * ctx,struct gl_query_object * q)76 delete_query(struct gl_context *ctx, struct gl_query_object *q)
77 {
78 struct pipe_context *pipe = ctx->pipe;
79
80 free_queries(pipe, q);
81 free(q->Label);
82 FREE(q);
83 }
84
85 static int
target_to_index(const struct gl_query_object * q)86 target_to_index(const struct gl_query_object *q)
87 {
88 if (q->Target == GL_PRIMITIVES_GENERATED ||
89 q->Target == GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN ||
90 q->Target == GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB)
91 return q->Stream;
92
93 /* Drivers with PIPE_CAP_QUERY_PIPELINE_STATISTICS_SINGLE = 0 ignore the
94 * index param so it should be useless; but radeonsi needs it in some cases,
95 * so pass the correct value.
96 */
97 switch (q->Target) {
98 case GL_VERTICES_SUBMITTED_ARB:
99 return PIPE_STAT_QUERY_IA_VERTICES;
100 case GL_PRIMITIVES_SUBMITTED_ARB:
101 return PIPE_STAT_QUERY_IA_PRIMITIVES;
102 case GL_VERTEX_SHADER_INVOCATIONS_ARB:
103 return PIPE_STAT_QUERY_VS_INVOCATIONS;
104 case GL_GEOMETRY_SHADER_INVOCATIONS:
105 return PIPE_STAT_QUERY_GS_INVOCATIONS;
106 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
107 return PIPE_STAT_QUERY_GS_PRIMITIVES;
108 case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
109 return PIPE_STAT_QUERY_C_INVOCATIONS;
110 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
111 return PIPE_STAT_QUERY_C_PRIMITIVES;
112 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
113 return PIPE_STAT_QUERY_PS_INVOCATIONS;
114 case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
115 return PIPE_STAT_QUERY_HS_INVOCATIONS;
116 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
117 return PIPE_STAT_QUERY_DS_INVOCATIONS;
118 case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
119 return PIPE_STAT_QUERY_CS_INVOCATIONS;
120 default:
121 break;
122 }
123
124 return 0;
125 }
126
127 static void
begin_query(struct gl_context * ctx,struct gl_query_object * q)128 begin_query(struct gl_context *ctx, struct gl_query_object *q)
129 {
130 struct st_context *st = st_context(ctx);
131 struct pipe_context *pipe = ctx->pipe;
132 unsigned type;
133 bool ret = false;
134
135 st_flush_bitmap_cache(st_context(ctx));
136
137 /* convert GL query type to Gallium query type */
138 switch (q->Target) {
139 case GL_ANY_SAMPLES_PASSED:
140 type = PIPE_QUERY_OCCLUSION_PREDICATE;
141 break;
142 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
143 type = PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE;
144 break;
145 case GL_SAMPLES_PASSED_ARB:
146 type = PIPE_QUERY_OCCLUSION_COUNTER;
147 break;
148 case GL_PRIMITIVES_GENERATED:
149 type = PIPE_QUERY_PRIMITIVES_GENERATED;
150 break;
151 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
152 type = PIPE_QUERY_PRIMITIVES_EMITTED;
153 break;
154 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
155 type = PIPE_QUERY_SO_OVERFLOW_PREDICATE;
156 break;
157 case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB:
158 type = PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE;
159 break;
160 case GL_TIME_ELAPSED:
161 if (st->has_time_elapsed)
162 type = PIPE_QUERY_TIME_ELAPSED;
163 else
164 type = PIPE_QUERY_TIMESTAMP;
165 break;
166 case GL_VERTICES_SUBMITTED_ARB:
167 case GL_PRIMITIVES_SUBMITTED_ARB:
168 case GL_VERTEX_SHADER_INVOCATIONS_ARB:
169 case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
170 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
171 case GL_GEOMETRY_SHADER_INVOCATIONS:
172 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
173 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
174 case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
175 case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
176 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
177 type = st->has_single_pipe_stat ? PIPE_QUERY_PIPELINE_STATISTICS_SINGLE
178 : PIPE_QUERY_PIPELINE_STATISTICS;
179 break;
180 default:
181 assert(0 && "unexpected query target in st_BeginQuery()");
182 return;
183 }
184
185 if (q->type != type) {
186 /* free old query of different type */
187 free_queries(pipe, q);
188 q->type = PIPE_QUERY_TYPES; /* an invalid value */
189 }
190
191 if (q->Target == GL_TIME_ELAPSED &&
192 type == PIPE_QUERY_TIMESTAMP) {
193 /* Determine time elapsed by emitting two timestamp queries. */
194 if (!q->pq_begin) {
195 q->pq_begin = pipe->create_query(pipe, type, 0);
196 q->type = type;
197 }
198 if (q->pq_begin)
199 ret = pipe->end_query(pipe, q->pq_begin);
200 } else {
201 if (!q->pq) {
202 q->pq = pipe->create_query(pipe, type, target_to_index(q));
203 q->type = type;
204 }
205 if (q->pq)
206 ret = pipe->begin_query(pipe, q->pq);
207 }
208
209 if (!ret) {
210 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery");
211
212 free_queries(pipe, q);
213 q->Active = GL_FALSE;
214 return;
215 }
216
217 if (q->type != PIPE_QUERY_TIMESTAMP)
218 st->active_queries++;
219
220 assert(q->type == type);
221 }
222
223
224 static void
end_query(struct gl_context * ctx,struct gl_query_object * q)225 end_query(struct gl_context *ctx, struct gl_query_object *q)
226 {
227 struct st_context *st = st_context(ctx);
228 struct pipe_context *pipe = ctx->pipe;
229 bool ret = false;
230
231 st_flush_bitmap_cache(st_context(ctx));
232
233 if ((q->Target == GL_TIMESTAMP ||
234 q->Target == GL_TIME_ELAPSED) &&
235 !q->pq) {
236 q->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP, 0);
237 q->type = PIPE_QUERY_TIMESTAMP;
238 }
239
240 if (q->pq)
241 ret = pipe->end_query(pipe, q->pq);
242
243 if (!ret) {
244 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEndQuery");
245 return;
246 }
247
248 if (q->type != PIPE_QUERY_TIMESTAMP)
249 st->active_queries--;
250 }
251
252
253 static boolean
get_query_result(struct pipe_context * pipe,struct gl_query_object * q,boolean wait)254 get_query_result(struct pipe_context *pipe,
255 struct gl_query_object *q,
256 boolean wait)
257 {
258 union pipe_query_result data;
259
260 if (!q->pq) {
261 /* Only needed in case we failed to allocate the gallium query earlier.
262 * Return TRUE so we don't spin on this forever.
263 */
264 return TRUE;
265 }
266
267 if (!pipe->get_query_result(pipe, q->pq, wait, &data))
268 return FALSE;
269
270 switch (q->type) {
271 case PIPE_QUERY_PIPELINE_STATISTICS:
272 switch (q->Target) {
273 case GL_VERTICES_SUBMITTED_ARB:
274 q->Result = data.pipeline_statistics.ia_vertices;
275 break;
276 case GL_PRIMITIVES_SUBMITTED_ARB:
277 q->Result = data.pipeline_statistics.ia_primitives;
278 break;
279 case GL_VERTEX_SHADER_INVOCATIONS_ARB:
280 q->Result = data.pipeline_statistics.vs_invocations;
281 break;
282 case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
283 q->Result = data.pipeline_statistics.hs_invocations;
284 break;
285 case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
286 q->Result = data.pipeline_statistics.ds_invocations;
287 break;
288 case GL_GEOMETRY_SHADER_INVOCATIONS:
289 q->Result = data.pipeline_statistics.gs_invocations;
290 break;
291 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
292 q->Result = data.pipeline_statistics.gs_primitives;
293 break;
294 case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
295 q->Result = data.pipeline_statistics.ps_invocations;
296 break;
297 case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
298 q->Result = data.pipeline_statistics.cs_invocations;
299 break;
300 case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
301 q->Result = data.pipeline_statistics.c_invocations;
302 break;
303 case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
304 q->Result = data.pipeline_statistics.c_primitives;
305 break;
306 default:
307 unreachable("invalid pipeline statistics counter");
308 }
309 break;
310 case PIPE_QUERY_OCCLUSION_PREDICATE:
311 case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
312 case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
313 case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
314 q->Result = !!data.b;
315 break;
316 default:
317 q->Result = data.u64;
318 break;
319 }
320
321 if (q->Target == GL_TIME_ELAPSED &&
322 q->type == PIPE_QUERY_TIMESTAMP) {
323 /* Calculate the elapsed time from the two timestamp queries */
324 GLuint64EXT Result0 = 0;
325 assert(q->pq_begin);
326 pipe->get_query_result(pipe, q->pq_begin, TRUE, (void *)&Result0);
327 q->Result -= Result0;
328 } else {
329 assert(!q->pq_begin);
330 }
331
332 return TRUE;
333 }
334
335
336 void
_mesa_wait_query(struct gl_context * ctx,struct gl_query_object * q)337 _mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
338 {
339 struct pipe_context *pipe = ctx->pipe;
340
341 /* this function should only be called if we don't have a ready result */
342 assert(!q->Ready);
343
344 while (!q->Ready &&
345 !get_query_result(pipe, q, TRUE))
346 {
347 /* nothing */
348 }
349
350 q->Ready = GL_TRUE;
351 }
352
353
354 void
_mesa_check_query(struct gl_context * ctx,struct gl_query_object * q)355 _mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
356 {
357 struct pipe_context *pipe = ctx->pipe;
358 assert(!q->Ready); /* we should not get called if Ready is TRUE */
359 q->Ready = get_query_result(pipe, q, FALSE);
360 }
361
362
363 uint64_t
_mesa_get_timestamp(struct gl_context * ctx)364 _mesa_get_timestamp(struct gl_context *ctx)
365 {
366 struct pipe_context *pipe = ctx->pipe;
367 struct pipe_screen *screen = pipe->screen;
368
369 /* Prefer the per-screen function */
370 if (screen->get_timestamp) {
371 return screen->get_timestamp(screen);
372 }
373 else {
374 /* Fall back to the per-context function */
375 assert(pipe->get_timestamp);
376 return pipe->get_timestamp(pipe);
377 }
378 }
379
380 static void
store_query_result(struct gl_context * ctx,struct gl_query_object * q,struct gl_buffer_object * buf,intptr_t offset,GLenum pname,GLenum ptype)381 store_query_result(struct gl_context *ctx, struct gl_query_object *q,
382 struct gl_buffer_object *buf, intptr_t offset,
383 GLenum pname, GLenum ptype)
384 {
385 struct pipe_context *pipe = ctx->pipe;
386 enum pipe_query_flags flags = 0;
387 enum pipe_query_value_type result_type;
388 int index;
389
390 if (pname == GL_QUERY_RESULT)
391 flags |= PIPE_QUERY_WAIT;
392
393 /* GL_QUERY_TARGET is a bit of an extension since it has nothing to
394 * do with the GPU end of the query. Write it in "by hand".
395 */
396 if (pname == GL_QUERY_TARGET) {
397 /* Assume that the data must be LE. The endianness situation wrt CPU and
398 * GPU is incredibly confusing, but the vast majority of GPUs are
399 * LE. When a BE one comes along, this needs some form of resolution.
400 */
401 unsigned data[2] = { CPU_TO_LE32(q->Target), 0 };
402 pipe_buffer_write(pipe, buf->buffer, offset,
403 (ptype == GL_INT64_ARB ||
404 ptype == GL_UNSIGNED_INT64_ARB) ? 8 : 4,
405 data);
406 return;
407 }
408
409 switch (ptype) {
410 case GL_INT:
411 result_type = PIPE_QUERY_TYPE_I32;
412 break;
413 case GL_UNSIGNED_INT:
414 result_type = PIPE_QUERY_TYPE_U32;
415 break;
416 case GL_INT64_ARB:
417 result_type = PIPE_QUERY_TYPE_I64;
418 break;
419 case GL_UNSIGNED_INT64_ARB:
420 result_type = PIPE_QUERY_TYPE_U64;
421 break;
422 default:
423 unreachable("Unexpected result type");
424 }
425
426 if (pname == GL_QUERY_RESULT_AVAILABLE) {
427 index = -1;
428 } else if (q->type == PIPE_QUERY_PIPELINE_STATISTICS) {
429 index = target_to_index(q);
430 } else {
431 index = 0;
432 }
433
434 pipe->get_query_result_resource(pipe, q->pq, flags, result_type, index,
435 buf->buffer, offset);
436 }
437
438 static struct gl_query_object **
get_pipe_stats_binding_point(struct gl_context * ctx,GLenum target)439 get_pipe_stats_binding_point(struct gl_context *ctx,
440 GLenum target)
441 {
442 const int which = target - GL_VERTICES_SUBMITTED;
443 assert(which < MAX_PIPELINE_STATISTICS);
444
445 if (!_mesa_has_ARB_pipeline_statistics_query(ctx))
446 return NULL;
447
448 return &ctx->Query.pipeline_stats[which];
449 }
450
451 /**
452 * Return pointer to the query object binding point for the given target and
453 * index.
454 * \return NULL if invalid target, else the address of binding point
455 */
456 static struct gl_query_object **
get_query_binding_point(struct gl_context * ctx,GLenum target,GLuint index)457 get_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
458 {
459 switch (target) {
460 case GL_SAMPLES_PASSED:
461 if (_mesa_has_ARB_occlusion_query(ctx) ||
462 _mesa_has_ARB_occlusion_query2(ctx))
463 return &ctx->Query.CurrentOcclusionObject;
464 else
465 return NULL;
466 case GL_ANY_SAMPLES_PASSED:
467 if (_mesa_has_ARB_occlusion_query2(ctx) ||
468 _mesa_has_EXT_occlusion_query_boolean(ctx))
469 return &ctx->Query.CurrentOcclusionObject;
470 else
471 return NULL;
472 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
473 if (_mesa_has_ARB_ES3_compatibility(ctx) ||
474 _mesa_has_EXT_occlusion_query_boolean(ctx))
475 return &ctx->Query.CurrentOcclusionObject;
476 else
477 return NULL;
478 case GL_TIME_ELAPSED:
479 if (_mesa_has_EXT_timer_query(ctx) ||
480 _mesa_has_EXT_disjoint_timer_query(ctx))
481 return &ctx->Query.CurrentTimerObject;
482 else
483 return NULL;
484 case GL_PRIMITIVES_GENERATED:
485 if (_mesa_has_EXT_transform_feedback(ctx) ||
486 _mesa_has_EXT_tessellation_shader(ctx) ||
487 _mesa_has_OES_geometry_shader(ctx))
488 return &ctx->Query.PrimitivesGenerated[index];
489 else
490 return NULL;
491 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
492 if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx))
493 return &ctx->Query.PrimitivesWritten[index];
494 else
495 return NULL;
496 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
497 if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
498 return &ctx->Query.TransformFeedbackOverflow[index];
499 else
500 return NULL;
501 case GL_TRANSFORM_FEEDBACK_OVERFLOW:
502 if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
503 return &ctx->Query.TransformFeedbackOverflowAny;
504 else
505 return NULL;
506
507 case GL_VERTICES_SUBMITTED:
508 case GL_PRIMITIVES_SUBMITTED:
509 case GL_VERTEX_SHADER_INVOCATIONS:
510 case GL_FRAGMENT_SHADER_INVOCATIONS:
511 case GL_CLIPPING_INPUT_PRIMITIVES:
512 case GL_CLIPPING_OUTPUT_PRIMITIVES:
513 return get_pipe_stats_binding_point(ctx, target);
514
515 case GL_GEOMETRY_SHADER_INVOCATIONS:
516 /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
517 target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1;
518 FALLTHROUGH;
519 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
520 if (_mesa_has_geometry_shaders(ctx))
521 return get_pipe_stats_binding_point(ctx, target);
522 else
523 return NULL;
524
525 case GL_TESS_CONTROL_SHADER_PATCHES:
526 case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
527 if (_mesa_has_tessellation(ctx))
528 return get_pipe_stats_binding_point(ctx, target);
529 else
530 return NULL;
531
532 case GL_COMPUTE_SHADER_INVOCATIONS:
533 if (_mesa_has_compute_shaders(ctx))
534 return get_pipe_stats_binding_point(ctx, target);
535 else
536 return NULL;
537
538 default:
539 return NULL;
540 }
541 }
542
543 /**
544 * Create $n query objects and store them in *ids. Make them of type $target
545 * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
546 */
547 static void
create_queries(struct gl_context * ctx,GLenum target,GLsizei n,GLuint * ids,bool dsa)548 create_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
549 bool dsa)
550 {
551 const char *func = dsa ? "glGenQueries" : "glCreateQueries";
552
553 if (MESA_VERBOSE & VERBOSE_API)
554 _mesa_debug(ctx, "%s(%d)\n", func, n);
555
556 if (n < 0) {
557 _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
558 return;
559 }
560
561 if (_mesa_HashFindFreeKeys(ctx->Query.QueryObjects, ids, n)) {
562 GLsizei i;
563 for (i = 0; i < n; i++) {
564 struct gl_query_object *q
565 = new_query_object(ctx, ids[i]);
566 if (!q) {
567 _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
568 return;
569 } else if (dsa) {
570 /* Do the equivalent of binding the buffer with a target */
571 q->Target = target;
572 q->EverBound = GL_TRUE;
573 }
574 _mesa_HashInsertLocked(ctx->Query.QueryObjects, ids[i], q, true);
575 }
576 }
577 }
578
579 void GLAPIENTRY
_mesa_GenQueries(GLsizei n,GLuint * ids)580 _mesa_GenQueries(GLsizei n, GLuint *ids)
581 {
582 GET_CURRENT_CONTEXT(ctx);
583 create_queries(ctx, 0, n, ids, false);
584 }
585
586 void GLAPIENTRY
_mesa_CreateQueries(GLenum target,GLsizei n,GLuint * ids)587 _mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
588 {
589 GET_CURRENT_CONTEXT(ctx);
590
591 switch (target) {
592 case GL_SAMPLES_PASSED:
593 case GL_ANY_SAMPLES_PASSED:
594 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
595 case GL_TIME_ELAPSED:
596 case GL_TIMESTAMP:
597 case GL_PRIMITIVES_GENERATED:
598 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
599 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
600 case GL_TRANSFORM_FEEDBACK_OVERFLOW:
601 break;
602 default:
603 _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
604 _mesa_enum_to_string(target));
605 return;
606 }
607
608 create_queries(ctx, target, n, ids, true);
609 }
610
611
612 void GLAPIENTRY
_mesa_DeleteQueries(GLsizei n,const GLuint * ids)613 _mesa_DeleteQueries(GLsizei n, const GLuint *ids)
614 {
615 GLint i;
616 GET_CURRENT_CONTEXT(ctx);
617 FLUSH_VERTICES(ctx, 0, 0);
618
619 if (MESA_VERBOSE & VERBOSE_API)
620 _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
621
622 if (n < 0) {
623 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
624 return;
625 }
626
627 for (i = 0; i < n; i++) {
628 if (ids[i] > 0) {
629 struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
630 if (q) {
631 if (q->Active) {
632 struct gl_query_object **bindpt;
633 bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
634 assert(bindpt); /* Should be non-null for active q. */
635 if (bindpt) {
636 *bindpt = NULL;
637 }
638 q->Active = GL_FALSE;
639 end_query(ctx, q);
640 }
641 _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]);
642 delete_query(ctx, q);
643 }
644 }
645 }
646 }
647
648
649 GLboolean GLAPIENTRY
_mesa_IsQuery(GLuint id)650 _mesa_IsQuery(GLuint id)
651 {
652 struct gl_query_object *q;
653
654 GET_CURRENT_CONTEXT(ctx);
655 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
656
657 if (MESA_VERBOSE & VERBOSE_API)
658 _mesa_debug(ctx, "glIsQuery(%u)\n", id);
659
660 if (id == 0)
661 return GL_FALSE;
662
663 q = _mesa_lookup_query_object(ctx, id);
664 if (q == NULL)
665 return GL_FALSE;
666
667 return q->EverBound;
668 }
669
670 static GLboolean
query_error_check_index(struct gl_context * ctx,GLenum target,GLuint index)671 query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
672 {
673 switch (target) {
674 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
675 case GL_PRIMITIVES_GENERATED:
676 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
677 if (index >= ctx->Const.MaxVertexStreams) {
678 _mesa_error(ctx, GL_INVALID_VALUE,
679 "glBeginQueryIndexed(index>=MaxVertexStreams)");
680 return GL_FALSE;
681 }
682 break;
683 default:
684 if (index > 0) {
685 _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
686 return GL_FALSE;
687 }
688 }
689 return GL_TRUE;
690 }
691
692 void GLAPIENTRY
_mesa_BeginQueryIndexed(GLenum target,GLuint index,GLuint id)693 _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
694 {
695 struct gl_query_object *q, **bindpt;
696 GET_CURRENT_CONTEXT(ctx);
697
698 if (MESA_VERBOSE & VERBOSE_API)
699 _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
700 _mesa_enum_to_string(target), index, id);
701
702 if (!query_error_check_index(ctx, target, index))
703 return;
704
705 FLUSH_VERTICES(ctx, 0, 0);
706
707 bindpt = get_query_binding_point(ctx, target, index);
708 if (!bindpt) {
709 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
710 return;
711 }
712
713 /* From the GL_ARB_occlusion_query spec:
714 *
715 * "If BeginQueryARB is called while another query is already in
716 * progress with the same target, an INVALID_OPERATION error is
717 * generated."
718 */
719 if (*bindpt) {
720 _mesa_error(ctx, GL_INVALID_OPERATION,
721 "glBeginQuery{Indexed}(target=%s is active)",
722 _mesa_enum_to_string(target));
723 return;
724 }
725
726 if (id == 0) {
727 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
728 return;
729 }
730
731 q = _mesa_lookup_query_object(ctx, id);
732 if (!q) {
733 if (ctx->API != API_OPENGL_COMPAT) {
734 _mesa_error(ctx, GL_INVALID_OPERATION,
735 "glBeginQuery{Indexed}(non-gen name)");
736 return;
737 } else {
738 /* create new object */
739 q = new_query_object(ctx, id);
740 if (!q) {
741 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
742 return;
743 }
744 _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false);
745 }
746 }
747 else {
748 /* pre-existing object */
749 if (q->Active) {
750 _mesa_error(ctx, GL_INVALID_OPERATION,
751 "glBeginQuery{Indexed}(query already active)");
752 return;
753 }
754
755 /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
756 * spec states:
757 *
758 * "BeginQuery generates an INVALID_OPERATION error if any of the
759 * following conditions hold: [...] id is the name of an
760 * existing query object whose type does not match target; [...]
761 *
762 * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
763 * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
764 */
765 if (q->EverBound && q->Target != target) {
766 _mesa_error(ctx, GL_INVALID_OPERATION,
767 "glBeginQuery{Indexed}(target mismatch)");
768 return;
769 }
770 }
771
772 /* This possibly changes the target of a buffer allocated by
773 * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
774 * the following:
775 *
776 * "CreateQueries adds a <target>, so strictly speaking the <target>
777 * command isn't needed for BeginQuery/EndQuery, but in the end, this also
778 * isn't a selector, so we decided not to change it."
779 *
780 * Updating the target of the query object should be acceptable, so let's
781 * do that.
782 */
783
784 q->Target = target;
785 q->Active = GL_TRUE;
786 q->Result = 0;
787 q->Ready = GL_FALSE;
788 q->EverBound = GL_TRUE;
789 q->Stream = index;
790
791 /* XXX should probably refcount query objects */
792 *bindpt = q;
793
794 begin_query(ctx, q);
795 }
796
797
798 void GLAPIENTRY
_mesa_EndQueryIndexed(GLenum target,GLuint index)799 _mesa_EndQueryIndexed(GLenum target, GLuint index)
800 {
801 struct gl_query_object *q, **bindpt;
802 GET_CURRENT_CONTEXT(ctx);
803
804 if (MESA_VERBOSE & VERBOSE_API)
805 _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
806 _mesa_enum_to_string(target), index);
807
808 if (!query_error_check_index(ctx, target, index))
809 return;
810
811 FLUSH_VERTICES(ctx, 0, 0);
812
813 bindpt = get_query_binding_point(ctx, target, index);
814 if (!bindpt) {
815 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
816 return;
817 }
818
819 /* XXX should probably refcount query objects */
820 q = *bindpt;
821
822 /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
823 if (q && q->Target != target) {
824 _mesa_error(ctx, GL_INVALID_OPERATION,
825 "glEndQuery(target=%s with active query of target %s)",
826 _mesa_enum_to_string(target),
827 _mesa_enum_to_string(q->Target));
828 return;
829 }
830
831 *bindpt = NULL;
832
833 if (!q || !q->Active) {
834 _mesa_error(ctx, GL_INVALID_OPERATION,
835 "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
836 return;
837 }
838
839 q->Active = GL_FALSE;
840 end_query(ctx, q);
841 }
842
843 void GLAPIENTRY
_mesa_BeginQuery(GLenum target,GLuint id)844 _mesa_BeginQuery(GLenum target, GLuint id)
845 {
846 _mesa_BeginQueryIndexed(target, 0, id);
847 }
848
849 void GLAPIENTRY
_mesa_EndQuery(GLenum target)850 _mesa_EndQuery(GLenum target)
851 {
852 _mesa_EndQueryIndexed(target, 0);
853 }
854
855 void GLAPIENTRY
_mesa_QueryCounter(GLuint id,GLenum target)856 _mesa_QueryCounter(GLuint id, GLenum target)
857 {
858 struct gl_query_object *q;
859 GET_CURRENT_CONTEXT(ctx);
860
861 if (MESA_VERBOSE & VERBOSE_API)
862 _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
863 _mesa_enum_to_string(target));
864
865 /* error checking */
866 if (target != GL_TIMESTAMP) {
867 _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
868 return;
869 }
870
871 if (id == 0) {
872 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
873 return;
874 }
875
876 q = _mesa_lookup_query_object(ctx, id);
877 if (!q) {
878 /* XXX the Core profile should throw INVALID_OPERATION here */
879
880 /* create new object */
881 q = new_query_object(ctx, id);
882 if (!q) {
883 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
884 return;
885 }
886 _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false);
887 }
888 else {
889 if (q->Target && q->Target != GL_TIMESTAMP) {
890 _mesa_error(ctx, GL_INVALID_OPERATION,
891 "glQueryCounter(id has an invalid target)");
892 return;
893 }
894 }
895
896 if (q->Active) {
897 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
898 return;
899 }
900
901 /* This possibly changes the target of a buffer allocated by
902 * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
903 * the following:
904 *
905 * "CreateQueries adds a <target>, so strictly speaking the <target>
906 * command isn't needed for BeginQuery/EndQuery, but in the end, this also
907 * isn't a selector, so we decided not to change it."
908 *
909 * Updating the target of the query object should be acceptable, so let's
910 * do that.
911 */
912
913 q->Target = target;
914 q->Result = 0;
915 q->Ready = GL_FALSE;
916 q->EverBound = GL_TRUE;
917
918 /* QueryCounter is implemented using EndQuery without BeginQuery
919 * in drivers. This is actually Direct3D and Gallium convention.
920 */
921 end_query(ctx, q);
922 }
923
924
925 void GLAPIENTRY
_mesa_GetQueryIndexediv(GLenum target,GLuint index,GLenum pname,GLint * params)926 _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
927 GLint *params)
928 {
929 struct gl_query_object *q = NULL, **bindpt = NULL;
930 GET_CURRENT_CONTEXT(ctx);
931
932 if (MESA_VERBOSE & VERBOSE_API)
933 _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
934 _mesa_enum_to_string(target),
935 index,
936 _mesa_enum_to_string(pname));
937
938 if (!query_error_check_index(ctx, target, index))
939 return;
940
941 /* From the GL_EXT_occlusion_query_boolean spec:
942 *
943 * "The error INVALID_ENUM is generated if GetQueryivEXT is called where
944 * <pname> is not CURRENT_QUERY_EXT."
945 *
946 * Same rule is present also in ES 3.2 spec.
947 *
948 * EXT_disjoint_timer_query extends this with GL_QUERY_COUNTER_BITS.
949 */
950 if (_mesa_is_gles(ctx)) {
951 switch (pname) {
952 case GL_CURRENT_QUERY:
953 break;
954 case GL_QUERY_COUNTER_BITS:
955 if (_mesa_has_EXT_disjoint_timer_query(ctx))
956 break;
957 FALLTHROUGH;
958 default:
959 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)",
960 _mesa_enum_to_string(pname));
961 }
962 }
963
964 if (target == GL_TIMESTAMP) {
965 if (!_mesa_has_ARB_timer_query(ctx) &&
966 !_mesa_has_EXT_disjoint_timer_query(ctx)) {
967 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
968 return;
969 }
970 }
971 else {
972 bindpt = get_query_binding_point(ctx, target, index);
973 if (!bindpt) {
974 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
975 return;
976 }
977
978 q = *bindpt;
979 }
980
981 switch (pname) {
982 case GL_QUERY_COUNTER_BITS:
983 switch (target) {
984 case GL_SAMPLES_PASSED:
985 *params = ctx->Const.QueryCounterBits.SamplesPassed;
986 break;
987 case GL_ANY_SAMPLES_PASSED:
988 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
989 /* The minimum value of this is 1 if it's nonzero, and the value
990 * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
991 * bits.
992 */
993 *params = 1;
994 break;
995 case GL_TIME_ELAPSED:
996 *params = ctx->Const.QueryCounterBits.TimeElapsed;
997 break;
998 case GL_TIMESTAMP:
999 *params = ctx->Const.QueryCounterBits.Timestamp;
1000 break;
1001 case GL_PRIMITIVES_GENERATED:
1002 *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
1003 break;
1004 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1005 *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
1006 break;
1007 case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
1008 case GL_TRANSFORM_FEEDBACK_OVERFLOW:
1009 /* The minimum value of this is 1 if it's nonzero, and the value
1010 * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
1011 * bits.
1012 */
1013 *params = 1;
1014 break;
1015 case GL_VERTICES_SUBMITTED:
1016 *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
1017 break;
1018 case GL_PRIMITIVES_SUBMITTED:
1019 *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
1020 break;
1021 case GL_VERTEX_SHADER_INVOCATIONS:
1022 *params = ctx->Const.QueryCounterBits.VsInvocations;
1023 break;
1024 case GL_TESS_CONTROL_SHADER_PATCHES:
1025 *params = ctx->Const.QueryCounterBits.TessPatches;
1026 break;
1027 case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
1028 *params = ctx->Const.QueryCounterBits.TessInvocations;
1029 break;
1030 case GL_GEOMETRY_SHADER_INVOCATIONS:
1031 *params = ctx->Const.QueryCounterBits.GsInvocations;
1032 break;
1033 case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
1034 *params = ctx->Const.QueryCounterBits.GsPrimitives;
1035 break;
1036 case GL_FRAGMENT_SHADER_INVOCATIONS:
1037 *params = ctx->Const.QueryCounterBits.FsInvocations;
1038 break;
1039 case GL_COMPUTE_SHADER_INVOCATIONS:
1040 *params = ctx->Const.QueryCounterBits.ComputeInvocations;
1041 break;
1042 case GL_CLIPPING_INPUT_PRIMITIVES:
1043 *params = ctx->Const.QueryCounterBits.ClInPrimitives;
1044 break;
1045 case GL_CLIPPING_OUTPUT_PRIMITIVES:
1046 *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
1047 break;
1048 default:
1049 _mesa_problem(ctx,
1050 "Unknown target in glGetQueryIndexediv(target = %s)",
1051 _mesa_enum_to_string(target));
1052 *params = 0;
1053 break;
1054 }
1055 break;
1056 case GL_CURRENT_QUERY:
1057 *params = (q && q->Target == target) ? q->Id : 0;
1058 break;
1059 default:
1060 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
1061 return;
1062 }
1063 }
1064
1065 void GLAPIENTRY
_mesa_GetQueryiv(GLenum target,GLenum pname,GLint * params)1066 _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
1067 {
1068 _mesa_GetQueryIndexediv(target, 0, pname, params);
1069 }
1070
1071 static void
get_query_object(struct gl_context * ctx,const char * func,GLuint id,GLenum pname,GLenum ptype,struct gl_buffer_object * buf,intptr_t offset)1072 get_query_object(struct gl_context *ctx, const char *func,
1073 GLuint id, GLenum pname, GLenum ptype,
1074 struct gl_buffer_object *buf, intptr_t offset)
1075 {
1076 struct gl_query_object *q = NULL;
1077 uint64_t value;
1078
1079 if (MESA_VERBOSE & VERBOSE_API)
1080 _mesa_debug(ctx, "%s(%u, %s)\n", func, id,
1081 _mesa_enum_to_string(pname));
1082
1083 if (id)
1084 q = _mesa_lookup_query_object(ctx, id);
1085
1086 if (!q || q->Active || !q->EverBound) {
1087 _mesa_error(ctx, GL_INVALID_OPERATION,
1088 "%s(id=%d is invalid or active)", func, id);
1089 return;
1090 }
1091
1092 /* From GL_EXT_occlusion_query_boolean spec:
1093 *
1094 * "Accepted by the <pname> parameter of GetQueryObjectivEXT and
1095 * GetQueryObjectuivEXT:
1096 *
1097 * QUERY_RESULT_EXT 0x8866
1098 * QUERY_RESULT_AVAILABLE_EXT 0x8867"
1099 *
1100 * Same rule is present also in ES 3.2 spec.
1101 */
1102 if (_mesa_is_gles(ctx) &&
1103 (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) {
1104 _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func,
1105 _mesa_enum_to_string(pname));
1106 return;
1107 }
1108
1109 if (buf) {
1110 bool is_64bit = ptype == GL_INT64_ARB ||
1111 ptype == GL_UNSIGNED_INT64_ARB;
1112 if (!_mesa_has_ARB_query_buffer_object(ctx)) {
1113 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func);
1114 return;
1115 }
1116 if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) {
1117 _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func);
1118 return;
1119 }
1120
1121 if (offset < 0) {
1122 _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func);
1123 return;
1124 }
1125
1126 switch (pname) {
1127 case GL_QUERY_RESULT:
1128 case GL_QUERY_RESULT_NO_WAIT:
1129 case GL_QUERY_RESULT_AVAILABLE:
1130 case GL_QUERY_TARGET:
1131 store_query_result(ctx, q, buf, offset, pname, ptype);
1132 return;
1133 }
1134
1135 /* fall through to get error below */
1136 }
1137
1138 switch (pname) {
1139 case GL_QUERY_RESULT:
1140 if (!q->Ready)
1141 _mesa_wait_query(ctx, q);
1142 value = q->Result;
1143 break;
1144 case GL_QUERY_RESULT_NO_WAIT:
1145 if (!_mesa_has_ARB_query_buffer_object(ctx))
1146 goto invalid_enum;
1147 _mesa_check_query(ctx, q);
1148 if (!q->Ready)
1149 return;
1150 value = q->Result;
1151 break;
1152 case GL_QUERY_RESULT_AVAILABLE:
1153 if (!q->Ready)
1154 _mesa_check_query(ctx, q);
1155 value = q->Ready;
1156 break;
1157 case GL_QUERY_TARGET:
1158 value = q->Target;
1159 break;
1160 default:
1161 invalid_enum:
1162 _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)",
1163 func, _mesa_enum_to_string(pname));
1164 return;
1165 }
1166
1167 switch (ptype) {
1168 case GL_INT: {
1169 GLint *param = (GLint *)offset;
1170 if (value > 0x7fffffff)
1171 *param = 0x7fffffff;
1172 else
1173 *param = value;
1174 break;
1175 }
1176 case GL_UNSIGNED_INT: {
1177 GLuint *param = (GLuint *)offset;
1178 if (value > 0xffffffff)
1179 *param = 0xffffffff;
1180 else
1181 *param = value;
1182 break;
1183 }
1184 case GL_INT64_ARB:
1185 case GL_UNSIGNED_INT64_ARB: {
1186 GLuint64EXT *param = (GLuint64EXT *)offset;
1187 *param = value;
1188 break;
1189 }
1190 default:
1191 unreachable("unexpected ptype");
1192 }
1193 }
1194
1195 void GLAPIENTRY
_mesa_GetQueryObjectiv(GLuint id,GLenum pname,GLint * params)1196 _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
1197 {
1198 GET_CURRENT_CONTEXT(ctx);
1199
1200 get_query_object(ctx, "glGetQueryObjectiv",
1201 id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params);
1202 }
1203
1204
1205 void GLAPIENTRY
_mesa_GetQueryObjectuiv(GLuint id,GLenum pname,GLuint * params)1206 _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
1207 {
1208 GET_CURRENT_CONTEXT(ctx);
1209
1210 get_query_object(ctx, "glGetQueryObjectuiv",
1211 id, pname, GL_UNSIGNED_INT,
1212 ctx->QueryBuffer, (intptr_t)params);
1213 }
1214
1215
1216 /**
1217 * New with GL_EXT_timer_query
1218 */
1219 void GLAPIENTRY
_mesa_GetQueryObjecti64v(GLuint id,GLenum pname,GLint64EXT * params)1220 _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
1221 {
1222 GET_CURRENT_CONTEXT(ctx);
1223
1224 get_query_object(ctx, "glGetQueryObjecti64v",
1225 id, pname, GL_INT64_ARB,
1226 ctx->QueryBuffer, (intptr_t)params);
1227 }
1228
1229
1230 /**
1231 * New with GL_EXT_timer_query
1232 */
1233 void GLAPIENTRY
_mesa_GetQueryObjectui64v(GLuint id,GLenum pname,GLuint64EXT * params)1234 _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
1235 {
1236 GET_CURRENT_CONTEXT(ctx);
1237
1238 get_query_object(ctx, "glGetQueryObjectui64v",
1239 id, pname, GL_UNSIGNED_INT64_ARB,
1240 ctx->QueryBuffer, (intptr_t)params);
1241 }
1242
1243 /**
1244 * New with GL_ARB_query_buffer_object
1245 */
1246 void GLAPIENTRY
_mesa_GetQueryBufferObjectiv(GLuint id,GLuint buffer,GLenum pname,GLintptr offset)1247 _mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
1248 GLintptr offset)
1249 {
1250 struct gl_buffer_object *buf;
1251 GET_CURRENT_CONTEXT(ctx);
1252
1253 buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv");
1254 if (!buf)
1255 return;
1256
1257 get_query_object(ctx, "glGetQueryBufferObjectiv",
1258 id, pname, GL_INT, buf, offset);
1259 }
1260
1261
1262 void GLAPIENTRY
_mesa_GetQueryBufferObjectuiv(GLuint id,GLuint buffer,GLenum pname,GLintptr offset)1263 _mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
1264 GLintptr offset)
1265 {
1266 struct gl_buffer_object *buf;
1267 GET_CURRENT_CONTEXT(ctx);
1268
1269 buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv");
1270 if (!buf)
1271 return;
1272
1273 get_query_object(ctx, "glGetQueryBufferObjectuiv",
1274 id, pname, GL_UNSIGNED_INT, buf, offset);
1275 }
1276
1277
1278 void GLAPIENTRY
_mesa_GetQueryBufferObjecti64v(GLuint id,GLuint buffer,GLenum pname,GLintptr offset)1279 _mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
1280 GLintptr offset)
1281 {
1282 struct gl_buffer_object *buf;
1283 GET_CURRENT_CONTEXT(ctx);
1284
1285 buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v");
1286 if (!buf)
1287 return;
1288
1289 get_query_object(ctx, "glGetQueryBufferObjecti64v",
1290 id, pname, GL_INT64_ARB, buf, offset);
1291 }
1292
1293
1294 void GLAPIENTRY
_mesa_GetQueryBufferObjectui64v(GLuint id,GLuint buffer,GLenum pname,GLintptr offset)1295 _mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
1296 GLintptr offset)
1297 {
1298 struct gl_buffer_object *buf;
1299 GET_CURRENT_CONTEXT(ctx);
1300
1301 buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v");
1302 if (!buf)
1303 return;
1304
1305 get_query_object(ctx, "glGetQueryBufferObjectui64v",
1306 id, pname, GL_UNSIGNED_INT64_ARB, buf, offset);
1307 }
1308
1309
1310 /**
1311 * Allocate/init the context state related to query objects.
1312 */
1313 void
_mesa_init_queryobj(struct gl_context * ctx)1314 _mesa_init_queryobj(struct gl_context *ctx)
1315 {
1316 struct pipe_screen *screen = ctx->pipe->screen;
1317
1318 ctx->Query.QueryObjects = _mesa_NewHashTable();
1319 ctx->Query.CurrentOcclusionObject = NULL;
1320
1321 if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY))
1322 ctx->Const.QueryCounterBits.SamplesPassed = 64;
1323 else
1324 ctx->Const.QueryCounterBits.SamplesPassed = 0;
1325
1326 ctx->Const.QueryCounterBits.TimeElapsed = 64;
1327 ctx->Const.QueryCounterBits.Timestamp = 64;
1328 ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
1329 ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
1330
1331 ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
1332 ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
1333 ctx->Const.QueryCounterBits.VsInvocations = 64;
1334 ctx->Const.QueryCounterBits.TessPatches = 64;
1335 ctx->Const.QueryCounterBits.TessInvocations = 64;
1336 ctx->Const.QueryCounterBits.GsInvocations = 64;
1337 ctx->Const.QueryCounterBits.GsPrimitives = 64;
1338 ctx->Const.QueryCounterBits.FsInvocations = 64;
1339 ctx->Const.QueryCounterBits.ComputeInvocations = 64;
1340 ctx->Const.QueryCounterBits.ClInPrimitives = 64;
1341 ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
1342 }
1343
1344
1345 /**
1346 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
1347 */
1348 static void
delete_queryobj_cb(void * data,void * userData)1349 delete_queryobj_cb(void *data, void *userData)
1350 {
1351 struct gl_query_object *q= (struct gl_query_object *) data;
1352 struct gl_context *ctx = (struct gl_context *)userData;
1353 delete_query(ctx, q);
1354 }
1355
1356
1357 /**
1358 * Free the context state related to query objects.
1359 */
1360 void
_mesa_free_queryobj_data(struct gl_context * ctx)1361 _mesa_free_queryobj_data(struct gl_context *ctx)
1362 {
1363 _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
1364 _mesa_DeleteHashTable(ctx->Query.QueryObjects);
1365 }
1366