queryobj.c revision cdc920a0
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"
287117f1b4Smrg#include "hash.h"
297117f1b4Smrg#include "imports.h"
307117f1b4Smrg#include "queryobj.h"
317117f1b4Smrg#include "mtypes.h"
32cdc920a0Smrg#include "main/dispatch.h"
334a49301eSmrg
344a49301eSmrg
354a49301eSmrg#if FEATURE_queryobj
367117f1b4Smrg
377117f1b4Smrg
387117f1b4Smrg/**
397117f1b4Smrg * Allocate a new query object.  This is a fallback routine called via
407117f1b4Smrg * ctx->Driver.NewQueryObject().
417117f1b4Smrg * \param ctx - rendering context
427117f1b4Smrg * \param id - the new object's ID
437117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory.
447117f1b4Smrg */
454a49301eSmrgstatic struct gl_query_object *
467117f1b4Smrg_mesa_new_query_object(GLcontext *ctx, GLuint id)
477117f1b4Smrg{
487117f1b4Smrg   struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
497117f1b4Smrg   (void) ctx;
507117f1b4Smrg   if (q) {
517117f1b4Smrg      q->Id = id;
527117f1b4Smrg      q->Result = 0;
537117f1b4Smrg      q->Active = GL_FALSE;
547117f1b4Smrg      q->Ready = GL_TRUE;   /* correct, see spec */
557117f1b4Smrg   }
567117f1b4Smrg   return q;
577117f1b4Smrg}
587117f1b4Smrg
597117f1b4Smrg
607117f1b4Smrg/**
61c1f859d4Smrg * Begin a query.  Software driver fallback.
62c1f859d4Smrg * Called via ctx->Driver.BeginQuery().
63c1f859d4Smrg */
644a49301eSmrgstatic void
65c1f859d4Smrg_mesa_begin_query(GLcontext *ctx, struct gl_query_object *q)
66c1f859d4Smrg{
67c1f859d4Smrg   /* no-op */
68c1f859d4Smrg}
69c1f859d4Smrg
70c1f859d4Smrg
71c1f859d4Smrg/**
72c1f859d4Smrg * End a query.  Software driver fallback.
73c1f859d4Smrg * Called via ctx->Driver.EndQuery().
74c1f859d4Smrg */
754a49301eSmrgstatic void
76c1f859d4Smrg_mesa_end_query(GLcontext *ctx, struct gl_query_object *q)
77c1f859d4Smrg{
78c1f859d4Smrg   q->Ready = GL_TRUE;
79c1f859d4Smrg}
80c1f859d4Smrg
81c1f859d4Smrg
82c1f859d4Smrg/**
83c1f859d4Smrg * Wait for query to complete.  Software driver fallback.
84c1f859d4Smrg * Called via ctx->Driver.WaitQuery().
85c1f859d4Smrg */
864a49301eSmrgstatic void
87c1f859d4Smrg_mesa_wait_query(GLcontext *ctx, struct gl_query_object *q)
88c1f859d4Smrg{
89c1f859d4Smrg   /* For software drivers, _mesa_end_query() should have completed the query.
904a49301eSmrg    * For real hardware, implement a proper WaitQuery() driver function,
914a49301eSmrg    * which may require issuing a flush.
92c1f859d4Smrg    */
93c1f859d4Smrg   assert(q->Ready);
94c1f859d4Smrg}
95c1f859d4Smrg
96c1f859d4Smrg
974a49301eSmrg/**
984a49301eSmrg * Check if a query results are ready.  Software driver fallback.
994a49301eSmrg * Called via ctx->Driver.CheckQuery().
1004a49301eSmrg */
1014a49301eSmrgstatic void
1024a49301eSmrg_mesa_check_query(GLcontext *ctx, struct gl_query_object *q)
1034a49301eSmrg{
1044a49301eSmrg   /* No-op for sw rendering.
1054a49301eSmrg    * HW drivers may need to flush at this time.
1064a49301eSmrg    */
1074a49301eSmrg}
1084a49301eSmrg
1094a49301eSmrg
110c1f859d4Smrg/**
111c1f859d4Smrg * Delete a query object.  Called via ctx->Driver.DeleteQuery().
1127117f1b4Smrg * Not removed from hash table here.
1137117f1b4Smrg */
1144a49301eSmrgstatic void
115c1f859d4Smrg_mesa_delete_query(GLcontext *ctx, struct gl_query_object *q)
1167117f1b4Smrg{
117cdc920a0Smrg   free(q);
1187117f1b4Smrg}
1197117f1b4Smrg
1207117f1b4Smrg
1214a49301eSmrgvoid
1224a49301eSmrg_mesa_init_query_object_functions(struct dd_function_table *driver)
1234a49301eSmrg{
1244a49301eSmrg   driver->NewQueryObject = _mesa_new_query_object;
1254a49301eSmrg   driver->DeleteQuery = _mesa_delete_query;
1264a49301eSmrg   driver->BeginQuery = _mesa_begin_query;
1274a49301eSmrg   driver->EndQuery = _mesa_end_query;
1284a49301eSmrg   driver->WaitQuery = _mesa_wait_query;
1294a49301eSmrg   driver->CheckQuery = _mesa_check_query;
1304a49301eSmrg}
1314a49301eSmrg
1324a49301eSmrg
1337117f1b4Smrgvoid GLAPIENTRY
1347117f1b4Smrg_mesa_GenQueriesARB(GLsizei n, GLuint *ids)
1357117f1b4Smrg{
1367117f1b4Smrg   GLuint first;
1377117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1387117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1397117f1b4Smrg
1407117f1b4Smrg   if (n < 0) {
1417117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
1427117f1b4Smrg      return;
1437117f1b4Smrg   }
1447117f1b4Smrg
1457117f1b4Smrg   /* No query objects can be active at this time! */
1467117f1b4Smrg   if (ctx->Query.CurrentOcclusionObject ||
1477117f1b4Smrg       ctx->Query.CurrentTimerObject) {
1487117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
1497117f1b4Smrg      return;
1507117f1b4Smrg   }
1517117f1b4Smrg
1527117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
1537117f1b4Smrg   if (first) {
1547117f1b4Smrg      GLsizei i;
1557117f1b4Smrg      for (i = 0; i < n; i++) {
1567117f1b4Smrg         struct gl_query_object *q
1577117f1b4Smrg            = ctx->Driver.NewQueryObject(ctx, first + i);
1587117f1b4Smrg         if (!q) {
1597117f1b4Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
1607117f1b4Smrg            return;
1617117f1b4Smrg         }
1627117f1b4Smrg         ids[i] = first + i;
1637117f1b4Smrg         _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
1647117f1b4Smrg      }
1657117f1b4Smrg   }
1667117f1b4Smrg}
1677117f1b4Smrg
1687117f1b4Smrg
1697117f1b4Smrgvoid GLAPIENTRY
1707117f1b4Smrg_mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
1717117f1b4Smrg{
1727117f1b4Smrg   GLint i;
1737117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
1747117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
1757117f1b4Smrg
1767117f1b4Smrg   if (n < 0) {
1777117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
1787117f1b4Smrg      return;
1797117f1b4Smrg   }
1807117f1b4Smrg
1817117f1b4Smrg   /* No query objects can be active at this time! */
1827117f1b4Smrg   if (ctx->Query.CurrentOcclusionObject ||
1837117f1b4Smrg       ctx->Query.CurrentTimerObject) {
1847117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
1857117f1b4Smrg      return;
1867117f1b4Smrg   }
1877117f1b4Smrg
1887117f1b4Smrg   for (i = 0; i < n; i++) {
1897117f1b4Smrg      if (ids[i] > 0) {
190cdc920a0Smrg         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
1917117f1b4Smrg         if (q) {
1927117f1b4Smrg            ASSERT(!q->Active); /* should be caught earlier */
1937117f1b4Smrg            _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
194c1f859d4Smrg            ctx->Driver.DeleteQuery(ctx, q);
1957117f1b4Smrg         }
1967117f1b4Smrg      }
1977117f1b4Smrg   }
1987117f1b4Smrg}
1997117f1b4Smrg
2007117f1b4Smrg
2017117f1b4SmrgGLboolean GLAPIENTRY
2027117f1b4Smrg_mesa_IsQueryARB(GLuint id)
2037117f1b4Smrg{
2047117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2057117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
2067117f1b4Smrg
207cdc920a0Smrg   if (id && _mesa_lookup_query_object(ctx, id))
2087117f1b4Smrg      return GL_TRUE;
2097117f1b4Smrg   else
2107117f1b4Smrg      return GL_FALSE;
2117117f1b4Smrg}
2127117f1b4Smrg
2137117f1b4Smrg
2144a49301eSmrgstatic void GLAPIENTRY
2157117f1b4Smrg_mesa_BeginQueryARB(GLenum target, GLuint id)
2167117f1b4Smrg{
2177117f1b4Smrg   struct gl_query_object *q;
2187117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2197117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2207117f1b4Smrg
2217117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_DEPTH);
2227117f1b4Smrg
2237117f1b4Smrg   switch (target) {
2247117f1b4Smrg      case GL_SAMPLES_PASSED_ARB:
2257117f1b4Smrg         if (!ctx->Extensions.ARB_occlusion_query) {
2267117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
2277117f1b4Smrg            return;
2287117f1b4Smrg         }
2297117f1b4Smrg         if (ctx->Query.CurrentOcclusionObject) {
2307117f1b4Smrg            _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
2317117f1b4Smrg            return;
2327117f1b4Smrg         }
2337117f1b4Smrg         break;
2347117f1b4Smrg      case GL_TIME_ELAPSED_EXT:
2357117f1b4Smrg         if (!ctx->Extensions.EXT_timer_query) {
2367117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
2377117f1b4Smrg            return;
2387117f1b4Smrg         }
2397117f1b4Smrg         if (ctx->Query.CurrentTimerObject) {
2407117f1b4Smrg            _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
2417117f1b4Smrg            return;
2427117f1b4Smrg         }
2437117f1b4Smrg         break;
2447117f1b4Smrg      default:
2457117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
2467117f1b4Smrg         return;
2477117f1b4Smrg   }
2487117f1b4Smrg
2497117f1b4Smrg   if (id == 0) {
2507117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
2517117f1b4Smrg      return;
2527117f1b4Smrg   }
2537117f1b4Smrg
254cdc920a0Smrg   q = _mesa_lookup_query_object(ctx, id);
2557117f1b4Smrg   if (!q) {
2567117f1b4Smrg      /* create new object */
2577117f1b4Smrg      q = ctx->Driver.NewQueryObject(ctx, id);
2587117f1b4Smrg      if (!q) {
2597117f1b4Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
2607117f1b4Smrg         return;
2617117f1b4Smrg      }
2627117f1b4Smrg      _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
2637117f1b4Smrg   }
2647117f1b4Smrg   else {
2657117f1b4Smrg      /* pre-existing object */
2667117f1b4Smrg      if (q->Active) {
2677117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
2687117f1b4Smrg                     "glBeginQueryARB(query already active)");
2697117f1b4Smrg         return;
2707117f1b4Smrg      }
2717117f1b4Smrg   }
2727117f1b4Smrg
273c1f859d4Smrg   q->Target = target;
2747117f1b4Smrg   q->Active = GL_TRUE;
2757117f1b4Smrg   q->Result = 0;
2767117f1b4Smrg   q->Ready = GL_FALSE;
2777117f1b4Smrg
2787117f1b4Smrg   if (target == GL_SAMPLES_PASSED_ARB) {
2797117f1b4Smrg      ctx->Query.CurrentOcclusionObject = q;
2807117f1b4Smrg   }
2817117f1b4Smrg   else if (target == GL_TIME_ELAPSED_EXT) {
2827117f1b4Smrg      ctx->Query.CurrentTimerObject = q;
2837117f1b4Smrg   }
2847117f1b4Smrg
285c1f859d4Smrg   ctx->Driver.BeginQuery(ctx, q);
2867117f1b4Smrg}
2877117f1b4Smrg
2887117f1b4Smrg
2894a49301eSmrgstatic void GLAPIENTRY
2907117f1b4Smrg_mesa_EndQueryARB(GLenum target)
2917117f1b4Smrg{
2927117f1b4Smrg   struct gl_query_object *q;
2937117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
2947117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
2957117f1b4Smrg
2967117f1b4Smrg   FLUSH_VERTICES(ctx, _NEW_DEPTH);
2977117f1b4Smrg
2987117f1b4Smrg   switch (target) {
2997117f1b4Smrg      case GL_SAMPLES_PASSED_ARB:
3007117f1b4Smrg         if (!ctx->Extensions.ARB_occlusion_query) {
3017117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3027117f1b4Smrg            return;
3037117f1b4Smrg         }
3047117f1b4Smrg         q = ctx->Query.CurrentOcclusionObject;
3057117f1b4Smrg         ctx->Query.CurrentOcclusionObject = NULL;
3067117f1b4Smrg         break;
3077117f1b4Smrg      case GL_TIME_ELAPSED_EXT:
3087117f1b4Smrg         if (!ctx->Extensions.EXT_timer_query) {
3097117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3107117f1b4Smrg            return;
3117117f1b4Smrg         }
3127117f1b4Smrg         q = ctx->Query.CurrentTimerObject;
3137117f1b4Smrg         ctx->Query.CurrentTimerObject = NULL;
3147117f1b4Smrg         break;
3157117f1b4Smrg      default:
3167117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3177117f1b4Smrg         return;
3187117f1b4Smrg   }
3197117f1b4Smrg
3207117f1b4Smrg   if (!q || !q->Active) {
3217117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
3227117f1b4Smrg                  "glEndQueryARB(no matching glBeginQueryARB)");
3237117f1b4Smrg      return;
3247117f1b4Smrg   }
3257117f1b4Smrg
3267117f1b4Smrg   q->Active = GL_FALSE;
327c1f859d4Smrg   ctx->Driver.EndQuery(ctx, q);
3287117f1b4Smrg}
3297117f1b4Smrg
3307117f1b4Smrg
3317117f1b4Smrgvoid GLAPIENTRY
3327117f1b4Smrg_mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
3337117f1b4Smrg{
3347117f1b4Smrg   struct gl_query_object *q;
3357117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3367117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3377117f1b4Smrg
3387117f1b4Smrg   switch (target) {
3397117f1b4Smrg      case GL_SAMPLES_PASSED_ARB:
3407117f1b4Smrg         if (!ctx->Extensions.ARB_occlusion_query) {
3417117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3427117f1b4Smrg            return;
3437117f1b4Smrg         }
3447117f1b4Smrg         q = ctx->Query.CurrentOcclusionObject;
3457117f1b4Smrg         break;
3467117f1b4Smrg      case GL_TIME_ELAPSED_EXT:
3477117f1b4Smrg         if (!ctx->Extensions.EXT_timer_query) {
3487117f1b4Smrg            _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
3497117f1b4Smrg            return;
3507117f1b4Smrg         }
3517117f1b4Smrg         q = ctx->Query.CurrentTimerObject;
3527117f1b4Smrg         break;
3537117f1b4Smrg      default:
3547117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(target)");
3557117f1b4Smrg         return;
3567117f1b4Smrg   }
3577117f1b4Smrg
3587117f1b4Smrg   switch (pname) {
3597117f1b4Smrg      case GL_QUERY_COUNTER_BITS_ARB:
3607117f1b4Smrg         *params = 8 * sizeof(q->Result);
3617117f1b4Smrg         break;
3627117f1b4Smrg      case GL_CURRENT_QUERY_ARB:
3637117f1b4Smrg         *params = q ? q->Id : 0;
3647117f1b4Smrg         break;
3657117f1b4Smrg      default:
3667117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
3677117f1b4Smrg         return;
3687117f1b4Smrg   }
3697117f1b4Smrg}
3707117f1b4Smrg
3717117f1b4Smrg
3727117f1b4Smrgvoid GLAPIENTRY
3737117f1b4Smrg_mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
3747117f1b4Smrg{
3757117f1b4Smrg   struct gl_query_object *q = NULL;
3767117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3777117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
3787117f1b4Smrg
3797117f1b4Smrg   if (id)
380cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
3817117f1b4Smrg
3827117f1b4Smrg   if (!q || q->Active) {
3837117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
3847117f1b4Smrg                  "glGetQueryObjectivARB(id=%d is invalid or active)", id);
3857117f1b4Smrg      return;
3867117f1b4Smrg   }
3877117f1b4Smrg
3887117f1b4Smrg   switch (pname) {
3897117f1b4Smrg      case GL_QUERY_RESULT_ARB:
390c1f859d4Smrg         if (!q->Ready)
391c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
3927117f1b4Smrg         /* if result is too large for returned type, clamp to max value */
3937117f1b4Smrg         if (q->Result > 0x7fffffff) {
3947117f1b4Smrg            *params = 0x7fffffff;
3957117f1b4Smrg         }
3967117f1b4Smrg         else {
397c1f859d4Smrg            *params = (GLint)q->Result;
3987117f1b4Smrg         }
3997117f1b4Smrg         break;
4007117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
401c1f859d4Smrg	 if (!q->Ready)
402c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
4037117f1b4Smrg         *params = q->Ready;
4047117f1b4Smrg         break;
4057117f1b4Smrg      default:
4067117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
4077117f1b4Smrg         return;
4087117f1b4Smrg   }
4097117f1b4Smrg}
4107117f1b4Smrg
4117117f1b4Smrg
4127117f1b4Smrgvoid GLAPIENTRY
4137117f1b4Smrg_mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
4147117f1b4Smrg{
4157117f1b4Smrg   struct gl_query_object *q = NULL;
4167117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4177117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
4187117f1b4Smrg
4197117f1b4Smrg   if (id)
420cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
4217117f1b4Smrg
4227117f1b4Smrg   if (!q || q->Active) {
4237117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4247117f1b4Smrg                  "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
4257117f1b4Smrg      return;
4267117f1b4Smrg   }
4277117f1b4Smrg
4287117f1b4Smrg   switch (pname) {
4297117f1b4Smrg      case GL_QUERY_RESULT_ARB:
430c1f859d4Smrg         if (!q->Ready)
431c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
4327117f1b4Smrg         /* if result is too large for returned type, clamp to max value */
4337117f1b4Smrg         if (q->Result > 0xffffffff) {
4347117f1b4Smrg            *params = 0xffffffff;
4357117f1b4Smrg         }
4367117f1b4Smrg         else {
437c1f859d4Smrg            *params = (GLuint)q->Result;
4387117f1b4Smrg         }
4397117f1b4Smrg         break;
4407117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
441c1f859d4Smrg	 if (!q->Ready)
442c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
4437117f1b4Smrg         *params = q->Ready;
4447117f1b4Smrg         break;
4457117f1b4Smrg      default:
4467117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
4477117f1b4Smrg         return;
4487117f1b4Smrg   }
4497117f1b4Smrg}
4507117f1b4Smrg
4517117f1b4Smrg
4527117f1b4Smrg/**
4537117f1b4Smrg * New with GL_EXT_timer_query
4547117f1b4Smrg */
4554a49301eSmrgstatic void GLAPIENTRY
4567117f1b4Smrg_mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
4577117f1b4Smrg{
4587117f1b4Smrg   struct gl_query_object *q = NULL;
4597117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4607117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
4617117f1b4Smrg
4627117f1b4Smrg   if (id)
463cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
4647117f1b4Smrg
4657117f1b4Smrg   if (!q || q->Active) {
4667117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
4677117f1b4Smrg                  "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
4687117f1b4Smrg      return;
4697117f1b4Smrg   }
4707117f1b4Smrg
4717117f1b4Smrg   switch (pname) {
4727117f1b4Smrg      case GL_QUERY_RESULT_ARB:
473c1f859d4Smrg         if (!q->Ready)
474c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
4757117f1b4Smrg         *params = q->Result;
4767117f1b4Smrg         break;
4777117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
478c1f859d4Smrg	 if (!q->Ready)
479c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
4807117f1b4Smrg         *params = q->Ready;
4817117f1b4Smrg         break;
4827117f1b4Smrg      default:
4837117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
4847117f1b4Smrg         return;
4857117f1b4Smrg   }
4867117f1b4Smrg}
4877117f1b4Smrg
4887117f1b4Smrg
4897117f1b4Smrg/**
4907117f1b4Smrg * New with GL_EXT_timer_query
4917117f1b4Smrg */
4924a49301eSmrgstatic void GLAPIENTRY
4937117f1b4Smrg_mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
4947117f1b4Smrg{
4957117f1b4Smrg   struct gl_query_object *q = NULL;
4967117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4977117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END(ctx);
4987117f1b4Smrg
4997117f1b4Smrg   if (id)
500cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
5017117f1b4Smrg
5027117f1b4Smrg   if (!q || q->Active) {
5037117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
5047117f1b4Smrg                  "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
5057117f1b4Smrg      return;
5067117f1b4Smrg   }
5077117f1b4Smrg
5087117f1b4Smrg   switch (pname) {
5097117f1b4Smrg      case GL_QUERY_RESULT_ARB:
510c1f859d4Smrg         if (!q->Ready)
511c1f859d4Smrg            ctx->Driver.WaitQuery(ctx, q);
5127117f1b4Smrg         *params = q->Result;
5137117f1b4Smrg         break;
5147117f1b4Smrg      case GL_QUERY_RESULT_AVAILABLE_ARB:
515c1f859d4Smrg	 if (!q->Ready)
516c1f859d4Smrg	    ctx->Driver.CheckQuery( ctx, q );
5177117f1b4Smrg         *params = q->Ready;
5187117f1b4Smrg         break;
5197117f1b4Smrg      default:
5207117f1b4Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
5217117f1b4Smrg         return;
5227117f1b4Smrg   }
5237117f1b4Smrg}
5247117f1b4Smrg
5254a49301eSmrg
5264a49301eSmrgvoid
5274a49301eSmrg_mesa_init_queryobj_dispatch(struct _glapi_table *disp)
5284a49301eSmrg{
5294a49301eSmrg   SET_GenQueriesARB(disp, _mesa_GenQueriesARB);
5304a49301eSmrg   SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB);
5314a49301eSmrg   SET_IsQueryARB(disp, _mesa_IsQueryARB);
5324a49301eSmrg   SET_BeginQueryARB(disp, _mesa_BeginQueryARB);
5334a49301eSmrg   SET_EndQueryARB(disp, _mesa_EndQueryARB);
5344a49301eSmrg   SET_GetQueryivARB(disp, _mesa_GetQueryivARB);
5354a49301eSmrg   SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB);
5364a49301eSmrg   SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB);
5374a49301eSmrg
5384a49301eSmrg   SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT);
5394a49301eSmrg   SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT);
5404a49301eSmrg}
5414a49301eSmrg
5424a49301eSmrg
5434a49301eSmrg#endif /* FEATURE_queryobj */
5447117f1b4Smrg
5457117f1b4Smrg
5467117f1b4Smrg/**
5477117f1b4Smrg * Allocate/init the context state related to query objects.
5487117f1b4Smrg */
5497117f1b4Smrgvoid
5504a49301eSmrg_mesa_init_queryobj(GLcontext *ctx)
5517117f1b4Smrg{
5527117f1b4Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
5537117f1b4Smrg   ctx->Query.CurrentOcclusionObject = NULL;
5547117f1b4Smrg}
5557117f1b4Smrg
5567117f1b4Smrg
5577117f1b4Smrg/**
5587117f1b4Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
5597117f1b4Smrg */
5607117f1b4Smrgstatic void
5617117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData)
5627117f1b4Smrg{
5637117f1b4Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
564c1f859d4Smrg   GLcontext *ctx = (GLcontext *)userData;
565c1f859d4Smrg   ctx->Driver.DeleteQuery(ctx, q);
5667117f1b4Smrg}
5677117f1b4Smrg
5687117f1b4Smrg
5697117f1b4Smrg/**
5707117f1b4Smrg * Free the context state related to query objects.
5717117f1b4Smrg */
5727117f1b4Smrgvoid
5734a49301eSmrg_mesa_free_queryobj_data(GLcontext *ctx)
5747117f1b4Smrg{
575c1f859d4Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
5767117f1b4Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
5777117f1b4Smrg}
578