queryobj.c revision 7e80685340dad7c76f72285c2f6c8268c413fbde
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 */
47static 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 */
66static 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 */
77static 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 */
88static 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 */
103static 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 */
116static void
117_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
118{
119   free(q);
120}
121
122
123void
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 */
139static struct gl_query_object **
140get_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
176static 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
215static 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
251static 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
266static GLboolean
267query_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
287static 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      if (ctx->API == API_OPENGL_CORE) {
317         _mesa_error(ctx, GL_INVALID_OPERATION,
318                     "glBeginQuery{Indexed}(non-gen name)");
319         return;
320      } else {
321         /* create new object */
322         q = ctx->Driver.NewQueryObject(ctx, id);
323         if (!q) {
324            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
325            return;
326         }
327         _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
328      }
329   }
330   else {
331      /* pre-existing object */
332      if (q->Active) {
333         _mesa_error(ctx, GL_INVALID_OPERATION,
334                     "glBeginQuery{Indexed}(query already active)");
335         return;
336      }
337   }
338
339   q->Target = target;
340   q->Active = GL_TRUE;
341   q->Result = 0;
342   q->Ready = GL_FALSE;
343
344   /* XXX should probably refcount query objects */
345   *bindpt = q;
346
347   ctx->Driver.BeginQuery(ctx, q);
348}
349
350
351static void GLAPIENTRY
352_mesa_EndQueryIndexed(GLenum target, GLuint index)
353{
354   struct gl_query_object *q, **bindpt;
355   GET_CURRENT_CONTEXT(ctx);
356   ASSERT_OUTSIDE_BEGIN_END(ctx);
357
358   if (MESA_VERBOSE & VERBOSE_API)
359      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
360                  _mesa_lookup_enum_by_nr(target), index);
361
362   if (!query_error_check_index(ctx, target, index))
363      return;
364
365   FLUSH_VERTICES(ctx, _NEW_DEPTH);
366
367   bindpt = get_query_binding_point(ctx, target);
368   if (!bindpt) {
369      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
370      return;
371   }
372
373   /* XXX should probably refcount query objects */
374   q = *bindpt;
375   *bindpt = NULL;
376
377   if (!q || !q->Active) {
378      _mesa_error(ctx, GL_INVALID_OPERATION,
379                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
380      return;
381   }
382
383   q->Active = GL_FALSE;
384   ctx->Driver.EndQuery(ctx, q);
385}
386
387static void GLAPIENTRY
388_mesa_BeginQueryARB(GLenum target, GLuint id)
389{
390   _mesa_BeginQueryIndexed(target, 0, id);
391}
392
393static void GLAPIENTRY
394_mesa_EndQueryARB(GLenum target)
395{
396   _mesa_EndQueryIndexed(target, 0);
397}
398
399static void GLAPIENTRY
400_mesa_QueryCounter(GLuint id, GLenum target)
401{
402   struct gl_query_object *q;
403   GET_CURRENT_CONTEXT(ctx);
404   ASSERT_OUTSIDE_BEGIN_END(ctx);
405
406   if (MESA_VERBOSE & VERBOSE_API)
407      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
408                  _mesa_lookup_enum_by_nr(target));
409
410   /* error checking */
411   if (target != GL_TIMESTAMP) {
412      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
413      return;
414   }
415
416   if (id == 0) {
417      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
418      return;
419   }
420
421   q = _mesa_lookup_query_object(ctx, id);
422   if (!q) {
423      /* XXX the Core profile should throw INVALID_OPERATION here */
424
425      /* create new object */
426      q = ctx->Driver.NewQueryObject(ctx, id);
427      if (!q) {
428         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
429         return;
430      }
431      _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
432   }
433   else {
434      if (q->Target && q->Target != GL_TIMESTAMP) {
435         _mesa_error(ctx, GL_INVALID_OPERATION,
436                     "glQueryCounter(id has an invalid target)");
437         return;
438      }
439   }
440
441   if (q->Active) {
442      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
443      return;
444   }
445
446   q->Target = target;
447   q->Result = 0;
448   q->Ready = GL_FALSE;
449
450   /* QueryCounter is implemented using EndQuery without BeginQuery
451    * in drivers. This is actually Direct3D and Gallium convention. */
452   ctx->Driver.EndQuery(ctx, q);
453}
454
455
456static void GLAPIENTRY
457_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
458                        GLint *params)
459{
460   struct gl_query_object *q = NULL, **bindpt = NULL;
461   GET_CURRENT_CONTEXT(ctx);
462   ASSERT_OUTSIDE_BEGIN_END(ctx);
463
464   if (MESA_VERBOSE & VERBOSE_API)
465      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
466                  _mesa_lookup_enum_by_nr(target),
467                  index,
468                  _mesa_lookup_enum_by_nr(pname));
469
470   if (!query_error_check_index(ctx, target, index))
471      return;
472
473   if (target == GL_TIMESTAMP) {
474      if (!ctx->Extensions.ARB_timer_query) {
475         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
476         return;
477      }
478   }
479   else {
480      bindpt = get_query_binding_point(ctx, target);
481      if (!bindpt) {
482         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
483         return;
484      }
485
486      q = *bindpt;
487   }
488
489   switch (pname) {
490      case GL_QUERY_COUNTER_BITS_ARB:
491         switch (target) {
492         case GL_SAMPLES_PASSED:
493            *params = ctx->Const.QueryCounterBits.SamplesPassed;
494            break;
495         case GL_ANY_SAMPLES_PASSED:
496            /* The minimum value of this is 1 if it's nonzero, and the value
497             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
498             * bits.
499             */
500            *params = 1;
501            break;
502         case GL_TIME_ELAPSED:
503            *params = ctx->Const.QueryCounterBits.TimeElapsed;
504            break;
505         case GL_TIMESTAMP:
506            *params = ctx->Const.QueryCounterBits.Timestamp;
507            break;
508         case GL_PRIMITIVES_GENERATED:
509            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
510            break;
511         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
512            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
513            break;
514         default:
515            _mesa_problem(ctx,
516                          "Unknown target in glGetQueryIndexediv(target = %s)",
517                          _mesa_lookup_enum_by_nr(target));
518            *params = 0;
519            break;
520         }
521         break;
522      case GL_CURRENT_QUERY_ARB:
523         *params = q ? q->Id : 0;
524         break;
525      default:
526         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
527         return;
528   }
529}
530
531static void GLAPIENTRY
532_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
533{
534   _mesa_GetQueryIndexediv(target, 0, pname, params);
535}
536
537static void GLAPIENTRY
538_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
539{
540   struct gl_query_object *q = NULL;
541   GET_CURRENT_CONTEXT(ctx);
542   ASSERT_OUTSIDE_BEGIN_END(ctx);
543
544   if (MESA_VERBOSE & VERBOSE_API)
545      _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
546                  _mesa_lookup_enum_by_nr(pname));
547
548   if (id)
549      q = _mesa_lookup_query_object(ctx, id);
550
551   if (!q || q->Active) {
552      _mesa_error(ctx, GL_INVALID_OPERATION,
553                  "glGetQueryObjectivARB(id=%d is invalid or active)", id);
554      return;
555   }
556
557   switch (pname) {
558      case GL_QUERY_RESULT_ARB:
559         if (!q->Ready)
560            ctx->Driver.WaitQuery(ctx, q);
561         /* if result is too large for returned type, clamp to max value */
562         if (q->Target == GL_ANY_SAMPLES_PASSED) {
563            if (q->Result)
564               *params = GL_TRUE;
565            else
566               *params = GL_FALSE;
567         } else {
568            if (q->Result > 0x7fffffff) {
569               *params = 0x7fffffff;
570            }
571            else {
572               *params = (GLint)q->Result;
573            }
574         }
575         break;
576      case GL_QUERY_RESULT_AVAILABLE_ARB:
577	 if (!q->Ready)
578	    ctx->Driver.CheckQuery( ctx, q );
579         *params = q->Ready;
580         break;
581      default:
582         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
583         return;
584   }
585}
586
587
588static void GLAPIENTRY
589_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
590{
591   struct gl_query_object *q = NULL;
592   GET_CURRENT_CONTEXT(ctx);
593   ASSERT_OUTSIDE_BEGIN_END(ctx);
594
595   if (MESA_VERBOSE & VERBOSE_API)
596      _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
597                  _mesa_lookup_enum_by_nr(pname));
598
599   if (id)
600      q = _mesa_lookup_query_object(ctx, id);
601
602   if (!q || q->Active) {
603      _mesa_error(ctx, GL_INVALID_OPERATION,
604                  "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
605      return;
606   }
607
608   switch (pname) {
609      case GL_QUERY_RESULT_ARB:
610         if (!q->Ready)
611            ctx->Driver.WaitQuery(ctx, q);
612         /* if result is too large for returned type, clamp to max value */
613         if (q->Target == GL_ANY_SAMPLES_PASSED) {
614            if (q->Result)
615               *params = GL_TRUE;
616            else
617               *params = GL_FALSE;
618         } else {
619            if (q->Result > 0xffffffff) {
620               *params = 0xffffffff;
621            }
622            else {
623               *params = (GLuint)q->Result;
624            }
625         }
626         break;
627      case GL_QUERY_RESULT_AVAILABLE_ARB:
628	 if (!q->Ready)
629	    ctx->Driver.CheckQuery( ctx, q );
630         *params = q->Ready;
631         break;
632      default:
633         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
634         return;
635   }
636}
637
638
639/**
640 * New with GL_EXT_timer_query
641 */
642static void GLAPIENTRY
643_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
644{
645   struct gl_query_object *q = NULL;
646   GET_CURRENT_CONTEXT(ctx);
647   ASSERT_OUTSIDE_BEGIN_END(ctx);
648
649   if (MESA_VERBOSE & VERBOSE_API)
650      _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
651                  _mesa_lookup_enum_by_nr(pname));
652
653   if (id)
654      q = _mesa_lookup_query_object(ctx, id);
655
656   if (!q || q->Active) {
657      _mesa_error(ctx, GL_INVALID_OPERATION,
658                  "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
659      return;
660   }
661
662   switch (pname) {
663      case GL_QUERY_RESULT_ARB:
664         if (!q->Ready)
665            ctx->Driver.WaitQuery(ctx, q);
666         *params = q->Result;
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, "glGetQueryObjecti64vARB(pname)");
675         return;
676   }
677}
678
679
680/**
681 * New with GL_EXT_timer_query
682 */
683static void GLAPIENTRY
684_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
685{
686   struct gl_query_object *q = NULL;
687   GET_CURRENT_CONTEXT(ctx);
688   ASSERT_OUTSIDE_BEGIN_END(ctx);
689
690   if (MESA_VERBOSE & VERBOSE_API)
691      _mesa_debug(ctx, "glGetQueryObjectui64v(%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                  "glGetQueryObjectuui64vARB(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, "glGetQueryObjectui64vARB(pname)");
716         return;
717   }
718}
719
720
721void
722_mesa_init_queryobj_dispatch(struct _glapi_table *disp)
723{
724   SET_GenQueriesARB(disp, _mesa_GenQueriesARB);
725   SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB);
726   SET_IsQueryARB(disp, _mesa_IsQueryARB);
727   SET_BeginQueryARB(disp, _mesa_BeginQueryARB);
728   SET_EndQueryARB(disp, _mesa_EndQueryARB);
729   SET_GetQueryivARB(disp, _mesa_GetQueryivARB);
730   SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB);
731   SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB);
732   SET_QueryCounter(disp, _mesa_QueryCounter);
733
734   SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT);
735   SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT);
736
737   SET_BeginQueryIndexed(disp, _mesa_BeginQueryIndexed);
738   SET_EndQueryIndexed(disp, _mesa_EndQueryIndexed);
739   SET_GetQueryIndexediv(disp, _mesa_GetQueryIndexediv);
740}
741
742
743#endif /* FEATURE_queryobj */
744
745
746/**
747 * Allocate/init the context state related to query objects.
748 */
749void
750_mesa_init_queryobj(struct gl_context *ctx)
751{
752   ctx->Query.QueryObjects = _mesa_NewHashTable();
753   ctx->Query.CurrentOcclusionObject = NULL;
754
755   ctx->Const.QueryCounterBits.SamplesPassed = 64;
756   ctx->Const.QueryCounterBits.TimeElapsed = 64;
757   ctx->Const.QueryCounterBits.Timestamp = 64;
758   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
759   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
760}
761
762
763/**
764 * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
765 */
766static void
767delete_queryobj_cb(GLuint id, void *data, void *userData)
768{
769   struct gl_query_object *q= (struct gl_query_object *) data;
770   struct gl_context *ctx = (struct gl_context *)userData;
771   ctx->Driver.DeleteQuery(ctx, q);
772}
773
774
775/**
776 * Free the context state related to query objects.
777 */
778void
779_mesa_free_queryobj_data(struct gl_context *ctx)
780{
781   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
782   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
783}
784