Remove error when calling glGenQueries/glDeleteQueries while a query is active
[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.
148 * \return NULL if invalid target, else the address of binding point
149 */
150 static struct gl_query_object **
151 get_query_binding_point(struct gl_context *ctx, GLenum target)
152 {
153 switch (target) {
154 case GL_SAMPLES_PASSED_ARB:
155 if (ctx->Extensions.ARB_occlusion_query)
156 return &ctx->Query.CurrentOcclusionObject;
157 else
158 return NULL;
159 case GL_ANY_SAMPLES_PASSED:
160 if (ctx->Extensions.ARB_occlusion_query2)
161 return &ctx->Query.CurrentOcclusionObject;
162 else
163 return NULL;
164 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
165 if (ctx->Extensions.ARB_ES3_compatibility
166 || (ctx->API == API_OPENGLES2 && ctx->Version >= 30))
167 return &ctx->Query.CurrentOcclusionObject;
168 else
169 return NULL;
170 case GL_TIME_ELAPSED_EXT:
171 if (ctx->Extensions.EXT_timer_query)
172 return &ctx->Query.CurrentTimerObject;
173 else
174 return NULL;
175 case GL_PRIMITIVES_GENERATED:
176 if (ctx->Extensions.EXT_transform_feedback)
177 return &ctx->Query.PrimitivesGenerated;
178 else
179 return NULL;
180 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
181 if (ctx->Extensions.EXT_transform_feedback)
182 return &ctx->Query.PrimitivesWritten;
183 else
184 return NULL;
185 default:
186 return NULL;
187 }
188 }
189
190
191 void GLAPIENTRY
192 _mesa_GenQueries(GLsizei n, GLuint *ids)
193 {
194 GLuint first;
195 GET_CURRENT_CONTEXT(ctx);
196
197 if (MESA_VERBOSE & VERBOSE_API)
198 _mesa_debug(ctx, "glGenQueries(%d)\n", n);
199
200 if (n < 0) {
201 _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
202 return;
203 }
204
205 first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
206 if (first) {
207 GLsizei i;
208 for (i = 0; i < n; i++) {
209 struct gl_query_object *q
210 = ctx->Driver.NewQueryObject(ctx, first + i);
211 if (!q) {
212 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
213 return;
214 }
215 ids[i] = first + i;
216 _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
217 }
218 }
219 }
220
221
222 void GLAPIENTRY
223 _mesa_DeleteQueries(GLsizei n, const GLuint *ids)
224 {
225 GLint i;
226 GET_CURRENT_CONTEXT(ctx);
227 FLUSH_VERTICES(ctx, 0);
228
229 if (MESA_VERBOSE & VERBOSE_API)
230 _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
231
232 if (n < 0) {
233 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
234 return;
235 }
236
237 for (i = 0; i < n; i++) {
238 if (ids[i] > 0) {
239 struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
240 if (q) {
241 if (q->Active) {
242 struct gl_query_object **bindpt;
243 bindpt = get_query_binding_point(ctx, q->Target);
244 assert(bindpt); /* Should be non-null for active q. */
245 if (bindpt) {
246 *bindpt = NULL;
247 }
248 q->Active = GL_FALSE;
249 ctx->Driver.EndQuery(ctx, q);
250 }
251 _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
252 ctx->Driver.DeleteQuery(ctx, q);
253 }
254 }
255 }
256 }
257
258
259 GLboolean GLAPIENTRY
260 _mesa_IsQuery(GLuint id)
261 {
262 struct gl_query_object *q;
263
264 GET_CURRENT_CONTEXT(ctx);
265 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
266
267 if (MESA_VERBOSE & VERBOSE_API)
268 _mesa_debug(ctx, "glIsQuery(%u)\n", id);
269
270 if (id == 0)
271 return GL_FALSE;
272
273 q = _mesa_lookup_query_object(ctx, id);
274 if (q == NULL)
275 return GL_FALSE;
276
277 return q->EverBound;
278 }
279
280 static GLboolean
281 query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
282 {
283 switch (target) {
284 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
285 case GL_PRIMITIVES_GENERATED:
286 if (index >= ctx->Const.MaxVertexStreams) {
287 _mesa_error(ctx, GL_INVALID_VALUE,
288 "glBeginQueryIndexed(index>=MaxVertexStreams)");
289 return GL_FALSE;
290 }
291 break;
292 default:
293 if (index > 0) {
294 _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
295 return GL_FALSE;
296 }
297 }
298 return GL_TRUE;
299 }
300
301 void GLAPIENTRY
302 _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
303 {
304 struct gl_query_object *q, **bindpt;
305 GET_CURRENT_CONTEXT(ctx);
306
307 if (MESA_VERBOSE & VERBOSE_API)
308 _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
309 _mesa_lookup_enum_by_nr(target), index, id);
310
311 if (!query_error_check_index(ctx, target, index))
312 return;
313
314 FLUSH_VERTICES(ctx, 0);
315
316 bindpt = get_query_binding_point(ctx, target);
317 if (!bindpt) {
318 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
319 return;
320 }
321
322 /* From the GL_ARB_occlusion_query spec:
323 *
324 * "If BeginQueryARB is called while another query is already in
325 * progress with the same target, an INVALID_OPERATION error is
326 * generated."
327 */
328 if (*bindpt) {
329 _mesa_error(ctx, GL_INVALID_OPERATION,
330 "glBeginQuery{Indexed}(target=%s is active)",
331 _mesa_lookup_enum_by_nr(target));
332 return;
333 }
334
335 if (id == 0) {
336 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
337 return;
338 }
339
340 q = _mesa_lookup_query_object(ctx, id);
341 if (!q) {
342 if (ctx->API != API_OPENGL_COMPAT) {
343 _mesa_error(ctx, GL_INVALID_OPERATION,
344 "glBeginQuery{Indexed}(non-gen name)");
345 return;
346 } else {
347 /* create new object */
348 q = ctx->Driver.NewQueryObject(ctx, id);
349 if (!q) {
350 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
351 return;
352 }
353 _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
354 }
355 }
356 else {
357 /* pre-existing object */
358 if (q->Active) {
359 _mesa_error(ctx, GL_INVALID_OPERATION,
360 "glBeginQuery{Indexed}(query already active)");
361 return;
362 }
363 }
364
365 q->Target = target;
366 q->Active = GL_TRUE;
367 q->Result = 0;
368 q->Ready = GL_FALSE;
369 q->EverBound = GL_TRUE;
370
371 /* XXX should probably refcount query objects */
372 *bindpt = q;
373
374 ctx->Driver.BeginQuery(ctx, q);
375 }
376
377
378 void GLAPIENTRY
379 _mesa_EndQueryIndexed(GLenum target, GLuint index)
380 {
381 struct gl_query_object *q, **bindpt;
382 GET_CURRENT_CONTEXT(ctx);
383
384 if (MESA_VERBOSE & VERBOSE_API)
385 _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
386 _mesa_lookup_enum_by_nr(target), index);
387
388 if (!query_error_check_index(ctx, target, index))
389 return;
390
391 FLUSH_VERTICES(ctx, 0);
392
393 bindpt = get_query_binding_point(ctx, target);
394 if (!bindpt) {
395 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
396 return;
397 }
398
399 /* XXX should probably refcount query objects */
400 q = *bindpt;
401
402 /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
403 if (q && q->Target != target) {
404 _mesa_error(ctx, GL_INVALID_OPERATION,
405 "glEndQuery(target=%s with active query of target %s)",
406 _mesa_lookup_enum_by_nr(target),
407 _mesa_lookup_enum_by_nr(q->Target));
408 return;
409 }
410
411 *bindpt = NULL;
412
413 if (!q || !q->Active) {
414 _mesa_error(ctx, GL_INVALID_OPERATION,
415 "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
416 return;
417 }
418
419 q->Active = GL_FALSE;
420 ctx->Driver.EndQuery(ctx, q);
421 }
422
423 void GLAPIENTRY
424 _mesa_BeginQuery(GLenum target, GLuint id)
425 {
426 _mesa_BeginQueryIndexed(target, 0, id);
427 }
428
429 void GLAPIENTRY
430 _mesa_EndQuery(GLenum target)
431 {
432 _mesa_EndQueryIndexed(target, 0);
433 }
434
435 void GLAPIENTRY
436 _mesa_QueryCounter(GLuint id, GLenum target)
437 {
438 struct gl_query_object *q;
439 GET_CURRENT_CONTEXT(ctx);
440
441 if (MESA_VERBOSE & VERBOSE_API)
442 _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
443 _mesa_lookup_enum_by_nr(target));
444
445 /* error checking */
446 if (target != GL_TIMESTAMP) {
447 _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
448 return;
449 }
450
451 if (id == 0) {
452 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
453 return;
454 }
455
456 q = _mesa_lookup_query_object(ctx, id);
457 if (!q) {
458 /* XXX the Core profile should throw INVALID_OPERATION here */
459
460 /* create new object */
461 q = ctx->Driver.NewQueryObject(ctx, id);
462 if (!q) {
463 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
464 return;
465 }
466 _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
467 }
468 else {
469 if (q->Target && q->Target != GL_TIMESTAMP) {
470 _mesa_error(ctx, GL_INVALID_OPERATION,
471 "glQueryCounter(id has an invalid target)");
472 return;
473 }
474 }
475
476 if (q->Active) {
477 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
478 return;
479 }
480
481 q->Target = target;
482 q->Result = 0;
483 q->Ready = GL_FALSE;
484 q->EverBound = GL_TRUE;
485
486 if (ctx->Driver.QueryCounter) {
487 ctx->Driver.QueryCounter(ctx, q);
488 } else {
489 /* QueryCounter is implemented using EndQuery without BeginQuery
490 * in drivers. This is actually Direct3D and Gallium convention.
491 */
492 ctx->Driver.EndQuery(ctx, q);
493 }
494 }
495
496
497 void GLAPIENTRY
498 _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
499 GLint *params)
500 {
501 struct gl_query_object *q = NULL, **bindpt = NULL;
502 GET_CURRENT_CONTEXT(ctx);
503
504 if (MESA_VERBOSE & VERBOSE_API)
505 _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
506 _mesa_lookup_enum_by_nr(target),
507 index,
508 _mesa_lookup_enum_by_nr(pname));
509
510 if (!query_error_check_index(ctx, target, index))
511 return;
512
513 if (target == GL_TIMESTAMP) {
514 if (!ctx->Extensions.ARB_timer_query) {
515 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
516 return;
517 }
518 }
519 else {
520 bindpt = get_query_binding_point(ctx, target);
521 if (!bindpt) {
522 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
523 return;
524 }
525
526 q = *bindpt;
527 }
528
529 switch (pname) {
530 case GL_QUERY_COUNTER_BITS_ARB:
531 switch (target) {
532 case GL_SAMPLES_PASSED:
533 *params = ctx->Const.QueryCounterBits.SamplesPassed;
534 break;
535 case GL_ANY_SAMPLES_PASSED:
536 /* The minimum value of this is 1 if it's nonzero, and the value
537 * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
538 * bits.
539 */
540 *params = 1;
541 break;
542 case GL_TIME_ELAPSED:
543 *params = ctx->Const.QueryCounterBits.TimeElapsed;
544 break;
545 case GL_TIMESTAMP:
546 *params = ctx->Const.QueryCounterBits.Timestamp;
547 break;
548 case GL_PRIMITIVES_GENERATED:
549 *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
550 break;
551 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
552 *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
553 break;
554 default:
555 _mesa_problem(ctx,
556 "Unknown target in glGetQueryIndexediv(target = %s)",
557 _mesa_lookup_enum_by_nr(target));
558 *params = 0;
559 break;
560 }
561 break;
562 case GL_CURRENT_QUERY_ARB:
563 *params = (q && q->Target == target) ? q->Id : 0;
564 break;
565 default:
566 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
567 return;
568 }
569 }
570
571 void GLAPIENTRY
572 _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
573 {
574 _mesa_GetQueryIndexediv(target, 0, pname, params);
575 }
576
577 void GLAPIENTRY
578 _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
579 {
580 struct gl_query_object *q = NULL;
581 GET_CURRENT_CONTEXT(ctx);
582
583 if (MESA_VERBOSE & VERBOSE_API)
584 _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
585 _mesa_lookup_enum_by_nr(pname));
586
587 if (id)
588 q = _mesa_lookup_query_object(ctx, id);
589
590 if (!q || q->Active) {
591 _mesa_error(ctx, GL_INVALID_OPERATION,
592 "glGetQueryObjectivARB(id=%d is invalid or active)", id);
593 return;
594 }
595
596 switch (pname) {
597 case GL_QUERY_RESULT_ARB:
598 if (!q->Ready)
599 ctx->Driver.WaitQuery(ctx, q);
600 /* if result is too large for returned type, clamp to max value */
601 if (q->Target == GL_ANY_SAMPLES_PASSED
602 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
603 if (q->Result)
604 *params = GL_TRUE;
605 else
606 *params = GL_FALSE;
607 } else {
608 if (q->Result > 0x7fffffff) {
609 *params = 0x7fffffff;
610 }
611 else {
612 *params = (GLint)q->Result;
613 }
614 }
615 break;
616 case GL_QUERY_RESULT_AVAILABLE_ARB:
617 if (!q->Ready)
618 ctx->Driver.CheckQuery( ctx, q );
619 *params = q->Ready;
620 break;
621 default:
622 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
623 return;
624 }
625 }
626
627
628 void GLAPIENTRY
629 _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
630 {
631 struct gl_query_object *q = NULL;
632 GET_CURRENT_CONTEXT(ctx);
633
634 if (MESA_VERBOSE & VERBOSE_API)
635 _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
636 _mesa_lookup_enum_by_nr(pname));
637
638 if (id)
639 q = _mesa_lookup_query_object(ctx, id);
640
641 if (!q || q->Active) {
642 _mesa_error(ctx, GL_INVALID_OPERATION,
643 "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
644 return;
645 }
646
647 switch (pname) {
648 case GL_QUERY_RESULT_ARB:
649 if (!q->Ready)
650 ctx->Driver.WaitQuery(ctx, q);
651 /* if result is too large for returned type, clamp to max value */
652 if (q->Target == GL_ANY_SAMPLES_PASSED
653 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
654 if (q->Result)
655 *params = GL_TRUE;
656 else
657 *params = GL_FALSE;
658 } else {
659 if (q->Result > 0xffffffff) {
660 *params = 0xffffffff;
661 }
662 else {
663 *params = (GLuint)q->Result;
664 }
665 }
666 break;
667 case GL_QUERY_RESULT_AVAILABLE_ARB:
668 if (!q->Ready)
669 ctx->Driver.CheckQuery( ctx, q );
670 *params = q->Ready;
671 break;
672 default:
673 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
674 return;
675 }
676 }
677
678
679 /**
680 * New with GL_EXT_timer_query
681 */
682 void GLAPIENTRY
683 _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
684 {
685 struct gl_query_object *q = NULL;
686 GET_CURRENT_CONTEXT(ctx);
687
688 if (MESA_VERBOSE & VERBOSE_API)
689 _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
690 _mesa_lookup_enum_by_nr(pname));
691
692 if (id)
693 q = _mesa_lookup_query_object(ctx, id);
694
695 if (!q || q->Active) {
696 _mesa_error(ctx, GL_INVALID_OPERATION,
697 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
698 return;
699 }
700
701 switch (pname) {
702 case GL_QUERY_RESULT_ARB:
703 if (!q->Ready)
704 ctx->Driver.WaitQuery(ctx, q);
705 *params = q->Result;
706 break;
707 case GL_QUERY_RESULT_AVAILABLE_ARB:
708 if (!q->Ready)
709 ctx->Driver.CheckQuery( ctx, q );
710 *params = q->Ready;
711 break;
712 default:
713 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
714 return;
715 }
716 }
717
718
719 /**
720 * New with GL_EXT_timer_query
721 */
722 void GLAPIENTRY
723 _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
724 {
725 struct gl_query_object *q = NULL;
726 GET_CURRENT_CONTEXT(ctx);
727
728 if (MESA_VERBOSE & VERBOSE_API)
729 _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
730 _mesa_lookup_enum_by_nr(pname));
731
732 if (id)
733 q = _mesa_lookup_query_object(ctx, id);
734
735 if (!q || q->Active) {
736 _mesa_error(ctx, GL_INVALID_OPERATION,
737 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
738 return;
739 }
740
741 switch (pname) {
742 case GL_QUERY_RESULT_ARB:
743 if (!q->Ready)
744 ctx->Driver.WaitQuery(ctx, q);
745 *params = q->Result;
746 break;
747 case GL_QUERY_RESULT_AVAILABLE_ARB:
748 if (!q->Ready)
749 ctx->Driver.CheckQuery( ctx, q );
750 *params = q->Ready;
751 break;
752 default:
753 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
754 return;
755 }
756 }
757
758 /**
759 * Allocate/init the context state related to query objects.
760 */
761 void
762 _mesa_init_queryobj(struct gl_context *ctx)
763 {
764 ctx->Query.QueryObjects = _mesa_NewHashTable();
765 ctx->Query.CurrentOcclusionObject = NULL;
766
767 ctx->Const.QueryCounterBits.SamplesPassed = 64;
768 ctx->Const.QueryCounterBits.TimeElapsed = 64;
769 ctx->Const.QueryCounterBits.Timestamp = 64;
770 ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
771 ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
772 }
773
774
775 /**
776 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
777 */
778 static void
779 delete_queryobj_cb(GLuint id, void *data, void *userData)
780 {
781 struct gl_query_object *q= (struct gl_query_object *) data;
782 struct gl_context *ctx = (struct gl_context *)userData;
783 ctx->Driver.DeleteQuery(ctx, q);
784 }
785
786
787 /**
788 * Free the context state related to query objects.
789 */
790 void
791 _mesa_free_queryobj_data(struct gl_context *ctx)
792 {
793 _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
794 _mesa_DeleteHashTable(ctx->Query.QueryObjects);
795 }