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