queryobj.c revision 3464ebd5
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
3c1f859d4Smrg * Version:  7.1
47117f1b4Smrg *
5c1f859d4Smrg * Copyright (C) 1999-2007  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"
283464ebd5Sriastradh#include "enums.h"
297117f1b4Smrg#include "hash.h"
307117f1b4Smrg#include "imports.h"
317117f1b4Smrg#include "queryobj.h"
323464ebd5Sriastradh#include "mfeatures.h"
337117f1b4Smrg#include "mtypes.h"
34cdc920a0Smrg#include "main/dispatch.h"
354a49301eSmrg
364a49301eSmrg
374a49301eSmrg#if FEATURE_queryobj
387117f1b4Smrg
397117f1b4Smrg
407117f1b4Smrg/**
417117f1b4Smrg * Allocate a new query object.  This is a fallback routine called via
427117f1b4Smrg * ctx->Driver.NewQueryObject().
437117f1b4Smrg * \param ctx - rendering context
447117f1b4Smrg * \param id - the new object's ID
457117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory.
467117f1b4Smrg */
474a49301eSmrgstatic struct gl_query_object *
483464ebd5Sriastradh_mesa_new_query_object(struct gl_context *ctx, GLuint id)
497117f1b4Smrg{
507117f1b4Smrg   struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
517117f1b4Smrg   (void) ctx;
527117f1b4Smrg   if (q) {
537117f1b4Smrg      q->Id = id;
547117f1b4Smrg      q->Result = 0;
557117f1b4Smrg      q->Active = GL_FALSE;
567117f1b4Smrg      q->Ready = GL_TRUE;   /* correct, see spec */
577117f1b4Smrg   }
587117f1b4Smrg   return q;
597117f1b4Smrg}
607117f1b4Smrg
617117f1b4Smrg
627117f1b4Smrg/**
63c1f859d4Smrg * Begin a query.  Software driver fallback.
64c1f859d4Smrg * Called via ctx->Driver.BeginQuery().
65c1f859d4Smrg */
664a49301eSmrgstatic void
673464ebd5Sriastradh_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
68c1f859d4Smrg{
69c1f859d4Smrg   /* no-op */
70c1f859d4Smrg}
71c1f859d4Smrg
72c1f859d4Smrg
73c1f859d4Smrg/**
74c1f859d4Smrg * End a query.  Software driver fallback.
75c1f859d4Smrg * Called via ctx->Driver.EndQuery().
76c1f859d4Smrg */
774a49301eSmrgstatic void
783464ebd5Sriastradh_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
79c1f859d4Smrg{
80c1f859d4Smrg   q->Ready = GL_TRUE;
81c1f859d4Smrg}
82c1f859d4Smrg
83c1f859d4Smrg
84c1f859d4Smrg/**
85c1f859d4Smrg * Wait for query to complete.  Software driver fallback.
86c1f859d4Smrg * Called via ctx->Driver.WaitQuery().
87c1f859d4Smrg */
884a49301eSmrgstatic void
893464ebd5Sriastradh_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
90c1f859d4Smrg{
91c1f859d4Smrg   /* For software drivers, _mesa_end_query() should have completed the query.
924a49301eSmrg    * For real hardware, implement a proper WaitQuery() driver function,
934a49301eSmrg    * which may require issuing a flush.
94c1f859d4Smrg    */
95c1f859d4Smrg   assert(q->Ready);
96c1f859d4Smrg}
97c1f859d4Smrg
98c1f859d4Smrg
994a49301eSmrg/**
1004a49301eSmrg * Check if a query results are ready.  Software driver fallback.
1014a49301eSmrg * Called via ctx->Driver.CheckQuery().
1024a49301eSmrg */
1034a49301eSmrgstatic void
1043464ebd5Sriastradh_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
1054a49301eSmrg{
1064a49301eSmrg   /* No-op for sw rendering.
1074a49301eSmrg    * HW drivers may need to flush at this time.
1084a49301eSmrg    */
1094a49301eSmrg}
1104a49301eSmrg
1114a49301eSmrg
112c1f859d4Smrg/**
113c1f859d4Smrg * Delete a query object.  Called via ctx->Driver.DeleteQuery().
1147117f1b4Smrg * Not removed from hash table here.
1157117f1b4Smrg */
1164a49301eSmrgstatic void
1173464ebd5Sriastradh_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
1187117f1b4Smrg{
119cdc920a0Smrg   free(q);
1207117f1b4Smrg}
1217117f1b4Smrg
1227117f1b4Smrg
1234a49301eSmrgvoid
1244a49301eSmrg_mesa_init_query_object_functions(struct dd_function_table *driver)
1254a49301eSmrg{
1264a49301eSmrg   driver->NewQueryObject = _mesa_new_query_object;
1274a49301eSmrg   driver->DeleteQuery = _mesa_delete_query;
1284a49301eSmrg   driver->BeginQuery = _mesa_begin_query;
1294a49301eSmrg   driver->EndQuery = _mesa_end_query;
1304a49301eSmrg   driver->WaitQuery = _mesa_wait_query;
1314a49301eSmrg   driver->CheckQuery = _mesa_check_query;
1324a49301eSmrg}
1334a49301eSmrg
1344a49301eSmrg
1353464ebd5Sriastradh/**
1363464ebd5Sriastradh * Return pointer to the query object binding point for the given target.
1373464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point
1383464ebd5Sriastradh */
1393464ebd5Sriastradhstatic struct gl_query_object **
1403464ebd5Sriastradhget_query_binding_point(struct gl_context *ctx, GLenum target)
1413464ebd5Sriastradh{
1423464ebd5Sriastradh   switch (target) {
1433464ebd5Sriastradh   case GL_SAMPLES_PASSED_ARB:
1443464ebd5Sriastradh      if (ctx->Extensions.ARB_occlusion_query)
1453464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1463464ebd5Sriastradh      else
1473464ebd5Sriastradh         return NULL;
1483464ebd5Sriastradh   case GL_ANY_SAMPLES_PASSED:
1493464ebd5Sriastradh      if (ctx->Extensions.ARB_occlusion_query2)
1503464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1513464ebd5Sriastradh      else
1523464ebd5Sriastradh         return NULL;
1533464ebd5Sriastradh   case GL_TIME_ELAPSED_EXT:
1543464ebd5Sriastradh      if (ctx->Extensions.EXT_timer_query)
1553464ebd5Sriastradh         return &ctx->Query.CurrentTimerObject;
1563464ebd5Sriastradh      else
1573464ebd5Sriastradh         return NULL;
1583464ebd5Sriastradh#if FEATURE_EXT_transform_feedback
1593464ebd5Sriastradh   case GL_PRIMITIVES_GENERATED:
1603464ebd5Sriastradh      if (ctx->Extensions.EXT_transform_feedback)
1613464ebd5Sriastradh         return &ctx->Query.PrimitivesGenerated;
1623464ebd5Sriastradh      else
1633464ebd5Sriastradh         return NULL;
1643464ebd5Sriastradh   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1653464ebd5Sriastradh      if (ctx->Extensions.EXT_transform_feedback)
1663464ebd5Sriastradh         return &ctx->Query.PrimitivesWritten;
1673464ebd5Sriastradh      else
1683464ebd5Sriastradh         return NULL;
1693464ebd5Sriastradh#endif
1703464ebd5Sriastradh   default:
1713464ebd5Sriastradh      return NULL;
1723464ebd5Sriastradh   }
1733464ebd5Sriastradh}
1743464ebd5Sriastradh
1753464ebd5Sriastradh
1763464ebd5Sriastradhstatic void GLAPIENTRY
1777117f1b4Smrg_mesa_GenQueriesARB(GLsizei n, GLuint *ids)
1787117f1b4Smrg{
1797117f1b4Smrg   GLuint first;
1807117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1817117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1827117f1b4Smrg
1833464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
1843464ebd5Sriastradh      _mesa_debug(ctx, "glGenQueries(%d)\n", n);
1853464ebd5Sriastradh
1867117f1b4Smrg   if (n < 0) {
1877117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
1887117f1b4Smrg      return;
1897117f1b4Smrg   }
1907117f1b4Smrg
1917117f1b4Smrg   /* No query objects can be active at this time! */
1927117f1b4Smrg   if (ctx->Query.CurrentOcclusionObject ||
1937117f1b4Smrg       ctx->Query.CurrentTimerObject) {
1947117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
1957117f1b4Smrg      return;
1967117f1b4Smrg   }
1977117f1b4Smrg
1987117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
1997117f1b4Smrg   if (first) {
2007117f1b4Smrg      GLsizei i;
2017117f1b4Smrg      for (i = 0; i < n; i++) {
2027117f1b4Smrg         struct gl_query_object *q
2037117f1b4Smrg            = ctx->Driver.NewQueryObject(ctx, first + i);
2047117f1b4Smrg         if (!q) {
2057117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
2067117f1b4Smrg            return;
2077117f1b4Smrg         }
2087117f1b4Smrg         ids[i] = first + i;
2097117f1b4Smrg         _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
2107117f1b4Smrg      }
2117117f1b4Smrg   }
2127117f1b4Smrg}
2137117f1b4Smrg
2147117f1b4Smrg
2153464ebd5Sriastradhstatic void GLAPIENTRY
2167117f1b4Smrg_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
2177117f1b4Smrg{
2187117f1b4Smrg   GLint i;
2197117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2207117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2213464ebd5Sriastradh   FLUSH_VERTICES(ctx, 0);
2223464ebd5Sriastradh
2233464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
2243464ebd5Sriastradh      _mesa_debug(ctx, "glDeleeteQueries(%d)\n", n);
2257117f1b4Smrg
2267117f1b4Smrg   if (n < 0) {
2277117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
2287117f1b4Smrg      return;
2297117f1b4Smrg   }
2307117f1b4Smrg
2317117f1b4Smrg   /* No query objects can be active at this time! */
2327117f1b4Smrg   if (ctx->Query.CurrentOcclusionObject ||
2337117f1b4Smrg       ctx->Query.CurrentTimerObject) {
2347117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
2357117f1b4Smrg      return;
2367117f1b4Smrg   }
2377117f1b4Smrg
2387117f1b4Smrg   for (i = 0; i < n; i++) {
2397117f1b4Smrg      if (ids[i] > 0) {
240cdc920a0Smrg         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
2417117f1b4Smrg         if (q) {
2427117f1b4Smrg            ASSERT(!q->Active); /* should be caught earlier */
2437117f1b4Smrg            _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
244c1f859d4Smrg            ctx->Driver.DeleteQuery(ctx, q);
2457117f1b4Smrg         }
2467117f1b4Smrg      }
2477117f1b4Smrg   }
2487117f1b4Smrg}
2497117f1b4Smrg
2507117f1b4Smrg
2513464ebd5Sriastradhstatic GLboolean GLAPIENTRY
2527117f1b4Smrg_mesa_IsQueryARB(GLuint id)
2537117f1b4Smrg{
2547117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2557117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
2567117f1b4Smrg
2573464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
2583464ebd5Sriastradh      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
2593464ebd5Sriastradh
260cdc920a0Smrg   if (id && _mesa_lookup_query_object(ctx, id))
2617117f1b4Smrg      return GL_TRUE;
2627117f1b4Smrg   else
2637117f1b4Smrg      return GL_FALSE;
2647117f1b4Smrg}
2657117f1b4Smrg
2667117f1b4Smrg
2674a49301eSmrgstatic void GLAPIENTRY
2687117f1b4Smrg_mesa_BeginQueryARB(GLenum target, GLuint id)
2697117f1b4Smrg{
2703464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
2717117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2727117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2737117f1b4Smrg
2743464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
2753464ebd5Sriastradh      _mesa_debug(ctx, "glBeginQuery(%s, %u)\n",
2763464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(target), id);
2773464ebd5Sriastradh
2787117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_DEPTH);
2797117f1b4Smrg
2803464ebd5Sriastradh   bindpt = get_query_binding_point(ctx, target);
2813464ebd5Sriastradh   if (!bindpt) {
2823464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
2833464ebd5Sriastradh      return;
2847117f1b4Smrg   }
2857117f1b4Smrg
2867117f1b4Smrg   if (id == 0) {
2877117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
2887117f1b4Smrg      return;
2897117f1b4Smrg   }
2907117f1b4Smrg
291cdc920a0Smrg   q = _mesa_lookup_query_object(ctx, id);
2927117f1b4Smrg   if (!q) {
2937117f1b4Smrg      /* create new object */
2947117f1b4Smrg      q = ctx->Driver.NewQueryObject(ctx, id);
2957117f1b4Smrg      if (!q) {
2967117f1b4Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
2977117f1b4Smrg         return;
2987117f1b4Smrg      }
2997117f1b4Smrg      _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
3007117f1b4Smrg   }
3017117f1b4Smrg   else {
3027117f1b4Smrg      /* pre-existing object */
3037117f1b4Smrg      if (q->Active) {
3047117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
3057117f1b4Smrg                     "glBeginQueryARB(query already active)");
3067117f1b4Smrg         return;
3077117f1b4Smrg      }
3087117f1b4Smrg   }
3097117f1b4Smrg
310c1f859d4Smrg   q->Target = target;
3117117f1b4Smrg   q->Active = GL_TRUE;
3127117f1b4Smrg   q->Result = 0;
3137117f1b4Smrg   q->Ready = GL_FALSE;
3147117f1b4Smrg
3153464ebd5Sriastradh   /* XXX should probably refcount query objects */
3163464ebd5Sriastradh   *bindpt = q;
3177117f1b4Smrg
318c1f859d4Smrg   ctx->Driver.BeginQuery(ctx, q);
3197117f1b4Smrg}
3207117f1b4Smrg
3217117f1b4Smrg
3224a49301eSmrgstatic void GLAPIENTRY
3237117f1b4Smrg_mesa_EndQueryARB(GLenum target)
3247117f1b4Smrg{
3253464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
3267117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3277117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3287117f1b4Smrg
3293464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
3303464ebd5Sriastradh      _mesa_debug(ctx, "glEndQuery(%s)\n", _mesa_lookup_enum_by_nr(target));
3313464ebd5Sriastradh
3327117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_DEPTH);
3337117f1b4Smrg
3343464ebd5Sriastradh   bindpt = get_query_binding_point(ctx, target);
3353464ebd5Sriastradh   if (!bindpt) {
3363464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3373464ebd5Sriastradh      return;
3387117f1b4Smrg   }
3397117f1b4Smrg
3403464ebd5Sriastradh   /* XXX should probably refcount query objects */
3413464ebd5Sriastradh   q = *bindpt;
3423464ebd5Sriastradh   *bindpt = NULL;
3433464ebd5Sriastradh
3447117f1b4Smrg   if (!q || !q->Active) {
3457117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
3467117f1b4Smrg                  "glEndQueryARB(no matching glBeginQueryARB)");
3477117f1b4Smrg      return;
3487117f1b4Smrg   }
3497117f1b4Smrg
3507117f1b4Smrg   q->Active = GL_FALSE;
351c1f859d4Smrg   ctx->Driver.EndQuery(ctx, q);
3527117f1b4Smrg}
3537117f1b4Smrg
3547117f1b4Smrg
3553464ebd5Sriastradhstatic void GLAPIENTRY
3567117f1b4Smrg_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
3577117f1b4Smrg{
3583464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
3597117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3607117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3617117f1b4Smrg
3623464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
3633464ebd5Sriastradh      _mesa_debug(ctx, "glGetQueryiv(%s, %s)\n",
3643464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(target),
3653464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(pname));
3663464ebd5Sriastradh
3673464ebd5Sriastradh   bindpt = get_query_binding_point(ctx, target);
3683464ebd5Sriastradh   if (!bindpt) {
3693464ebd5Sriastradh      _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
3703464ebd5Sriastradh      return;
3717117f1b4Smrg   }
3727117f1b4Smrg
3733464ebd5Sriastradh   q = *bindpt;
3743464ebd5Sriastradh
3757117f1b4Smrg   switch (pname) {
3767117f1b4Smrg      case GL_QUERY_COUNTER_BITS_ARB:
3777117f1b4Smrg         *params = 8 * sizeof(q->Result);
3787117f1b4Smrg         break;
3797117f1b4Smrg      case GL_CURRENT_QUERY_ARB:
3807117f1b4Smrg         *params = q ? q->Id : 0;
3817117f1b4Smrg         break;
3827117f1b4Smrg      default:
3837117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
3847117f1b4Smrg         return;
3857117f1b4Smrg   }
3867117f1b4Smrg}
3877117f1b4Smrg
3887117f1b4Smrg
3893464ebd5Sriastradhstatic void GLAPIENTRY
3907117f1b4Smrg_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
3917117f1b4Smrg{
3927117f1b4Smrg   struct gl_query_object *q = NULL;
3937117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3947117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3957117f1b4Smrg
3963464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
3973464ebd5Sriastradh      _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
3983464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(pname));
3993464ebd5Sriastradh
4007117f1b4Smrg   if (id)
401cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
4027117f1b4Smrg
4037117f1b4Smrg   if (!q || q->Active) {
4047117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4057117f1b4Smrg                  "glGetQueryObjectivARB(id=%d is invalid or active)", id);
4067117f1b4Smrg      return;
4077117f1b4Smrg   }
4087117f1b4Smrg
4097117f1b4Smrg   switch (pname) {
4107117f1b4Smrg      case GL_QUERY_RESULT_ARB:
411c1f859d4Smrg         if (!q->Ready)
412c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
4137117f1b4Smrg         /* if result is too large for returned type, clamp to max value */
4143464ebd5Sriastradh         if (q->Target == GL_ANY_SAMPLES_PASSED) {
4153464ebd5Sriastradh            if (q->Result)
4163464ebd5Sriastradh               *params = GL_TRUE;
4173464ebd5Sriastradh            else
4183464ebd5Sriastradh               *params = GL_FALSE;
4193464ebd5Sriastradh         } else {
4203464ebd5Sriastradh            if (q->Result > 0x7fffffff) {
4213464ebd5Sriastradh               *params = 0x7fffffff;
4223464ebd5Sriastradh            }
4233464ebd5Sriastradh            else {
4243464ebd5Sriastradh               *params = (GLint)q->Result;
4253464ebd5Sriastradh            }
4267117f1b4Smrg         }
4277117f1b4Smrg         break;
4287117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
429c1f859d4Smrg	 if (!q->Ready)
430c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
4317117f1b4Smrg         *params = q->Ready;
4327117f1b4Smrg         break;
4337117f1b4Smrg      default:
4347117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
4357117f1b4Smrg         return;
4367117f1b4Smrg   }
4377117f1b4Smrg}
4387117f1b4Smrg
4397117f1b4Smrg
4403464ebd5Sriastradhstatic void GLAPIENTRY
4417117f1b4Smrg_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
4427117f1b4Smrg{
4437117f1b4Smrg   struct gl_query_object *q = NULL;
4447117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4457117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
4467117f1b4Smrg
4473464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
4483464ebd5Sriastradh      _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
4493464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(pname));
4503464ebd5Sriastradh
4517117f1b4Smrg   if (id)
452cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
4537117f1b4Smrg
4547117f1b4Smrg   if (!q || q->Active) {
4557117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4567117f1b4Smrg                  "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
4577117f1b4Smrg      return;
4587117f1b4Smrg   }
4597117f1b4Smrg
4607117f1b4Smrg   switch (pname) {
4617117f1b4Smrg      case GL_QUERY_RESULT_ARB:
462c1f859d4Smrg         if (!q->Ready)
463c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
4647117f1b4Smrg         /* if result is too large for returned type, clamp to max value */
4653464ebd5Sriastradh         if (q->Target == GL_ANY_SAMPLES_PASSED) {
4663464ebd5Sriastradh            if (q->Result)
4673464ebd5Sriastradh               *params = GL_TRUE;
4683464ebd5Sriastradh            else
4693464ebd5Sriastradh               *params = GL_FALSE;
4703464ebd5Sriastradh         } else {
4713464ebd5Sriastradh            if (q->Result > 0xffffffff) {
4723464ebd5Sriastradh               *params = 0xffffffff;
4733464ebd5Sriastradh            }
4743464ebd5Sriastradh            else {
4753464ebd5Sriastradh               *params = (GLuint)q->Result;
4763464ebd5Sriastradh            }
4777117f1b4Smrg         }
4787117f1b4Smrg         break;
4797117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
480c1f859d4Smrg	 if (!q->Ready)
481c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
4827117f1b4Smrg         *params = q->Ready;
4837117f1b4Smrg         break;
4847117f1b4Smrg      default:
4857117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
4867117f1b4Smrg         return;
4877117f1b4Smrg   }
4887117f1b4Smrg}
4897117f1b4Smrg
4907117f1b4Smrg
4917117f1b4Smrg/**
4927117f1b4Smrg * New with GL_EXT_timer_query
4937117f1b4Smrg */
4944a49301eSmrgstatic void GLAPIENTRY
4957117f1b4Smrg_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
4967117f1b4Smrg{
4977117f1b4Smrg   struct gl_query_object *q = NULL;
4987117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4997117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
5007117f1b4Smrg
5013464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
5023464ebd5Sriastradh      _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
5033464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(pname));
5043464ebd5Sriastradh
5057117f1b4Smrg   if (id)
506cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
5077117f1b4Smrg
5087117f1b4Smrg   if (!q || q->Active) {
5097117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
5107117f1b4Smrg                  "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
5117117f1b4Smrg      return;
5127117f1b4Smrg   }
5137117f1b4Smrg
5147117f1b4Smrg   switch (pname) {
5157117f1b4Smrg      case GL_QUERY_RESULT_ARB:
516c1f859d4Smrg         if (!q->Ready)
517c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
5187117f1b4Smrg         *params = q->Result;
5197117f1b4Smrg         break;
5207117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
521c1f859d4Smrg	 if (!q->Ready)
522c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
5237117f1b4Smrg         *params = q->Ready;
5247117f1b4Smrg         break;
5257117f1b4Smrg      default:
5267117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
5277117f1b4Smrg         return;
5287117f1b4Smrg   }
5297117f1b4Smrg}
5307117f1b4Smrg
5317117f1b4Smrg
5327117f1b4Smrg/**
5337117f1b4Smrg * New with GL_EXT_timer_query
5347117f1b4Smrg */
5354a49301eSmrgstatic void GLAPIENTRY
5367117f1b4Smrg_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
5377117f1b4Smrg{
5387117f1b4Smrg   struct gl_query_object *q = NULL;
5397117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5407117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
5417117f1b4Smrg
5423464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
5433464ebd5Sriastradh      _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
5443464ebd5Sriastradh                  _mesa_lookup_enum_by_nr(pname));
5453464ebd5Sriastradh
5467117f1b4Smrg   if (id)
547cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
5487117f1b4Smrg
5497117f1b4Smrg   if (!q || q->Active) {
5507117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
5517117f1b4Smrg                  "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
5527117f1b4Smrg      return;
5537117f1b4Smrg   }
5547117f1b4Smrg
5557117f1b4Smrg   switch (pname) {
5567117f1b4Smrg      case GL_QUERY_RESULT_ARB:
557c1f859d4Smrg         if (!q->Ready)
558c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
5597117f1b4Smrg         *params = q->Result;
5607117f1b4Smrg         break;
5617117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
562c1f859d4Smrg	 if (!q->Ready)
563c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
5647117f1b4Smrg         *params = q->Ready;
5657117f1b4Smrg         break;
5667117f1b4Smrg      default:
5677117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
5687117f1b4Smrg         return;
5697117f1b4Smrg   }
5707117f1b4Smrg}
5717117f1b4Smrg
5724a49301eSmrg
5734a49301eSmrgvoid
5744a49301eSmrg_mesa_init_queryobj_dispatch(struct _glapi_table *disp)
5754a49301eSmrg{
5764a49301eSmrg   SET_GenQueriesARB(disp, _mesa_GenQueriesARB);
5774a49301eSmrg   SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB);
5784a49301eSmrg   SET_IsQueryARB(disp, _mesa_IsQueryARB);
5794a49301eSmrg   SET_BeginQueryARB(disp, _mesa_BeginQueryARB);
5804a49301eSmrg   SET_EndQueryARB(disp, _mesa_EndQueryARB);
5814a49301eSmrg   SET_GetQueryivARB(disp, _mesa_GetQueryivARB);
5824a49301eSmrg   SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB);
5834a49301eSmrg   SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB);
5844a49301eSmrg
5854a49301eSmrg   SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT);
5864a49301eSmrg   SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT);
5874a49301eSmrg}
5884a49301eSmrg
5894a49301eSmrg
5904a49301eSmrg#endif /* FEATURE_queryobj */
5917117f1b4Smrg
5927117f1b4Smrg
5937117f1b4Smrg/**
5947117f1b4Smrg * Allocate/init the context state related to query objects.
5957117f1b4Smrg */
5967117f1b4Smrgvoid
5973464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx)
5987117f1b4Smrg{
5997117f1b4Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
6007117f1b4Smrg   ctx->Query.CurrentOcclusionObject = NULL;
6017117f1b4Smrg}
6027117f1b4Smrg
6037117f1b4Smrg
6047117f1b4Smrg/**
6057117f1b4Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
6067117f1b4Smrg */
6077117f1b4Smrgstatic void
6087117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData)
6097117f1b4Smrg{
6107117f1b4Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
6113464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *)userData;
612c1f859d4Smrg   ctx->Driver.DeleteQuery(ctx, q);
6137117f1b4Smrg}
6147117f1b4Smrg
6157117f1b4Smrg
6167117f1b4Smrg/**
6177117f1b4Smrg * Free the context state related to query objects.
6187117f1b4Smrg */
6197117f1b4Smrgvoid
6203464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx)
6217117f1b4Smrg{
622c1f859d4Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
6237117f1b4Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
6247117f1b4Smrg}
625