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