Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.1
      4  *
      5  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 
     26 #include "glheader.h"
     27 #include "context.h"
     28 #include "enums.h"
     29 #include "hash.h"
     30 #include "imports.h"
     31 #include "queryobj.h"
     32 #include "mfeatures.h"
     33 #include "mtypes.h"
     34 #include "main/dispatch.h"
     35 
     36 
     37 #if FEATURE_queryobj
     38 
     39 
     40 /**
     41  * Allocate a new query object.  This is a fallback routine called via
     42  * ctx->Driver.NewQueryObject().
     43  * \param ctx - rendering context
     44  * \param id - the new object's ID
     45  * \return pointer to new query_object object or NULL if out of memory.
     46  */
     47 static struct gl_query_object *
     48 _mesa_new_query_object(struct gl_context *ctx, GLuint id)
     49 {
     50    struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
     51    (void) ctx;
     52    if (q) {
     53       q->Id = id;
     54       q->Result = 0;
     55       q->Active = GL_FALSE;
     56       q->Ready = GL_TRUE;   /* correct, see spec */
     57    }
     58    return q;
     59 }
     60 
     61 
     62 /**
     63  * Begin a query.  Software driver fallback.
     64  * Called via ctx->Driver.BeginQuery().
     65  */
     66 static void
     67 _mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
     68 {
     69    /* no-op */
     70 }
     71 
     72 
     73 /**
     74  * End a query.  Software driver fallback.
     75  * Called via ctx->Driver.EndQuery().
     76  */
     77 static void
     78 _mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
     79 {
     80    q->Ready = GL_TRUE;
     81 }
     82 
     83 
     84 /**
     85  * Wait for query to complete.  Software driver fallback.
     86  * Called via ctx->Driver.WaitQuery().
     87  */
     88 static void
     89 _mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
     90 {
     91    /* For software drivers, _mesa_end_query() should have completed the query.
     92     * For real hardware, implement a proper WaitQuery() driver function,
     93     * which may require issuing a flush.
     94     */
     95    assert(q->Ready);
     96 }
     97 
     98 
     99 /**
    100  * Check if a query results are ready.  Software driver fallback.
    101  * Called via ctx->Driver.CheckQuery().
    102  */
    103 static void
    104 _mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
    105 {
    106    /* No-op for sw rendering.
    107     * HW drivers may need to flush at this time.
    108     */
    109 }
    110 
    111 
    112 /**
    113  * Delete a query object.  Called via ctx->Driver.DeleteQuery().
    114  * Not removed from hash table here.
    115  */
    116 static void
    117 _mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
    118 {
    119    free(q);
    120 }
    121 
    122 
    123 void
    124 _mesa_init_query_object_functions(struct dd_function_table *driver)
    125 {
    126    driver->NewQueryObject = _mesa_new_query_object;
    127    driver->DeleteQuery = _mesa_delete_query;
    128    driver->BeginQuery = _mesa_begin_query;
    129    driver->EndQuery = _mesa_end_query;
    130    driver->WaitQuery = _mesa_wait_query;
    131    driver->CheckQuery = _mesa_check_query;
    132 }
    133 
    134 
    135 /**
    136  * Return pointer to the query object binding point for the given target.
    137  * \return NULL if invalid target, else the address of binding point
    138  */
    139 static struct gl_query_object **
    140 get_query_binding_point(struct gl_context *ctx, GLenum target)
    141 {
    142    switch (target) {
    143    case GL_SAMPLES_PASSED_ARB:
    144       if (ctx->Extensions.ARB_occlusion_query)
    145          return &ctx->Query.CurrentOcclusionObject;
    146       else
    147          return NULL;
    148    case GL_ANY_SAMPLES_PASSED:
    149       if (ctx->Extensions.ARB_occlusion_query2)
    150          return &ctx->Query.CurrentOcclusionObject;
    151       else
    152          return NULL;
    153    case GL_TIME_ELAPSED_EXT:
    154       if (ctx->Extensions.EXT_timer_query)
    155          return &ctx->Query.CurrentTimerObject;
    156       else
    157          return NULL;
    158 #if FEATURE_EXT_transform_feedback
    159    case GL_PRIMITIVES_GENERATED:
    160       if (ctx->Extensions.EXT_transform_feedback)
    161          return &ctx->Query.PrimitivesGenerated;
    162       else
    163          return NULL;
    164    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
    165       if (ctx->Extensions.EXT_transform_feedback)
    166          return &ctx->Query.PrimitivesWritten;
    167       else
    168          return NULL;
    169 #endif
    170    default:
    171       return NULL;
    172    }
    173 }
    174 
    175 
    176 static void GLAPIENTRY
    177 _mesa_GenQueriesARB(GLsizei n, GLuint *ids)
    178 {
    179    GLuint first;
    180    GET_CURRENT_CONTEXT(ctx);
    181    ASSERT_OUTSIDE_BEGIN_END(ctx);
    182 
    183    if (MESA_VERBOSE & VERBOSE_API)
    184       _mesa_debug(ctx, "glGenQueries(%d)\n", n);
    185 
    186    if (n < 0) {
    187       _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
    188       return;
    189    }
    190 
    191    /* No query objects can be active at this time! */
    192    if (ctx->Query.CurrentOcclusionObject ||
    193        ctx->Query.CurrentTimerObject) {
    194       _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
    195       return;
    196    }
    197 
    198    first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
    199    if (first) {
    200       GLsizei i;
    201       for (i = 0; i < n; i++) {
    202          struct gl_query_object *q
    203             = ctx->Driver.NewQueryObject(ctx, first + i);
    204          if (!q) {
    205             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
    206             return;
    207          }
    208          ids[i] = first + i;
    209          _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
    210       }
    211    }
    212 }
    213 
    214 
    215 static void GLAPIENTRY
    216 _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
    217 {
    218    GLint i;
    219    GET_CURRENT_CONTEXT(ctx);
    220    ASSERT_OUTSIDE_BEGIN_END(ctx);
    221    FLUSH_VERTICES(ctx, 0);
    222 
    223    if (MESA_VERBOSE & VERBOSE_API)
    224       _mesa_debug(ctx, "glDeleeteQueries(%d)\n", n);
    225 
    226    if (n < 0) {
    227       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
    228       return;
    229    }
    230 
    231    /* No query objects can be active at this time! */
    232    if (ctx->Query.CurrentOcclusionObject ||
    233        ctx->Query.CurrentTimerObject) {
    234       _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
    235       return;
    236    }
    237 
    238    for (i = 0; i < n; i++) {
    239       if (ids[i] > 0) {
    240          struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
    241          if (q) {
    242             ASSERT(!q->Active); /* should be caught earlier */
    243             _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
    244             ctx->Driver.DeleteQuery(ctx, q);
    245          }
    246       }
    247    }
    248 }
    249 
    250 
    251 static GLboolean GLAPIENTRY
    252 _mesa_IsQueryARB(GLuint id)
    253 {
    254    GET_CURRENT_CONTEXT(ctx);
    255    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
    256 
    257    if (MESA_VERBOSE & VERBOSE_API)
    258       _mesa_debug(ctx, "glIsQuery(%u)\n", id);
    259 
    260    if (id && _mesa_lookup_query_object(ctx, id))
    261       return GL_TRUE;
    262    else
    263       return GL_FALSE;
    264 }
    265 
    266 static GLboolean
    267 query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
    268 {
    269    switch (target) {
    270    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
    271    case GL_PRIMITIVES_GENERATED:
    272       if (index >= ctx->Const.MaxVertexStreams) {
    273          _mesa_error(ctx, GL_INVALID_VALUE,
    274                      "glBeginQueryIndexed(index>=MaxVertexStreams)");
    275          return GL_FALSE;
    276       }
    277       break;
    278    default:
    279       if (index > 0) {
    280          _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
    281          return GL_FALSE;
    282       }
    283    }
    284    return GL_TRUE;
    285 }
    286 
    287 static void GLAPIENTRY
    288 _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
    289 {
    290    struct gl_query_object *q, **bindpt;
    291    GET_CURRENT_CONTEXT(ctx);
    292    ASSERT_OUTSIDE_BEGIN_END(ctx);
    293 
    294    if (MESA_VERBOSE & VERBOSE_API)
    295       _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
    296                   _mesa_lookup_enum_by_nr(target), index, id);
    297 
    298    if (!query_error_check_index(ctx, target, index))
    299       return;
    300 
    301    FLUSH_VERTICES(ctx, _NEW_DEPTH);
    302 
    303    bindpt = get_query_binding_point(ctx, target);
    304    if (!bindpt) {
    305       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
    306       return;
    307    }
    308 
    309    if (id == 0) {
    310       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
    311       return;
    312    }
    313 
    314    q = _mesa_lookup_query_object(ctx, id);
    315    if (!q) {
    316       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 
    351 static 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 
    387 static void GLAPIENTRY
    388 _mesa_BeginQueryARB(GLenum target, GLuint id)
    389 {
    390    _mesa_BeginQueryIndexed(target, 0, id);
    391 }
    392 
    393 static void GLAPIENTRY
    394 _mesa_EndQueryARB(GLenum target)
    395 {
    396    _mesa_EndQueryIndexed(target, 0);
    397 }
    398 
    399 static 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 
    456 static 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 
    531 static void GLAPIENTRY
    532 _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
    533 {
    534    _mesa_GetQueryIndexediv(target, 0, pname, params);
    535 }
    536 
    537 static 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 
    588 static 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  */
    642 static 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  */
    683 static 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 
    721 void
    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  */
    749 void
    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  */
    766 static void
    767 delete_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  */
    778 void
    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