queryobj.c revision 7117f1b4
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg * Version:  6.5.1
47117f1b4Smrg *
57117f1b4Smrg * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
207117f1b4Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
217117f1b4Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
227117f1b4Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
267117f1b4Smrg#include "glheader.h"
277117f1b4Smrg#include "context.h"
287117f1b4Smrg#include "hash.h"
297117f1b4Smrg#include "imports.h"
307117f1b4Smrg#include "queryobj.h"
317117f1b4Smrg#include "mtypes.h"
327117f1b4Smrg
337117f1b4Smrg
347117f1b4Smrg/**
357117f1b4Smrg * Allocate a new query object.  This is a fallback routine called via
367117f1b4Smrg * ctx->Driver.NewQueryObject().
377117f1b4Smrg * \param ctx - rendering context
387117f1b4Smrg * \param id - the new object's ID
397117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory.
407117f1b4Smrg */
417117f1b4Smrgstruct gl_query_object *
427117f1b4Smrg_mesa_new_query_object(GLcontext *ctx, GLuint id)
437117f1b4Smrg{
447117f1b4Smrg   struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
457117f1b4Smrg   (void) ctx;
467117f1b4Smrg   if (q) {
477117f1b4Smrg      q->Id = id;
487117f1b4Smrg      q->Result = 0;
497117f1b4Smrg      q->Active = GL_FALSE;
507117f1b4Smrg      q->Ready = GL_TRUE;   /* correct, see spec */
517117f1b4Smrg   }
527117f1b4Smrg   return q;
537117f1b4Smrg}
547117f1b4Smrg
557117f1b4Smrg
567117f1b4Smrg/**
577117f1b4Smrg * Delete an occlusion query object.
587117f1b4Smrg * Not removed from hash table here.
597117f1b4Smrg * XXX maybe add Delete() method to gl_query_object class and call that instead
607117f1b4Smrg */
617117f1b4Smrgstatic void
627117f1b4Smrgdelete_query_object(struct gl_query_object *q)
637117f1b4Smrg{
647117f1b4Smrg   FREE(q);
657117f1b4Smrg}
667117f1b4Smrg
677117f1b4Smrg
687117f1b4Smrgstatic struct gl_query_object *
697117f1b4Smrglookup_query_object(GLcontext *ctx, GLuint id)
707117f1b4Smrg{
717117f1b4Smrg   return (struct gl_query_object *)
727117f1b4Smrg      _mesa_HashLookup(ctx->Query.QueryObjects, id);
737117f1b4Smrg}
747117f1b4Smrg
757117f1b4Smrg
767117f1b4Smrg
777117f1b4Smrgvoid GLAPIENTRY
787117f1b4Smrg_mesa_GenQueriesARB(GLsizei n, GLuint *ids)
797117f1b4Smrg{
807117f1b4Smrg   GLuint first;
817117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
827117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
837117f1b4Smrg
847117f1b4Smrg   if (n < 0) {
857117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
867117f1b4Smrg      return;
877117f1b4Smrg   }
887117f1b4Smrg
897117f1b4Smrg   /* No query objects can be active at this time! */
907117f1b4Smrg   if (ctx->Query.CurrentOcclusionObject ||
917117f1b4Smrg       ctx->Query.CurrentTimerObject) {
927117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
937117f1b4Smrg      return;
947117f1b4Smrg   }
957117f1b4Smrg
967117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
977117f1b4Smrg   if (first) {
987117f1b4Smrg      GLsizei i;
997117f1b4Smrg      for (i = 0; i < n; i++) {
1007117f1b4Smrg         struct gl_query_object *q
1017117f1b4Smrg            = ctx->Driver.NewQueryObject(ctx, first + i);
1027117f1b4Smrg         if (!q) {
1037117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
1047117f1b4Smrg            return;
1057117f1b4Smrg         }
1067117f1b4Smrg         ids[i] = first + i;
1077117f1b4Smrg         _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
1087117f1b4Smrg      }
1097117f1b4Smrg   }
1107117f1b4Smrg}
1117117f1b4Smrg
1127117f1b4Smrg
1137117f1b4Smrgvoid GLAPIENTRY
1147117f1b4Smrg_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
1157117f1b4Smrg{
1167117f1b4Smrg   GLint i;
1177117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1187117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1197117f1b4Smrg
1207117f1b4Smrg   if (n < 0) {
1217117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
1227117f1b4Smrg      return;
1237117f1b4Smrg   }
1247117f1b4Smrg
1257117f1b4Smrg   /* No query objects can be active at this time! */
1267117f1b4Smrg   if (ctx->Query.CurrentOcclusionObject ||
1277117f1b4Smrg       ctx->Query.CurrentTimerObject) {
1287117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
1297117f1b4Smrg      return;
1307117f1b4Smrg   }
1317117f1b4Smrg
1327117f1b4Smrg   for (i = 0; i < n; i++) {
1337117f1b4Smrg      if (ids[i] > 0) {
1347117f1b4Smrg         struct gl_query_object *q = lookup_query_object(ctx, ids[i]);
1357117f1b4Smrg         if (q) {
1367117f1b4Smrg            ASSERT(!q->Active); /* should be caught earlier */
1377117f1b4Smrg            _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
1387117f1b4Smrg            delete_query_object(q);
1397117f1b4Smrg         }
1407117f1b4Smrg      }
1417117f1b4Smrg   }
1427117f1b4Smrg}
1437117f1b4Smrg
1447117f1b4Smrg
1457117f1b4SmrgGLboolean GLAPIENTRY
1467117f1b4Smrg_mesa_IsQueryARB(GLuint id)
1477117f1b4Smrg{
1487117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1497117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
1507117f1b4Smrg
1517117f1b4Smrg   if (id && lookup_query_object(ctx, id))
1527117f1b4Smrg      return GL_TRUE;
1537117f1b4Smrg   else
1547117f1b4Smrg      return GL_FALSE;
1557117f1b4Smrg}
1567117f1b4Smrg
1577117f1b4Smrg
1587117f1b4Smrgvoid GLAPIENTRY
1597117f1b4Smrg_mesa_BeginQueryARB(GLenum target, GLuint id)
1607117f1b4Smrg{
1617117f1b4Smrg   struct gl_query_object *q;
1627117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1637117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1647117f1b4Smrg
1657117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_DEPTH);
1667117f1b4Smrg
1677117f1b4Smrg   switch (target) {
1687117f1b4Smrg      case GL_SAMPLES_PASSED_ARB:
1697117f1b4Smrg         if (!ctx->Extensions.ARB_occlusion_query) {
1707117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
1717117f1b4Smrg            return;
1727117f1b4Smrg         }
1737117f1b4Smrg         if (ctx->Query.CurrentOcclusionObject) {
1747117f1b4Smrg            _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
1757117f1b4Smrg            return;
1767117f1b4Smrg         }
1777117f1b4Smrg         break;
1787117f1b4Smrg#if FEATURE_EXT_timer_query
1797117f1b4Smrg      case GL_TIME_ELAPSED_EXT:
1807117f1b4Smrg         if (!ctx->Extensions.EXT_timer_query) {
1817117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
1827117f1b4Smrg            return;
1837117f1b4Smrg         }
1847117f1b4Smrg         if (ctx->Query.CurrentTimerObject) {
1857117f1b4Smrg            _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
1867117f1b4Smrg            return;
1877117f1b4Smrg         }
1887117f1b4Smrg         break;
1897117f1b4Smrg#endif
1907117f1b4Smrg      default:
1917117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
1927117f1b4Smrg         return;
1937117f1b4Smrg   }
1947117f1b4Smrg
1957117f1b4Smrg   if (id == 0) {
1967117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
1977117f1b4Smrg      return;
1987117f1b4Smrg   }
1997117f1b4Smrg
2007117f1b4Smrg   q = lookup_query_object(ctx, id);
2017117f1b4Smrg   if (!q) {
2027117f1b4Smrg      /* create new object */
2037117f1b4Smrg      q = ctx->Driver.NewQueryObject(ctx, id);
2047117f1b4Smrg      if (!q) {
2057117f1b4Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
2067117f1b4Smrg         return;
2077117f1b4Smrg      }
2087117f1b4Smrg      _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
2097117f1b4Smrg   }
2107117f1b4Smrg   else {
2117117f1b4Smrg      /* pre-existing object */
2127117f1b4Smrg      if (q->Active) {
2137117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2147117f1b4Smrg                     "glBeginQueryARB(query already active)");
2157117f1b4Smrg         return;
2167117f1b4Smrg      }
2177117f1b4Smrg   }
2187117f1b4Smrg
2197117f1b4Smrg   q->Active = GL_TRUE;
2207117f1b4Smrg   q->Result = 0;
2217117f1b4Smrg   q->Ready = GL_FALSE;
2227117f1b4Smrg
2237117f1b4Smrg   if (target == GL_SAMPLES_PASSED_ARB) {
2247117f1b4Smrg      ctx->Query.CurrentOcclusionObject = q;
2257117f1b4Smrg   }
2267117f1b4Smrg#if FEATURE_EXT_timer_query
2277117f1b4Smrg   else if (target == GL_TIME_ELAPSED_EXT) {
2287117f1b4Smrg      ctx->Query.CurrentTimerObject = q;
2297117f1b4Smrg   }
2307117f1b4Smrg#endif
2317117f1b4Smrg
2327117f1b4Smrg   if (ctx->Driver.BeginQuery) {
2337117f1b4Smrg      ctx->Driver.BeginQuery(ctx, target, q);
2347117f1b4Smrg   }
2357117f1b4Smrg}
2367117f1b4Smrg
2377117f1b4Smrg
2387117f1b4Smrgvoid GLAPIENTRY
2397117f1b4Smrg_mesa_EndQueryARB(GLenum target)
2407117f1b4Smrg{
2417117f1b4Smrg   struct gl_query_object *q;
2427117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2437117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2447117f1b4Smrg
2457117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_DEPTH);
2467117f1b4Smrg
2477117f1b4Smrg   switch (target) {
2487117f1b4Smrg      case GL_SAMPLES_PASSED_ARB:
2497117f1b4Smrg         if (!ctx->Extensions.ARB_occlusion_query) {
2507117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
2517117f1b4Smrg            return;
2527117f1b4Smrg         }
2537117f1b4Smrg         q = ctx->Query.CurrentOcclusionObject;
2547117f1b4Smrg         ctx->Query.CurrentOcclusionObject = NULL;
2557117f1b4Smrg         break;
2567117f1b4Smrg#if FEATURE_EXT_timer_query
2577117f1b4Smrg      case GL_TIME_ELAPSED_EXT:
2587117f1b4Smrg         if (!ctx->Extensions.EXT_timer_query) {
2597117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
2607117f1b4Smrg            return;
2617117f1b4Smrg         }
2627117f1b4Smrg         q = ctx->Query.CurrentTimerObject;
2637117f1b4Smrg         ctx->Query.CurrentTimerObject = NULL;
2647117f1b4Smrg         break;
2657117f1b4Smrg#endif
2667117f1b4Smrg      default:
2677117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
2687117f1b4Smrg         return;
2697117f1b4Smrg   }
2707117f1b4Smrg
2717117f1b4Smrg   if (!q || !q->Active) {
2727117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
2737117f1b4Smrg                  "glEndQueryARB(no matching glBeginQueryARB)");
2747117f1b4Smrg      return;
2757117f1b4Smrg   }
2767117f1b4Smrg
2777117f1b4Smrg   q->Active = GL_FALSE;
2787117f1b4Smrg   if (ctx->Driver.EndQuery) {
2797117f1b4Smrg      ctx->Driver.EndQuery(ctx, target, q);
2807117f1b4Smrg   }
2817117f1b4Smrg   else {
2827117f1b4Smrg      /* if we're using software rendering/querying */
2837117f1b4Smrg      q->Ready = GL_TRUE;
2847117f1b4Smrg   }
2857117f1b4Smrg}
2867117f1b4Smrg
2877117f1b4Smrg
2887117f1b4Smrgvoid GLAPIENTRY
2897117f1b4Smrg_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
2907117f1b4Smrg{
2917117f1b4Smrg   struct gl_query_object *q;
2927117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2937117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2947117f1b4Smrg
2957117f1b4Smrg   switch (target) {
2967117f1b4Smrg      case GL_SAMPLES_PASSED_ARB:
2977117f1b4Smrg         if (!ctx->Extensions.ARB_occlusion_query) {
2987117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
2997117f1b4Smrg            return;
3007117f1b4Smrg         }
3017117f1b4Smrg         q = ctx->Query.CurrentOcclusionObject;
3027117f1b4Smrg         break;
3037117f1b4Smrg#if FEATURE_EXT_timer_query
3047117f1b4Smrg      case GL_TIME_ELAPSED_EXT:
3057117f1b4Smrg         if (!ctx->Extensions.EXT_timer_query) {
3067117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3077117f1b4Smrg            return;
3087117f1b4Smrg         }
3097117f1b4Smrg         q = ctx->Query.CurrentTimerObject;
3107117f1b4Smrg         break;
3117117f1b4Smrg#endif
3127117f1b4Smrg      default:
3137117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(target)");
3147117f1b4Smrg         return;
3157117f1b4Smrg   }
3167117f1b4Smrg
3177117f1b4Smrg   switch (pname) {
3187117f1b4Smrg      case GL_QUERY_COUNTER_BITS_ARB:
3197117f1b4Smrg         *params = 8 * sizeof(q->Result);
3207117f1b4Smrg         break;
3217117f1b4Smrg      case GL_CURRENT_QUERY_ARB:
3227117f1b4Smrg         *params = q ? q->Id : 0;
3237117f1b4Smrg         break;
3247117f1b4Smrg      default:
3257117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
3267117f1b4Smrg         return;
3277117f1b4Smrg   }
3287117f1b4Smrg}
3297117f1b4Smrg
3307117f1b4Smrg
3317117f1b4Smrgvoid GLAPIENTRY
3327117f1b4Smrg_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
3337117f1b4Smrg{
3347117f1b4Smrg   struct gl_query_object *q = NULL;
3357117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3367117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3377117f1b4Smrg
3387117f1b4Smrg   if (id)
3397117f1b4Smrg      q = lookup_query_object(ctx, id);
3407117f1b4Smrg
3417117f1b4Smrg   if (!q || q->Active) {
3427117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
3437117f1b4Smrg                  "glGetQueryObjectivARB(id=%d is invalid or active)", id);
3447117f1b4Smrg      return;
3457117f1b4Smrg   }
3467117f1b4Smrg
3477117f1b4Smrg   switch (pname) {
3487117f1b4Smrg      case GL_QUERY_RESULT_ARB:
3497117f1b4Smrg         while (!q->Ready) {
3507117f1b4Smrg            /* Wait for the query to finish! */
3517117f1b4Smrg            /* If using software rendering, the result will always be ready
3527117f1b4Smrg             * by time we get here.  Otherwise, we must be using hardware!
3537117f1b4Smrg             */
3547117f1b4Smrg            ASSERT(ctx->Driver.EndQuery);
3557117f1b4Smrg         }
3567117f1b4Smrg         /* if result is too large for returned type, clamp to max value */
3577117f1b4Smrg         if (q->Result > 0x7fffffff) {
3587117f1b4Smrg            *params = 0x7fffffff;
3597117f1b4Smrg         }
3607117f1b4Smrg         else {
3617117f1b4Smrg            *params = q->Result;
3627117f1b4Smrg         }
3637117f1b4Smrg         break;
3647117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
3657117f1b4Smrg         /* XXX revisit when we have a hardware implementation! */
3667117f1b4Smrg         *params = q->Ready;
3677117f1b4Smrg         break;
3687117f1b4Smrg      default:
3697117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
3707117f1b4Smrg         return;
3717117f1b4Smrg   }
3727117f1b4Smrg}
3737117f1b4Smrg
3747117f1b4Smrg
3757117f1b4Smrgvoid GLAPIENTRY
3767117f1b4Smrg_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
3777117f1b4Smrg{
3787117f1b4Smrg   struct gl_query_object *q = NULL;
3797117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3807117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3817117f1b4Smrg
3827117f1b4Smrg   if (id)
3837117f1b4Smrg      q = lookup_query_object(ctx, id);
3847117f1b4Smrg
3857117f1b4Smrg   if (!q || q->Active) {
3867117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
3877117f1b4Smrg                  "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
3887117f1b4Smrg      return;
3897117f1b4Smrg   }
3907117f1b4Smrg
3917117f1b4Smrg   switch (pname) {
3927117f1b4Smrg      case GL_QUERY_RESULT_ARB:
3937117f1b4Smrg         while (!q->Ready) {
3947117f1b4Smrg            /* Wait for the query to finish! */
3957117f1b4Smrg            /* If using software rendering, the result will always be ready
3967117f1b4Smrg             * by time we get here.  Otherwise, we must be using hardware!
3977117f1b4Smrg             */
3987117f1b4Smrg            ASSERT(ctx->Driver.EndQuery);
3997117f1b4Smrg         }
4007117f1b4Smrg         /* if result is too large for returned type, clamp to max value */
4017117f1b4Smrg         if (q->Result > 0xffffffff) {
4027117f1b4Smrg            *params = 0xffffffff;
4037117f1b4Smrg         }
4047117f1b4Smrg         else {
4057117f1b4Smrg            *params = q->Result;
4067117f1b4Smrg         }
4077117f1b4Smrg         break;
4087117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
4097117f1b4Smrg         /* XXX revisit when we have a hardware implementation! */
4107117f1b4Smrg         *params = q->Ready;
4117117f1b4Smrg         break;
4127117f1b4Smrg      default:
4137117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
4147117f1b4Smrg         return;
4157117f1b4Smrg   }
4167117f1b4Smrg}
4177117f1b4Smrg
4187117f1b4Smrg
4197117f1b4Smrg#if FEATURE_EXT_timer_query
4207117f1b4Smrg
4217117f1b4Smrg/**
4227117f1b4Smrg * New with GL_EXT_timer_query
4237117f1b4Smrg */
4247117f1b4Smrgvoid GLAPIENTRY
4257117f1b4Smrg_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
4267117f1b4Smrg{
4277117f1b4Smrg   struct gl_query_object *q = NULL;
4287117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4297117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
4307117f1b4Smrg
4317117f1b4Smrg   if (id)
4327117f1b4Smrg      q = lookup_query_object(ctx, id);
4337117f1b4Smrg
4347117f1b4Smrg   if (!q || q->Active) {
4357117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4367117f1b4Smrg                  "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
4377117f1b4Smrg      return;
4387117f1b4Smrg   }
4397117f1b4Smrg
4407117f1b4Smrg   switch (pname) {
4417117f1b4Smrg      case GL_QUERY_RESULT_ARB:
4427117f1b4Smrg         while (!q->Ready) {
4437117f1b4Smrg            /* Wait for the query to finish! */
4447117f1b4Smrg            /* If using software rendering, the result will always be ready
4457117f1b4Smrg             * by time we get here.  Otherwise, we must be using hardware!
4467117f1b4Smrg             */
4477117f1b4Smrg            ASSERT(ctx->Driver.EndQuery);
4487117f1b4Smrg         }
4497117f1b4Smrg         *params = q->Result;
4507117f1b4Smrg         break;
4517117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
4527117f1b4Smrg         /* XXX revisit when we have a hardware implementation! */
4537117f1b4Smrg         *params = q->Ready;
4547117f1b4Smrg         break;
4557117f1b4Smrg      default:
4567117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
4577117f1b4Smrg         return;
4587117f1b4Smrg   }
4597117f1b4Smrg}
4607117f1b4Smrg
4617117f1b4Smrg
4627117f1b4Smrg/**
4637117f1b4Smrg * New with GL_EXT_timer_query
4647117f1b4Smrg */
4657117f1b4Smrgvoid GLAPIENTRY
4667117f1b4Smrg_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
4677117f1b4Smrg{
4687117f1b4Smrg   struct gl_query_object *q = NULL;
4697117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4707117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
4717117f1b4Smrg
4727117f1b4Smrg   if (id)
4737117f1b4Smrg      q = lookup_query_object(ctx, id);
4747117f1b4Smrg
4757117f1b4Smrg   if (!q || q->Active) {
4767117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4777117f1b4Smrg                  "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
4787117f1b4Smrg      return;
4797117f1b4Smrg   }
4807117f1b4Smrg
4817117f1b4Smrg   switch (pname) {
4827117f1b4Smrg      case GL_QUERY_RESULT_ARB:
4837117f1b4Smrg         while (!q->Ready) {
4847117f1b4Smrg            /* Wait for the query to finish! */
4857117f1b4Smrg            /* If using software rendering, the result will always be ready
4867117f1b4Smrg             * by time we get here.  Otherwise, we must be using hardware!
4877117f1b4Smrg             */
4887117f1b4Smrg            ASSERT(ctx->Driver.EndQuery);
4897117f1b4Smrg         }
4907117f1b4Smrg         *params = q->Result;
4917117f1b4Smrg         break;
4927117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
4937117f1b4Smrg         /* XXX revisit when we have a hardware implementation! */
4947117f1b4Smrg         *params = q->Ready;
4957117f1b4Smrg         break;
4967117f1b4Smrg      default:
4977117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
4987117f1b4Smrg         return;
4997117f1b4Smrg   }
5007117f1b4Smrg}
5017117f1b4Smrg
5027117f1b4Smrg#endif /* FEATURE_EXT_timer_query */
5037117f1b4Smrg
5047117f1b4Smrg
5057117f1b4Smrg/**
5067117f1b4Smrg * Allocate/init the context state related to query objects.
5077117f1b4Smrg */
5087117f1b4Smrgvoid
5097117f1b4Smrg_mesa_init_query(GLcontext *ctx)
5107117f1b4Smrg{
5117117f1b4Smrg#if FEATURE_ARB_occlusion_query
5127117f1b4Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
5137117f1b4Smrg   ctx->Query.CurrentOcclusionObject = NULL;
5147117f1b4Smrg#endif
5157117f1b4Smrg}
5167117f1b4Smrg
5177117f1b4Smrg
5187117f1b4Smrg/**
5197117f1b4Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
5207117f1b4Smrg */
5217117f1b4Smrgstatic void
5227117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData)
5237117f1b4Smrg{
5247117f1b4Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
5257117f1b4Smrg   (void) userData;
5267117f1b4Smrg   delete_query_object(q);
5277117f1b4Smrg}
5287117f1b4Smrg
5297117f1b4Smrg
5307117f1b4Smrg/**
5317117f1b4Smrg * Free the context state related to query objects.
5327117f1b4Smrg */
5337117f1b4Smrgvoid
5347117f1b4Smrg_mesa_free_query_data(GLcontext *ctx)
5357117f1b4Smrg{
5367117f1b4Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, NULL);
5377117f1b4Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
5387117f1b4Smrg}
539