mesa: Include stream information in indexed queries.
[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 q->Stream = index;
371
372 /* XXX should probably refcount query objects */
373 *bindpt = q;
374
375 ctx->Driver.BeginQuery(ctx, q);
376 }
377
378
379 void GLAPIENTRY
380 _mesa_EndQueryIndexed(GLenum target, GLuint index)
381 {
382 struct gl_query_object *q, **bindpt;
383 GET_CURRENT_CONTEXT(ctx);
384
385 if (MESA_VERBOSE & VERBOSE_API)
386 _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
387 _mesa_lookup_enum_by_nr(target), index);
388
389 if (!query_error_check_index(ctx, target, index))
390 return;
391
392 FLUSH_VERTICES(ctx, 0);
393
394 bindpt = get_query_binding_point(ctx, target);
395 if (!bindpt) {
396 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
397 return;
398 }
399
400 /* XXX should probably refcount query objects */
401 q = *bindpt;
402
403 /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
404 if (q && q->Target != target) {
405 _mesa_error(ctx, GL_INVALID_OPERATION,
406 "glEndQuery(target=%s with active query of target %s)",
407 _mesa_lookup_enum_by_nr(target),
408 _mesa_lookup_enum_by_nr(q->Target));
409 return;
410 }
411
412 *bindpt = NULL;
413
414 if (!q || !q->Active) {
415 _mesa_error(ctx, GL_INVALID_OPERATION,
416 "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
417 return;
418 }
419
420 q->Active = GL_FALSE;
421 ctx->Driver.EndQuery(ctx, q);
422 }
423
424 void GLAPIENTRY
425 _mesa_BeginQuery(GLenum target, GLuint id)
426 {
427 _mesa_BeginQueryIndexed(target, 0, id);
428 }
429
430 void GLAPIENTRY
431 _mesa_EndQuery(GLenum target)
432 {
433 _mesa_EndQueryIndexed(target, 0);
434 }
435
436 void GLAPIENTRY
437 _mesa_QueryCounter(GLuint id, GLenum target)
438 {
439 struct gl_query_object *q;
440 GET_CURRENT_CONTEXT(ctx);
441
442 if (MESA_VERBOSE & VERBOSE_API)
443 _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
444 _mesa_lookup_enum_by_nr(target));
445
446 /* error checking */
447 if (target != GL_TIMESTAMP) {
448 _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
449 return;
450 }
451
452 if (id == 0) {
453 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
454 return;
455 }
456
457 q = _mesa_lookup_query_object(ctx, id);
458 if (!q) {
459 /* XXX the Core profile should throw INVALID_OPERATION here */
460
461 /* create new object */
462 q = ctx->Driver.NewQueryObject(ctx, id);
463 if (!q) {
464 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
465 return;
466 }
467 _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
468 }
469 else {
470 if (q->Target && q->Target != GL_TIMESTAMP) {
471 _mesa_error(ctx, GL_INVALID_OPERATION,
472 "glQueryCounter(id has an invalid target)");
473 return;
474 }
475 }
476
477 if (q->Active) {
478 _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
479 return;
480 }
481
482 q->Target = target;
483 q->Result = 0;
484 q->Ready = GL_FALSE;
485 q->EverBound = GL_TRUE;
486
487 if (ctx->Driver.QueryCounter) {
488 ctx->Driver.QueryCounter(ctx, q);
489 } else {
490 /* QueryCounter is implemented using EndQuery without BeginQuery
491 * in drivers. This is actually Direct3D and Gallium convention.
492 */
493 ctx->Driver.EndQuery(ctx, q);
494 }
495 }
496
497
498 void GLAPIENTRY
499 _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
500 GLint *params)
501 {
502 struct gl_query_object *q = NULL, **bindpt = NULL;
503 GET_CURRENT_CONTEXT(ctx);
504
505 if (MESA_VERBOSE & VERBOSE_API)
506 _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
507 _mesa_lookup_enum_by_nr(target),
508 index,
509 _mesa_lookup_enum_by_nr(pname));
510
511 if (!query_error_check_index(ctx, target, index))
512 return;
513
514 if (target == GL_TIMESTAMP) {
515 if (!ctx->Extensions.ARB_timer_query) {
516 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
517 return;
518 }
519 }
520 else {
521 bindpt = get_query_binding_point(ctx, target);
522 if (!bindpt) {
523 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
524 return;
525 }
526
527 q = *bindpt;
528 }
529
530 switch (pname) {
531 case GL_QUERY_COUNTER_BITS_ARB:
532 switch (target) {
533 case GL_SAMPLES_PASSED:
534 *params = ctx->Const.QueryCounterBits.SamplesPassed;
535 break;
536 case GL_ANY_SAMPLES_PASSED:
537 /* The minimum value of this is 1 if it's nonzero, and the value
538 * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
539 * bits.
540 */
541 *params = 1;
542 break;
543 case GL_TIME_ELAPSED:
544 *params = ctx->Const.QueryCounterBits.TimeElapsed;
545 break;
546 case GL_TIMESTAMP:
547 *params = ctx->Const.QueryCounterBits.Timestamp;
548 break;
549 case GL_PRIMITIVES_GENERATED:
550 *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
551 break;
552 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
553 *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
554 break;
555 default:
556 _mesa_problem(ctx,
557 "Unknown target in glGetQueryIndexediv(target = %s)",
558 _mesa_lookup_enum_by_nr(target));
559 *params = 0;
560 break;
561 }
562 break;
563 case GL_CURRENT_QUERY_ARB:
564 *params = (q && q->Target == target) ? q->Id : 0;
565 break;
566 default:
567 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
568 return;
569 }
570 }
571
572 void GLAPIENTRY
573 _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
574 {
575 _mesa_GetQueryIndexediv(target, 0, pname, params);
576 }
577
578 void GLAPIENTRY
579 _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
580 {
581 struct gl_query_object *q = NULL;
582 GET_CURRENT_CONTEXT(ctx);
583
584 if (MESA_VERBOSE & VERBOSE_API)
585 _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
586 _mesa_lookup_enum_by_nr(pname));
587
588 if (id)
589 q = _mesa_lookup_query_object(ctx, id);
590
591 if (!q || q->Active) {
592 _mesa_error(ctx, GL_INVALID_OPERATION,
593 "glGetQueryObjectivARB(id=%d is invalid or active)", id);
594 return;
595 }
596
597 switch (pname) {
598 case GL_QUERY_RESULT_ARB:
599 if (!q->Ready)
600 ctx->Driver.WaitQuery(ctx, q);
601 /* if result is too large for returned type, clamp to max value */
602 if (q->Target == GL_ANY_SAMPLES_PASSED
603 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
604 if (q->Result)
605 *params = GL_TRUE;
606 else
607 *params = GL_FALSE;
608 } else {
609 if (q->Result > 0x7fffffff) {
610 *params = 0x7fffffff;
611 }
612 else {
613 *params = (GLint)q->Result;
614 }
615 }
616 break;
617 case GL_QUERY_RESULT_AVAILABLE_ARB:
618 if (!q->Ready)
619 ctx->Driver.CheckQuery( ctx, q );
620 *params = q->Ready;
621 break;
622 default:
623 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
624 return;
625 }
626 }
627
628
629 void GLAPIENTRY
630 _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
631 {
632 struct gl_query_object *q = NULL;
633 GET_CURRENT_CONTEXT(ctx);
634
635 if (MESA_VERBOSE & VERBOSE_API)
636 _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
637 _mesa_lookup_enum_by_nr(pname));
638
639 if (id)
640 q = _mesa_lookup_query_object(ctx, id);
641
642 if (!q || q->Active) {
643 _mesa_error(ctx, GL_INVALID_OPERATION,
644 "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
645 return;
646 }
647
648 switch (pname) {
649 case GL_QUERY_RESULT_ARB:
650 if (!q->Ready)
651 ctx->Driver.WaitQuery(ctx, q);
652 /* if result is too large for returned type, clamp to max value */
653 if (q->Target == GL_ANY_SAMPLES_PASSED
654 || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
655 if (q->Result)
656 *params = GL_TRUE;
657 else
658 *params = GL_FALSE;
659 } else {
660 if (q->Result > 0xffffffff) {
661 *params = 0xffffffff;
662 }
663 else {
664 *params = (GLuint)q->Result;
665 }
666 }
667 break;
668 case GL_QUERY_RESULT_AVAILABLE_ARB:
669 if (!q->Ready)
670 ctx->Driver.CheckQuery( ctx, q );
671 *params = q->Ready;
672 break;
673 default:
674 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
675 return;
676 }
677 }
678
679
680 /**
681 * New with GL_EXT_timer_query
682 */
683 void GLAPIENTRY
684 _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
685 {
686 struct gl_query_object *q = NULL;
687 GET_CURRENT_CONTEXT(ctx);
688
689 if (MESA_VERBOSE & VERBOSE_API)
690 _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
691 _mesa_lookup_enum_by_nr(pname));
692
693 if (id)
694 q = _mesa_lookup_query_object(ctx, id);
695
696 if (!q || q->Active) {
697 _mesa_error(ctx, GL_INVALID_OPERATION,
698 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
699 return;
700 }
701
702 switch (pname) {
703 case GL_QUERY_RESULT_ARB:
704 if (!q->Ready)
705 ctx->Driver.WaitQuery(ctx, q);
706 *params = q->Result;
707 break;
708 case GL_QUERY_RESULT_AVAILABLE_ARB:
709 if (!q->Ready)
710 ctx->Driver.CheckQuery( ctx, q );
711 *params = q->Ready;
712 break;
713 default:
714 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
715 return;
716 }
717 }
718
719
720 /**
721 * New with GL_EXT_timer_query
722 */
723 void GLAPIENTRY
724 _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
725 {
726 struct gl_query_object *q = NULL;
727 GET_CURRENT_CONTEXT(ctx);
728
729 if (MESA_VERBOSE & VERBOSE_API)
730 _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
731 _mesa_lookup_enum_by_nr(pname));
732
733 if (id)
734 q = _mesa_lookup_query_object(ctx, id);
735
736 if (!q || q->Active) {
737 _mesa_error(ctx, GL_INVALID_OPERATION,
738 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
739 return;
740 }
741
742 switch (pname) {
743 case GL_QUERY_RESULT_ARB:
744 if (!q->Ready)
745 ctx->Driver.WaitQuery(ctx, q);
746 *params = q->Result;
747 break;
748 case GL_QUERY_RESULT_AVAILABLE_ARB:
749 if (!q->Ready)
750 ctx->Driver.CheckQuery( ctx, q );
751 *params = q->Ready;
752 break;
753 default:
754 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
755 return;
756 }
757 }
758
759 /**
760 * Allocate/init the context state related to query objects.
761 */
762 void
763 _mesa_init_queryobj(struct gl_context *ctx)
764 {
765 ctx->Query.QueryObjects = _mesa_NewHashTable();
766 ctx->Query.CurrentOcclusionObject = NULL;
767
768 ctx->Const.QueryCounterBits.SamplesPassed = 64;
769 ctx->Const.QueryCounterBits.TimeElapsed = 64;
770 ctx->Const.QueryCounterBits.Timestamp = 64;
771 ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
772 ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
773 }
774
775
776 /**
777 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
778 */
779 static void
780 delete_queryobj_cb(GLuint id, void *data, void *userData)
781 {
782 struct gl_query_object *q= (struct gl_query_object *) data;
783 struct gl_context *ctx = (struct gl_context *)userData;
784 ctx->Driver.DeleteQuery(ctx, q);
785 }
786
787
788 /**
789 * Free the context state related to query objects.
790 */
791 void
792 _mesa_free_queryobj_data(struct gl_context *ctx)
793 {
794 _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
795 _mesa_DeleteHashTable(ctx->Query.QueryObjects);
796 }