Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Mesa 3-D graphics library
  3.  *
  4.  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the "Software"),
  8.  * to deal in the Software without restriction, including without limitation
  9.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  10.  * and/or sell copies of the Software, and to permit persons to whom the
  11.  * Software is furnished to do so, subject to the following conditions:
  12.  *
  13.  * The above copyright notice and this permission notice shall be included
  14.  * in all copies or substantial portions of the Software.
  15.  *
  16.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  17.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  19.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  20.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  21.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  22.  * 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 "mtypes.h"
  33. #include "main/dispatch.h"
  34.  
  35.  
  36. /**
  37.  * Allocate a new query object.  This is a fallback routine called via
  38.  * ctx->Driver.NewQueryObject().
  39.  * \param ctx - rendering context
  40.  * \param id - the new object's ID
  41.  * \return pointer to new query_object object or NULL if out of memory.
  42.  */
  43. static struct gl_query_object *
  44. _mesa_new_query_object(struct gl_context *ctx, GLuint id)
  45. {
  46.    struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
  47.    (void) ctx;
  48.    if (q) {
  49.       q->Id = id;
  50.       q->Result = 0;
  51.       q->Active = GL_FALSE;
  52.  
  53.       /* This is to satisfy the language of the specification: "In the initial
  54.        * state of a query object, the result is available" (OpenGL 3.1 §
  55.        * 2.13).
  56.        */
  57.       q->Ready = GL_TRUE;
  58.  
  59.       /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as
  60.        * used, but no object is associated with them until the first time they
  61.        * are used by BeginQuery." Since our implementation actually does
  62.        * allocate an object at this point, use a flag to indicate that this
  63.        * object has not yet been bound so should not be considered a query.
  64.        */
  65.       q->EverBound = GL_FALSE;
  66.    }
  67.    return q;
  68. }
  69.  
  70.  
  71. /**
  72.  * Begin a query.  Software driver fallback.
  73.  * Called via ctx->Driver.BeginQuery().
  74.  */
  75. static void
  76. _mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
  77. {
  78.    ctx->NewState |= _NEW_DEPTH; /* for swrast */
  79. }
  80.  
  81.  
  82. /**
  83.  * End a query.  Software driver fallback.
  84.  * Called via ctx->Driver.EndQuery().
  85.  */
  86. static void
  87. _mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
  88. {
  89.    ctx->NewState |= _NEW_DEPTH; /* for swrast */
  90.    q->Ready = GL_TRUE;
  91. }
  92.  
  93.  
  94. /**
  95.  * Wait for query to complete.  Software driver fallback.
  96.  * Called via ctx->Driver.WaitQuery().
  97.  */
  98. static void
  99. _mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
  100. {
  101.    /* For software drivers, _mesa_end_query() should have completed the query.
  102.     * For real hardware, implement a proper WaitQuery() driver function,
  103.     * which may require issuing a flush.
  104.     */
  105.    assert(q->Ready);
  106. }
  107.  
  108.  
  109. /**
  110.  * Check if a query results are ready.  Software driver fallback.
  111.  * Called via ctx->Driver.CheckQuery().
  112.  */
  113. static void
  114. _mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
  115. {
  116.    /* No-op for sw rendering.
  117.     * HW drivers may need to flush at this time.
  118.     */
  119. }
  120.  
  121.  
  122. /**
  123.  * Delete a query object.  Called via ctx->Driver.DeleteQuery().
  124.  * Not removed from hash table here.
  125.  */
  126. static void
  127. _mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
  128. {
  129.    free(q);
  130. }
  131.  
  132.  
  133. void
  134. _mesa_init_query_object_functions(struct dd_function_table *driver)
  135. {
  136.    driver->NewQueryObject = _mesa_new_query_object;
  137.    driver->DeleteQuery = _mesa_delete_query;
  138.    driver->BeginQuery = _mesa_begin_query;
  139.    driver->EndQuery = _mesa_end_query;
  140.    driver->WaitQuery = _mesa_wait_query;
  141.    driver->CheckQuery = _mesa_check_query;
  142. }
  143.  
  144.  
  145. /**
  146.  * Return pointer to the query object binding point for the given target.
  147.  * \return NULL if invalid target, else the address of binding point
  148.  */
  149. static struct gl_query_object **
  150. get_query_binding_point(struct gl_context *ctx, GLenum target)
  151. {
  152.    switch (target) {
  153.    case GL_SAMPLES_PASSED_ARB:
  154.       if (ctx->Extensions.ARB_occlusion_query)
  155.          return &ctx->Query.CurrentOcclusionObject;
  156.       else
  157.          return NULL;
  158.    case GL_ANY_SAMPLES_PASSED:
  159.       if (ctx->Extensions.ARB_occlusion_query2)
  160.          return &ctx->Query.CurrentOcclusionObject;
  161.       else
  162.          return NULL;
  163.    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
  164.       if (ctx->Extensions.ARB_ES3_compatibility
  165.           || (ctx->API == API_OPENGLES2 && ctx->Version >= 30))
  166.          return &ctx->Query.CurrentOcclusionObject;
  167.       else
  168.          return NULL;
  169.    case GL_TIME_ELAPSED_EXT:
  170.       if (ctx->Extensions.EXT_timer_query)
  171.          return &ctx->Query.CurrentTimerObject;
  172.       else
  173.          return NULL;
  174.    case GL_PRIMITIVES_GENERATED:
  175.       if (ctx->Extensions.EXT_transform_feedback)
  176.          return &ctx->Query.PrimitivesGenerated;
  177.       else
  178.          return NULL;
  179.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  180.       if (ctx->Extensions.EXT_transform_feedback)
  181.          return &ctx->Query.PrimitivesWritten;
  182.       else
  183.          return NULL;
  184.    default:
  185.       return NULL;
  186.    }
  187. }
  188.  
  189.  
  190. void GLAPIENTRY
  191. _mesa_GenQueries(GLsizei n, GLuint *ids)
  192. {
  193.    GLuint first;
  194.    GET_CURRENT_CONTEXT(ctx);
  195.  
  196.    if (MESA_VERBOSE & VERBOSE_API)
  197.       _mesa_debug(ctx, "glGenQueries(%d)\n", n);
  198.  
  199.    if (n < 0) {
  200.       _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
  201.       return;
  202.    }
  203.  
  204.    /* No query objects can be active at this time! */
  205.    if (ctx->Query.CurrentOcclusionObject ||
  206.        ctx->Query.CurrentTimerObject) {
  207.       _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
  208.       return;
  209.    }
  210.  
  211.    first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
  212.    if (first) {
  213.       GLsizei i;
  214.       for (i = 0; i < n; i++) {
  215.          struct gl_query_object *q
  216.             = ctx->Driver.NewQueryObject(ctx, first + i);
  217.          if (!q) {
  218.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
  219.             return;
  220.          }
  221.          ids[i] = first + i;
  222.          _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
  223.       }
  224.    }
  225. }
  226.  
  227.  
  228. void GLAPIENTRY
  229. _mesa_DeleteQueries(GLsizei n, const GLuint *ids)
  230. {
  231.    GLint i;
  232.    GET_CURRENT_CONTEXT(ctx);
  233.    FLUSH_VERTICES(ctx, 0);
  234.  
  235.    if (MESA_VERBOSE & VERBOSE_API)
  236.       _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
  237.  
  238.    if (n < 0) {
  239.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
  240.       return;
  241.    }
  242.  
  243.    /* No query objects can be active at this time! */
  244.    if (ctx->Query.CurrentOcclusionObject ||
  245.        ctx->Query.CurrentTimerObject) {
  246.       _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
  247.       return;
  248.    }
  249.  
  250.    for (i = 0; i < n; i++) {
  251.       if (ids[i] > 0) {
  252.          struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
  253.          if (q) {
  254.             ASSERT(!q->Active); /* should be caught earlier */
  255.             _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
  256.             ctx->Driver.DeleteQuery(ctx, q);
  257.          }
  258.       }
  259.    }
  260. }
  261.  
  262.  
  263. GLboolean GLAPIENTRY
  264. _mesa_IsQuery(GLuint id)
  265. {
  266.    struct gl_query_object *q;
  267.  
  268.    GET_CURRENT_CONTEXT(ctx);
  269.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  270.  
  271.    if (MESA_VERBOSE & VERBOSE_API)
  272.       _mesa_debug(ctx, "glIsQuery(%u)\n", id);
  273.  
  274.    if (id == 0)
  275.       return GL_FALSE;
  276.  
  277.    q = _mesa_lookup_query_object(ctx, id);
  278.    if (q == NULL)
  279.       return GL_FALSE;
  280.  
  281.    return q->EverBound;
  282. }
  283.  
  284. static GLboolean
  285. query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
  286. {
  287.    switch (target) {
  288.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  289.    case GL_PRIMITIVES_GENERATED:
  290.       if (index >= ctx->Const.MaxVertexStreams) {
  291.          _mesa_error(ctx, GL_INVALID_VALUE,
  292.                      "glBeginQueryIndexed(index>=MaxVertexStreams)");
  293.          return GL_FALSE;
  294.       }
  295.       break;
  296.    default:
  297.       if (index > 0) {
  298.          _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
  299.          return GL_FALSE;
  300.       }
  301.    }
  302.    return GL_TRUE;
  303. }
  304.  
  305. void GLAPIENTRY
  306. _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
  307. {
  308.    struct gl_query_object *q, **bindpt;
  309.    GET_CURRENT_CONTEXT(ctx);
  310.  
  311.    if (MESA_VERBOSE & VERBOSE_API)
  312.       _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
  313.                   _mesa_lookup_enum_by_nr(target), index, id);
  314.  
  315.    if (!query_error_check_index(ctx, target, index))
  316.       return;
  317.  
  318.    FLUSH_VERTICES(ctx, 0);
  319.  
  320.    bindpt = get_query_binding_point(ctx, target);
  321.    if (!bindpt) {
  322.       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
  323.       return;
  324.    }
  325.  
  326.    /* From the GL_ARB_occlusion_query spec:
  327.     *
  328.     *     "If BeginQueryARB is called while another query is already in
  329.     *      progress with the same target, an INVALID_OPERATION error is
  330.     *      generated."
  331.     */
  332.    if (*bindpt) {
  333.       _mesa_error(ctx, GL_INVALID_OPERATION,
  334.                   "glBeginQuery{Indexed}(target=%s is active)",
  335.                   _mesa_lookup_enum_by_nr(target));
  336.       return;
  337.    }
  338.  
  339.    if (id == 0) {
  340.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
  341.       return;
  342.    }
  343.  
  344.    q = _mesa_lookup_query_object(ctx, id);
  345.    if (!q) {
  346.       if (ctx->API != API_OPENGL_COMPAT) {
  347.          _mesa_error(ctx, GL_INVALID_OPERATION,
  348.                      "glBeginQuery{Indexed}(non-gen name)");
  349.          return;
  350.       } else {
  351.          /* create new object */
  352.          q = ctx->Driver.NewQueryObject(ctx, id);
  353.          if (!q) {
  354.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
  355.             return;
  356.          }
  357.          _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  358.       }
  359.    }
  360.    else {
  361.       /* pre-existing object */
  362.       if (q->Active) {
  363.          _mesa_error(ctx, GL_INVALID_OPERATION,
  364.                      "glBeginQuery{Indexed}(query already active)");
  365.          return;
  366.       }
  367.    }
  368.  
  369.    q->Target = target;
  370.    q->Active = GL_TRUE;
  371.    q->Result = 0;
  372.    q->Ready = GL_FALSE;
  373.    q->EverBound = GL_TRUE;
  374.  
  375.    /* XXX should probably refcount query objects */
  376.    *bindpt = q;
  377.  
  378.    ctx->Driver.BeginQuery(ctx, q);
  379. }
  380.  
  381.  
  382. void GLAPIENTRY
  383. _mesa_EndQueryIndexed(GLenum target, GLuint index)
  384. {
  385.    struct gl_query_object *q, **bindpt;
  386.    GET_CURRENT_CONTEXT(ctx);
  387.  
  388.    if (MESA_VERBOSE & VERBOSE_API)
  389.       _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
  390.                   _mesa_lookup_enum_by_nr(target), index);
  391.  
  392.    if (!query_error_check_index(ctx, target, index))
  393.       return;
  394.  
  395.    FLUSH_VERTICES(ctx, 0);
  396.  
  397.    bindpt = get_query_binding_point(ctx, target);
  398.    if (!bindpt) {
  399.       _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
  400.       return;
  401.    }
  402.  
  403.    /* XXX should probably refcount query objects */
  404.    q = *bindpt;
  405.  
  406.    /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
  407.    if (q && q->Target != target) {
  408.       _mesa_error(ctx, GL_INVALID_OPERATION,
  409.                   "glEndQuery(target=%s with active query of target %s)",
  410.                   _mesa_lookup_enum_by_nr(target),
  411.                   _mesa_lookup_enum_by_nr(q->Target));
  412.       return;
  413.    }
  414.  
  415.    *bindpt = NULL;
  416.  
  417.    if (!q || !q->Active) {
  418.       _mesa_error(ctx, GL_INVALID_OPERATION,
  419.                   "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
  420.       return;
  421.    }
  422.  
  423.    q->Active = GL_FALSE;
  424.    ctx->Driver.EndQuery(ctx, q);
  425. }
  426.  
  427. void GLAPIENTRY
  428. _mesa_BeginQuery(GLenum target, GLuint id)
  429. {
  430.    _mesa_BeginQueryIndexed(target, 0, id);
  431. }
  432.  
  433. void GLAPIENTRY
  434. _mesa_EndQuery(GLenum target)
  435. {
  436.    _mesa_EndQueryIndexed(target, 0);
  437. }
  438.  
  439. void GLAPIENTRY
  440. _mesa_QueryCounter(GLuint id, GLenum target)
  441. {
  442.    struct gl_query_object *q;
  443.    GET_CURRENT_CONTEXT(ctx);
  444.  
  445.    if (MESA_VERBOSE & VERBOSE_API)
  446.       _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
  447.                   _mesa_lookup_enum_by_nr(target));
  448.  
  449.    /* error checking */
  450.    if (target != GL_TIMESTAMP) {
  451.       _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
  452.       return;
  453.    }
  454.  
  455.    if (id == 0) {
  456.       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
  457.       return;
  458.    }
  459.  
  460.    q = _mesa_lookup_query_object(ctx, id);
  461.    if (!q) {
  462.       /* XXX the Core profile should throw INVALID_OPERATION here */
  463.  
  464.       /* create new object */
  465.       q = ctx->Driver.NewQueryObject(ctx, id);
  466.       if (!q) {
  467.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
  468.          return;
  469.       }
  470.       _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  471.    }
  472.    else {
  473.       if (q->Target && q->Target != GL_TIMESTAMP) {
  474.          _mesa_error(ctx, GL_INVALID_OPERATION,
  475.                      "glQueryCounter(id has an invalid target)");
  476.          return;
  477.       }
  478.    }
  479.  
  480.    if (q->Active) {
  481.       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
  482.       return;
  483.    }
  484.  
  485.    q->Target = target;
  486.    q->Result = 0;
  487.    q->Ready = GL_FALSE;
  488.    q->EverBound = GL_TRUE;
  489.  
  490.    if (ctx->Driver.QueryCounter) {
  491.       ctx->Driver.QueryCounter(ctx, q);
  492.    } else {
  493.       /* QueryCounter is implemented using EndQuery without BeginQuery
  494.        * in drivers. This is actually Direct3D and Gallium convention.
  495.        */
  496.       ctx->Driver.EndQuery(ctx, q);
  497.    }
  498. }
  499.  
  500.  
  501. void GLAPIENTRY
  502. _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
  503.                         GLint *params)
  504. {
  505.    struct gl_query_object *q = NULL, **bindpt = NULL;
  506.    GET_CURRENT_CONTEXT(ctx);
  507.  
  508.    if (MESA_VERBOSE & VERBOSE_API)
  509.       _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
  510.                   _mesa_lookup_enum_by_nr(target),
  511.                   index,
  512.                   _mesa_lookup_enum_by_nr(pname));
  513.  
  514.    if (!query_error_check_index(ctx, target, index))
  515.       return;
  516.  
  517.    if (target == GL_TIMESTAMP) {
  518.       if (!ctx->Extensions.ARB_timer_query) {
  519.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
  520.          return;
  521.       }
  522.    }
  523.    else {
  524.       bindpt = get_query_binding_point(ctx, target);
  525.       if (!bindpt) {
  526.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
  527.          return;
  528.       }
  529.  
  530.       q = *bindpt;
  531.    }
  532.  
  533.    switch (pname) {
  534.       case GL_QUERY_COUNTER_BITS_ARB:
  535.          switch (target) {
  536.          case GL_SAMPLES_PASSED:
  537.             *params = ctx->Const.QueryCounterBits.SamplesPassed;
  538.             break;
  539.          case GL_ANY_SAMPLES_PASSED:
  540.             /* The minimum value of this is 1 if it's nonzero, and the value
  541.              * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
  542.              * bits.
  543.              */
  544.             *params = 1;
  545.             break;
  546.          case GL_TIME_ELAPSED:
  547.             *params = ctx->Const.QueryCounterBits.TimeElapsed;
  548.             break;
  549.          case GL_TIMESTAMP:
  550.             *params = ctx->Const.QueryCounterBits.Timestamp;
  551.             break;
  552.          case GL_PRIMITIVES_GENERATED:
  553.             *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
  554.             break;
  555.          case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  556.             *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
  557.             break;
  558.          default:
  559.             _mesa_problem(ctx,
  560.                           "Unknown target in glGetQueryIndexediv(target = %s)",
  561.                           _mesa_lookup_enum_by_nr(target));
  562.             *params = 0;
  563.             break;
  564.          }
  565.          break;
  566.       case GL_CURRENT_QUERY_ARB:
  567.          *params = (q && q->Target == target) ? q->Id : 0;
  568.          break;
  569.       default:
  570.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
  571.          return;
  572.    }
  573. }
  574.  
  575. void GLAPIENTRY
  576. _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
  577. {
  578.    _mesa_GetQueryIndexediv(target, 0, pname, params);
  579. }
  580.  
  581. void GLAPIENTRY
  582. _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
  583. {
  584.    struct gl_query_object *q = NULL;
  585.    GET_CURRENT_CONTEXT(ctx);
  586.  
  587.    if (MESA_VERBOSE & VERBOSE_API)
  588.       _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
  589.                   _mesa_lookup_enum_by_nr(pname));
  590.  
  591.    if (id)
  592.       q = _mesa_lookup_query_object(ctx, id);
  593.  
  594.    if (!q || q->Active) {
  595.       _mesa_error(ctx, GL_INVALID_OPERATION,
  596.                   "glGetQueryObjectivARB(id=%d is invalid or active)", id);
  597.       return;
  598.    }
  599.  
  600.    switch (pname) {
  601.       case GL_QUERY_RESULT_ARB:
  602.          if (!q->Ready)
  603.             ctx->Driver.WaitQuery(ctx, q);
  604.          /* if result is too large for returned type, clamp to max value */
  605.          if (q->Target == GL_ANY_SAMPLES_PASSED
  606.              || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
  607.             if (q->Result)
  608.                *params = GL_TRUE;
  609.             else
  610.                *params = GL_FALSE;
  611.          } else {
  612.             if (q->Result > 0x7fffffff) {
  613.                *params = 0x7fffffff;
  614.             }
  615.             else {
  616.                *params = (GLint)q->Result;
  617.             }
  618.          }
  619.          break;
  620.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  621.          if (!q->Ready)
  622.             ctx->Driver.CheckQuery( ctx, q );
  623.          *params = q->Ready;
  624.          break;
  625.       default:
  626.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
  627.          return;
  628.    }
  629. }
  630.  
  631.  
  632. void GLAPIENTRY
  633. _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
  634. {
  635.    struct gl_query_object *q = NULL;
  636.    GET_CURRENT_CONTEXT(ctx);
  637.  
  638.    if (MESA_VERBOSE & VERBOSE_API)
  639.       _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
  640.                   _mesa_lookup_enum_by_nr(pname));
  641.  
  642.    if (id)
  643.       q = _mesa_lookup_query_object(ctx, id);
  644.  
  645.    if (!q || q->Active) {
  646.       _mesa_error(ctx, GL_INVALID_OPERATION,
  647.                   "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
  648.       return;
  649.    }
  650.  
  651.    switch (pname) {
  652.       case GL_QUERY_RESULT_ARB:
  653.          if (!q->Ready)
  654.             ctx->Driver.WaitQuery(ctx, q);
  655.          /* if result is too large for returned type, clamp to max value */
  656.          if (q->Target == GL_ANY_SAMPLES_PASSED
  657.              || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
  658.             if (q->Result)
  659.                *params = GL_TRUE;
  660.             else
  661.                *params = GL_FALSE;
  662.          } else {
  663.             if (q->Result > 0xffffffff) {
  664.                *params = 0xffffffff;
  665.             }
  666.             else {
  667.                *params = (GLuint)q->Result;
  668.             }
  669.          }
  670.          break;
  671.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  672.          if (!q->Ready)
  673.             ctx->Driver.CheckQuery( ctx, q );
  674.          *params = q->Ready;
  675.          break;
  676.       default:
  677.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
  678.          return;
  679.    }
  680. }
  681.  
  682.  
  683. /**
  684.  * New with GL_EXT_timer_query
  685.  */
  686. void GLAPIENTRY
  687. _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
  688. {
  689.    struct gl_query_object *q = NULL;
  690.    GET_CURRENT_CONTEXT(ctx);
  691.  
  692.    if (MESA_VERBOSE & VERBOSE_API)
  693.       _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
  694.                   _mesa_lookup_enum_by_nr(pname));
  695.  
  696.    if (id)
  697.       q = _mesa_lookup_query_object(ctx, id);
  698.  
  699.    if (!q || q->Active) {
  700.       _mesa_error(ctx, GL_INVALID_OPERATION,
  701.                   "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
  702.       return;
  703.    }
  704.  
  705.    switch (pname) {
  706.       case GL_QUERY_RESULT_ARB:
  707.          if (!q->Ready)
  708.             ctx->Driver.WaitQuery(ctx, q);
  709.          *params = q->Result;
  710.          break;
  711.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  712.          if (!q->Ready)
  713.             ctx->Driver.CheckQuery( ctx, q );
  714.          *params = q->Ready;
  715.          break;
  716.       default:
  717.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
  718.          return;
  719.    }
  720. }
  721.  
  722.  
  723. /**
  724.  * New with GL_EXT_timer_query
  725.  */
  726. void GLAPIENTRY
  727. _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
  728. {
  729.    struct gl_query_object *q = NULL;
  730.    GET_CURRENT_CONTEXT(ctx);
  731.  
  732.    if (MESA_VERBOSE & VERBOSE_API)
  733.       _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
  734.                   _mesa_lookup_enum_by_nr(pname));
  735.  
  736.    if (id)
  737.       q = _mesa_lookup_query_object(ctx, id);
  738.  
  739.    if (!q || q->Active) {
  740.       _mesa_error(ctx, GL_INVALID_OPERATION,
  741.                   "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
  742.       return;
  743.    }
  744.  
  745.    switch (pname) {
  746.       case GL_QUERY_RESULT_ARB:
  747.          if (!q->Ready)
  748.             ctx->Driver.WaitQuery(ctx, q);
  749.          *params = q->Result;
  750.          break;
  751.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  752.          if (!q->Ready)
  753.             ctx->Driver.CheckQuery( ctx, q );
  754.          *params = q->Ready;
  755.          break;
  756.       default:
  757.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
  758.          return;
  759.    }
  760. }
  761.  
  762. /**
  763.  * Allocate/init the context state related to query objects.
  764.  */
  765. void
  766. _mesa_init_queryobj(struct gl_context *ctx)
  767. {
  768.    ctx->Query.QueryObjects = _mesa_NewHashTable();
  769.    ctx->Query.CurrentOcclusionObject = NULL;
  770.  
  771.    ctx->Const.QueryCounterBits.SamplesPassed = 64;
  772.    ctx->Const.QueryCounterBits.TimeElapsed = 64;
  773.    ctx->Const.QueryCounterBits.Timestamp = 64;
  774.    ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
  775.    ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
  776. }
  777.  
  778.  
  779. /**
  780.  * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
  781.  */
  782. static void
  783. delete_queryobj_cb(GLuint id, void *data, void *userData)
  784. {
  785.    struct gl_query_object *q= (struct gl_query_object *) data;
  786.    struct gl_context *ctx = (struct gl_context *)userData;
  787.    ctx->Driver.DeleteQuery(ctx, q);
  788. }
  789.  
  790.  
  791. /**
  792.  * Free the context state related to query objects.
  793.  */
  794. void
  795. _mesa_free_queryobj_data(struct gl_context *ctx)
  796. {
  797.    _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
  798.    _mesa_DeleteHashTable(ctx->Query.QueryObjects);
  799. }
  800.