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