932359c4e7f2539b3ebb2bb758e6ace46f1f2b85
[mesa.git] / src / mesa / main / queryobj.c
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 "glheader.h"
27 #include "context.h"
28 #include "enums.h"
29 #include "hash.h"
30 #include "imports.h"
31 #include "queryobj.h"
32 #include "mtypes.h"
33 #include "main/dispatch.h"
34
35
36 /**
37 * Allocate a new query object. This is a fallback routine called via
38 * ctx->Driver.NewQueryObject().
39 * \param ctx - rendering context
40 * \param id - the new object's ID
41 * \return pointer to new query_object object or NULL if out of memory.
42 */
43 static struct gl_query_object *
44 _mesa_new_query_object(struct gl_context *ctx, GLuint id)
45 {
46 struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
47 (void) ctx;
48 if (q) {
49 q->Id = id;
50 q->Result = 0;
51 q->Active = GL_FALSE;
52
53 /* This is to satisfy the language of the specification: "In the initial
54 * state of a query object, the result is available" (OpenGL 3.1 §
55 * 2.13).
56 */
57 q->Ready = GL_TRUE;
58
59 /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as
60 * used, but no object is associated with them until the first time they
61 * are used by BeginQuery." Since our implementation actually does
62 * allocate an object at this point, use a flag to indicate that this
63 * object has not yet been bound so should not be considered a query.
64 */
65 q->EverBound = GL_FALSE;
66 }
67 return q;
68 }
69
70
71 /**
72 * Begin a query. Software driver fallback.
73 * Called via ctx->Driver.BeginQuery().
74 */
75 static void
76 _mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
77 {
78 ctx->NewState |= _NEW_DEPTH; /* for swrast */
79 }
80
81
82 /**
83 * End a query. Software driver fallback.
84 * Called via ctx->Driver.EndQuery().
85 */
86 static void
87 _mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
88 {
89 ctx->NewState |= _NEW_DEPTH; /* for swrast */
90 q->Ready = GL_TRUE;
91 }
92
93
94 /**
95 * Wait for query to complete. Software driver fallback.
96 * Called via ctx->Driver.WaitQuery().
97 */
98 static void
99 _mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
100 {
101 /* For software drivers, _mesa_end_query() should have completed the query.
102 * For real hardware, implement a proper WaitQuery() driver function,
103 * which may require issuing a flush.
104 */
105 assert(q->Ready);
106 }
107
108
109 /**
110 * Check if a query results are ready. Software driver fallback.
111 * Called via ctx->Driver.CheckQuery().
112 */
113 static void
114 _mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
115 {
116 /* No-op for sw rendering.
117 * HW drivers may need to flush at this time.
118 */
119 }
120
121
122 /**
123 * Delete a query object. Called via ctx->Driver.DeleteQuery().
124 * Not removed from hash table here.
125 */
126 static void
127 _mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
128 {
129 free(q->Label);
130 free(q);
131 }
132
133
134 void
135 _mesa_init_query_object_functions(struct dd_function_table *driver)
136 {
137 driver->NewQueryObject = _mesa_new_query_object;
138 driver->DeleteQuery = _mesa_delete_query;
139 driver->BeginQuery = _mesa_begin_query;
140 driver->EndQuery = _mesa_end_query;
141 driver->WaitQuery = _mesa_wait_query;
142 driver->CheckQuery = _mesa_check_query;
143 }
144
145
146 /**
147 * Return pointer to the query object binding point for the given target and
148 * index.
149 * \return NULL if invalid target, else the address of binding point
150 */
151 static struct gl_query_object **
152 get_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
153 {
154 switch (target) {
155 case GL_SAMPLES_PASSED_ARB:
156 if (ctx->Extensions.ARB_occlusion_query)
157 return &ctx->Query.CurrentOcclusionObject;
158 else
159 return NULL;
160 case GL_ANY_SAMPLES_PASSED:
161 if (ctx->Extensions.ARB_occlusion_query2)
162 return &ctx->Query.CurrentOcclusionObject;
163 else
164 return NULL;
165 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
166 if (ctx->Extensions.ARB_ES3_compatibility
167 || (ctx->API == API_OPENGLES2 && ctx->Version >= 30))
168 return &ctx->Query.CurrentOcclusionObject;
169 else
170 return NULL;
171 case GL_TIME_ELAPSED_EXT:
172 if (ctx->Extensions.EXT_timer_query)
173 return &ctx->Query.CurrentTimerObject;
174 else
175 return NULL;
176 case GL_PRIMITIVES_GENERATED:
177 if (ctx->Extensions.EXT_transform_feedback)
178 return &ctx->Query.PrimitivesGenerated[index];
179 else
180 return NULL;
181 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
182 if (ctx->Extensions.EXT_transform_feedback)
183 return &ctx->Query.PrimitivesWritten[index];
184 else
185 return NULL;
186 default:
187 return NULL;
188 }
189 }
190
191
192 void GLAPIENTRY
193 _mesa_GenQueries(GLsizei n, GLuint *ids)
194 {
195 GLuint first;
196 GET_CURRENT_CONTEXT(ctx);
197
198 if (MESA_VERBOSE & VERBOSE_API)
199 _mesa_debug(ctx, "glGenQueries(%d)\n", n);
200
201 if (n < 0) {
202 _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
203 return;
204 }
205
206 first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
207 if (first) {
208 GLsizei i;
209 for (i = 0; i < n; i++) {
210 struct gl_query_object *q
211 = ctx->Driver.NewQueryObject(ctx, first + i);
212 if (!q) {
213 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
214 return;
215 }
216 ids[i] = first + i;
217 _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
218 }
219 }
220 }
221
222
223 void GLAPIENTRY
224 _mesa_DeleteQueries(GLsizei n, const GLuint *ids)
225 {
226 GLint i;
227 GET_CURRENT_CONTEXT(ctx);
228 FLUSH_VERTICES(ctx, 0);
229
230 if (MESA_VERBOSE & VERBOSE_API)
231 _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
232
233 if (n < 0) {
234 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
235 return;
236 }
237
238 for (i = 0; i < n; i++) {
239 if (ids[i] > 0) {
240 struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
241 if (q) {
242 if (q->Active) {
243 struct gl_query_object **bindpt;
244 bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
245 assert(bindpt); /* Should be non-null for active q. */
246 if (bindpt) {
247 *bindpt = NULL;
248 }
249 q->Active = GL_FALSE;
250 ctx->Driver.EndQuery(ctx, q);
251 }
252 _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
253 ctx->Driver.DeleteQuery(ctx, q);
254 }
255 }
256 }
257 }
258
259
260 GLboolean GLAPIENTRY
261 _mesa_IsQuery(GLuint id)
262 {
263 struct gl_query_object *q;
264
265 GET_CURRENT_CONTEXT(ctx);
266 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
267
268 if (MESA_VERBOSE & VERBOSE_API)
269 _mesa_debug(ctx, "glIsQuery(%u)\n", id);
270
271 if (id == 0)
272 return GL_FALSE;
273
274 q = _mesa_lookup_query_object(ctx, id);
275 if (q == NULL)
276 return GL_FALSE;
277
278 return q->EverBound;
279 }
280
281 static GLboolean
282 query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
283 {
284 switch (target) {
285 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
286 case GL_PRIMITIVES_GENERATED:
287 if (index >= ctx->Const.MaxVertexStreams) {
288 _mesa_error(ctx, GL_INVALID_VALUE,
289 "glBeginQueryIndexed(index>=MaxVertexStreams)");
290 return GL_FALSE;
291 }
292 break;
293 default:
294 if (index > 0) {
295 _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
296 return GL_FALSE;
297 }
298 }
299 return GL_TRUE;
300 }
301
302 void GLAPIENTRY
303 _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
304 {
305 struct gl_query_object *q, **bindpt;
306 GET_CURRENT_CONTEXT(ctx);
307
308 if (MESA_VERBOSE & VERBOSE_API)
309 _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
310 _mesa_lookup_enum_by_nr(target), index, id);
311
312 if (!query_error_check_index(ctx, target, index))
313 return;
314
315 FLUSH_VERTICES(ctx, 0);
316
317 bindpt = get_query_binding_point(ctx, target, index);
318 if (!bindpt) {
319 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
320 return;
321 }
322
323 /* From the GL_ARB_occlusion_query spec:
324 *
325 * "If BeginQueryARB is called while another query is already in
326 * progress with the same target, an INVALID_OPERATION error is
327 * generated."
328 */
329 if (*bindpt) {
330 _mesa_error(ctx, GL_INVALID_OPERATION,
331 "glBeginQuery{Indexed}(target=%s is active)",
332 _mesa_lookup_enum_by_nr(target));
333 return;
334 }
335
336 if (id == 0) {
337 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
338 return;
339 }
340
341 q = _mesa_lookup_query_object(ctx, id);
342 if (!q) {
343 if (ctx->API != API_OPENGL_COMPAT) {
344 _mesa_error(ctx, GL_INVALID_OPERATION,
345 "glBeginQuery{Indexed}(non-gen name)");
346 return;
347 } else {
348 /* create new object */
349 q = ctx->Driver.NewQueryObject(ctx, id);
350 if (!q) {
351 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
352 return;
353 }
354 _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
355 }
356 }
357 else {
358 /* pre-existing object */
359 if (q->Active) {
360 _mesa_error(ctx, GL_INVALID_OPERATION,
361 "glBeginQuery{Indexed}(query already active)");
362 return;
363 }
364 }
365
366 q->Target = target;
367 q->Active = GL_TRUE;
368 q->Result = 0;
369 q->Ready = GL_FALSE;
370 q->EverBound = GL_TRUE;
371 q->Stream = index;
372
373 /* XXX should probably refcount query objects */
374 *bindpt = q;
375
376 ctx->Driver.BeginQuery(ctx, q);
377 }
378
379
380 void GLAPIENTRY
381 _mesa_EndQueryIndexed(GLenum target, GLuint index)
382 {
383 struct gl_query_object *q, **bindpt;
384 GET_CURRENT_CONTEXT(ctx);
385
386 if (MESA_VERBOSE & VERBOSE_API)
387 _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
388 _mesa_lookup_enum_by_nr(target), index);
389
390 if (!query_error_check_index(ctx, target, index))
391 return;
392
393 FLUSH_VERTICES(ctx, 0);
394
395 bindpt = get_query_binding_point(ctx, target, index);
396 if (!bindpt) {
397 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
398 return;
399 }
400
401 /* XXX should probably refcount query objects */
402 q = *bindpt;
403
404 /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
405 if (q && q->Target != target) {
406 _mesa_error(ctx, GL_INVALID_OPERATION,
407 "glEndQuery(target=%s with active query of target %s)",
408 _mesa_lookup_enum_by_nr(target),
409 _mesa_lookup_enum_by_nr(q->Target));
410 return;
411 }
412
413 *bindpt = NULL;
414
415 if (!q || !q->Active) {
416 _mesa_error(ctx, GL_INVALID_OPERATION,
417 "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
418 return;
419 }
420
421 q->Active = GL_FALSE;
422 ctx->Driver.EndQuery(ctx, q);
423 }
424
425 void GLAPIENTRY
426 _mesa_BeginQuery(GLenum target, GLuint id)
427 {
428 _mesa_BeginQueryIndexed(target, 0, id);
429 }
430
431 void GLAPIENTRY
432 _mesa_EndQuery(GLenum target)
433 {
434 _mesa_EndQueryIndexed(target, 0);
435 }
436
437 void GLAPIENTRY
438 _mesa_QueryCounter(GLuint id, GLenum target)
439 {
440 struct gl_query_object *q;
441 GET_CURRENT_CONTEXT(ctx);
442
443 if (MESA_VERBOSE & VERBOSE_API)
444 _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
445 _mesa_lookup_enum_by_nr(target));
446
447 /* error checking */
448 if (target != GL_TIMESTAMP) {
449 _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
450 return;
451 }
452
453 if (id == 0) {
454 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
455 return;
456 }
457
458 q = _mesa_lookup_query_object(ctx, id);
459 if (!q) {
460 /* XXX the Core profile should throw INVALID_OPERATION here */
461
462 /* create new object */
463 q = ctx->Driver.NewQueryObject(ctx, id);
464 if (!q) {
465 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
466 return;
467 }
468 _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
469 }
470 else {
471 if (q->Target && q->Target != GL_TIMESTAMP) {
472 _mesa_error(ctx, GL_INVALID_OPERATION,
473 "glQueryCounter(id has an invalid target)");
474 return;
475 }
476 }
477
478 if (q->Active) {
479 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
480 return;
481 }
482
483 q->Target = target;
484 q->Result = 0;
485 q->Ready = GL_FALSE;
486 q->EverBound = GL_TRUE;
487
488 if (ctx->Driver.QueryCounter) {
489 ctx->Driver.QueryCounter(ctx, q);
490 } else {
491 /* QueryCounter is implemented using EndQuery without BeginQuery
492 * in drivers. This is actually Direct3D and Gallium convention.
493 */
494 ctx->Driver.EndQuery(ctx, q);
495 }
496 }
497
498
499 void GLAPIENTRY
500 _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
501 GLint *params)
502 {
503 struct gl_query_object *q = NULL, **bindpt = NULL;
504 GET_CURRENT_CONTEXT(ctx);
505
506 if (MESA_VERBOSE & VERBOSE_API)
507 _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
508 _mesa_lookup_enum_by_nr(target),
509 index,
510 _mesa_lookup_enum_by_nr(pname));
511
512 if (!query_error_check_index(ctx, target, index))
513 return;
514
515 if (target == GL_TIMESTAMP) {
516 if (!ctx->Extensions.ARB_timer_query) {
517 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
518 return;
519 }
520 }
521 else {
522 bindpt = get_query_binding_point(ctx, target, index);
523 if (!bindpt) {
524 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
525 return;
526 }
527
528 q = *bindpt;
529 }
530
531 switch (pname) {
532 case GL_QUERY_COUNTER_BITS_ARB:
533 switch (target) {
534 case GL_SAMPLES_PASSED:
535 *params = ctx->Const.QueryCounterBits.SamplesPassed;
536 break;
537 case GL_ANY_SAMPLES_PASSED:
538 /* The minimum value of this is 1 if it's nonzero, and the value
539 * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
540 * bits.
541 */
542 *params = 1;
543 break;
544 case GL_TIME_ELAPSED:
545 *params = ctx->Const.QueryCounterBits.TimeElapsed;
546 break;
547 case GL_TIMESTAMP:
548 *params = ctx->Const.QueryCounterBits.Timestamp;
549 break;
550 case GL_PRIMITIVES_GENERATED:
551 *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
552 break;
553 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
554 *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
555 break;
556 default:
557 _mesa_problem(ctx,
558 "Unknown target in glGetQueryIndexediv(target = %s)",
559 _mesa_lookup_enum_by_nr(target));
560 *params = 0;
561 break;
562 }
563 break;
564 case GL_CURRENT_QUERY_ARB:
565 *params = (q && q->Target == target) ? q->Id : 0;
566 break;
567 default:
568 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
569 return;
570 }
571 }
572
573 void GLAPIENTRY
574 _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
575 {
576 _mesa_GetQueryIndexediv(target, 0, pname, params);
577 }
578
579 void GLAPIENTRY
580 _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
581 {
582 struct gl_query_object *q = NULL;
583 GET_CURRENT_CONTEXT(ctx);
584
585 if (MESA_VERBOSE & VERBOSE_API)
586 _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
587 _mesa_lookup_enum_by_nr(pname));
588
589 if (id)
590 q = _mesa_lookup_query_object(ctx, id);
591
592 if (!q || q->Active) {
593 _mesa_error(ctx, GL_INVALID_OPERATION,
594 "glGetQueryObjectivARB(id=%d is invalid or active)", id);
595 return;
596 }
597
598 switch (pname) {
599 case GL_QUERY_RESULT_ARB:
600 if (!q->Ready)
601 ctx->Driver.WaitQuery(ctx, q);
602 /* if result is too large for returned type, clamp to max value */
603 if (q->Target == GL_ANY_SAMPLES_PASSED
604 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
605 if (q->Result)
606 *params = GL_TRUE;
607 else
608 *params = GL_FALSE;
609 } else {
610 if (q->Result > 0x7fffffff) {
611 *params = 0x7fffffff;
612 }
613 else {
614 *params = (GLint)q->Result;
615 }
616 }
617 break;
618 case GL_QUERY_RESULT_AVAILABLE_ARB:
619 if (!q->Ready)
620 ctx->Driver.CheckQuery( ctx, q );
621 *params = q->Ready;
622 break;
623 default:
624 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
625 return;
626 }
627 }
628
629
630 void GLAPIENTRY
631 _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
632 {
633 struct gl_query_object *q = NULL;
634 GET_CURRENT_CONTEXT(ctx);
635
636 if (MESA_VERBOSE & VERBOSE_API)
637 _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
638 _mesa_lookup_enum_by_nr(pname));
639
640 if (id)
641 q = _mesa_lookup_query_object(ctx, id);
642
643 if (!q || q->Active) {
644 _mesa_error(ctx, GL_INVALID_OPERATION,
645 "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
646 return;
647 }
648
649 switch (pname) {
650 case GL_QUERY_RESULT_ARB:
651 if (!q->Ready)
652 ctx->Driver.WaitQuery(ctx, q);
653 /* if result is too large for returned type, clamp to max value */
654 if (q->Target == GL_ANY_SAMPLES_PASSED
655 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
656 if (q->Result)
657 *params = GL_TRUE;
658 else
659 *params = GL_FALSE;
660 } else {
661 if (q->Result > 0xffffffff) {
662 *params = 0xffffffff;
663 }
664 else {
665 *params = (GLuint)q->Result;
666 }
667 }
668 break;
669 case GL_QUERY_RESULT_AVAILABLE_ARB:
670 if (!q->Ready)
671 ctx->Driver.CheckQuery( ctx, q );
672 *params = q->Ready;
673 break;
674 default:
675 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
676 return;
677 }
678 }
679
680
681 /**
682 * New with GL_EXT_timer_query
683 */
684 void GLAPIENTRY
685 _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
686 {
687 struct gl_query_object *q = NULL;
688 GET_CURRENT_CONTEXT(ctx);
689
690 if (MESA_VERBOSE & VERBOSE_API)
691 _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
692 _mesa_lookup_enum_by_nr(pname));
693
694 if (id)
695 q = _mesa_lookup_query_object(ctx, id);
696
697 if (!q || q->Active) {
698 _mesa_error(ctx, GL_INVALID_OPERATION,
699 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
700 return;
701 }
702
703 switch (pname) {
704 case GL_QUERY_RESULT_ARB:
705 if (!q->Ready)
706 ctx->Driver.WaitQuery(ctx, q);
707 *params = q->Result;
708 break;
709 case GL_QUERY_RESULT_AVAILABLE_ARB:
710 if (!q->Ready)
711 ctx->Driver.CheckQuery( ctx, q );
712 *params = q->Ready;
713 break;
714 default:
715 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
716 return;
717 }
718 }
719
720
721 /**
722 * New with GL_EXT_timer_query
723 */
724 void GLAPIENTRY
725 _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
726 {
727 struct gl_query_object *q = NULL;
728 GET_CURRENT_CONTEXT(ctx);
729
730 if (MESA_VERBOSE & VERBOSE_API)
731 _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
732 _mesa_lookup_enum_by_nr(pname));
733
734 if (id)
735 q = _mesa_lookup_query_object(ctx, id);
736
737 if (!q || q->Active) {
738 _mesa_error(ctx, GL_INVALID_OPERATION,
739 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
740 return;
741 }
742
743 switch (pname) {
744 case GL_QUERY_RESULT_ARB:
745 if (!q->Ready)
746 ctx->Driver.WaitQuery(ctx, q);
747 *params = q->Result;
748 break;
749 case GL_QUERY_RESULT_AVAILABLE_ARB:
750 if (!q->Ready)
751 ctx->Driver.CheckQuery( ctx, q );
752 *params = q->Ready;
753 break;
754 default:
755 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
756 return;
757 }
758 }
759
760 /**
761 * Allocate/init the context state related to query objects.
762 */
763 void
764 _mesa_init_queryobj(struct gl_context *ctx)
765 {
766 ctx->Query.QueryObjects = _mesa_NewHashTable();
767 ctx->Query.CurrentOcclusionObject = NULL;
768
769 ctx->Const.QueryCounterBits.SamplesPassed = 64;
770 ctx->Const.QueryCounterBits.TimeElapsed = 64;
771 ctx->Const.QueryCounterBits.Timestamp = 64;
772 ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
773 ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
774 }
775
776
777 /**
778 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
779 */
780 static void
781 delete_queryobj_cb(GLuint id, void *data, void *userData)
782 {
783 struct gl_query_object *q= (struct gl_query_object *) data;
784 struct gl_context *ctx = (struct gl_context *)userData;
785 ctx->Driver.DeleteQuery(ctx, q);
786 }
787
788
789 /**
790 * Free the context state related to query objects.
791 */
792 void
793 _mesa_free_queryobj_data(struct gl_context *ctx)
794 {
795 _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
796 _mesa_DeleteHashTable(ctx->Query.QueryObjects);
797 }