Subversion Repositories Kolibri OS

Rev

Rev 4358 | 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.    first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
  205.    if (first) {
  206.       GLsizei i;
  207.       for (i = 0; i < n; i++) {
  208.          struct gl_query_object *q
  209.             = ctx->Driver.NewQueryObject(ctx, first + i);
  210.          if (!q) {
  211.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
  212.             return;
  213.          }
  214.          ids[i] = first + i;
  215.          _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
  216.       }
  217.    }
  218. }
  219.  
  220.  
  221. void GLAPIENTRY
  222. _mesa_DeleteQueries(GLsizei n, const GLuint *ids)
  223. {
  224.    GLint i;
  225.    GET_CURRENT_CONTEXT(ctx);
  226.    FLUSH_VERTICES(ctx, 0);
  227.  
  228.    if (MESA_VERBOSE & VERBOSE_API)
  229.       _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
  230.  
  231.    if (n < 0) {
  232.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
  233.       return;
  234.    }
  235.  
  236.    for (i = 0; i < n; i++) {
  237.       if (ids[i] > 0) {
  238.          struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
  239.          if (q) {
  240.             if (q->Active) {
  241.                struct gl_query_object **bindpt;
  242.                bindpt = get_query_binding_point(ctx, q->Target);
  243.                assert(bindpt); /* Should be non-null for active q. */
  244.                if (bindpt) {
  245.                   *bindpt = NULL;
  246.                }
  247.                q->Active = GL_FALSE;
  248.                ctx->Driver.EndQuery(ctx, q);
  249.             }
  250.             _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
  251.             ctx->Driver.DeleteQuery(ctx, q);
  252.          }
  253.       }
  254.    }
  255. }
  256.  
  257.  
  258. GLboolean GLAPIENTRY
  259. _mesa_IsQuery(GLuint id)
  260. {
  261.    struct gl_query_object *q;
  262.  
  263.    GET_CURRENT_CONTEXT(ctx);
  264.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  265.  
  266.    if (MESA_VERBOSE & VERBOSE_API)
  267.       _mesa_debug(ctx, "glIsQuery(%u)\n", id);
  268.  
  269.    if (id == 0)
  270.       return GL_FALSE;
  271.  
  272.    q = _mesa_lookup_query_object(ctx, id);
  273.    if (q == NULL)
  274.       return GL_FALSE;
  275.  
  276.    return q->EverBound;
  277. }
  278.  
  279. static GLboolean
  280. query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
  281. {
  282.    switch (target) {
  283.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  284.    case GL_PRIMITIVES_GENERATED:
  285.       if (index >= ctx->Const.MaxVertexStreams) {
  286.          _mesa_error(ctx, GL_INVALID_VALUE,
  287.                      "glBeginQueryIndexed(index>=MaxVertexStreams)");
  288.          return GL_FALSE;
  289.       }
  290.       break;
  291.    default:
  292.       if (index > 0) {
  293.          _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
  294.          return GL_FALSE;
  295.       }
  296.    }
  297.    return GL_TRUE;
  298. }
  299.  
  300. void GLAPIENTRY
  301. _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
  302. {
  303.    struct gl_query_object *q, **bindpt;
  304.    GET_CURRENT_CONTEXT(ctx);
  305.  
  306.    if (MESA_VERBOSE & VERBOSE_API)
  307.       _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
  308.                   _mesa_lookup_enum_by_nr(target), index, id);
  309.  
  310.    if (!query_error_check_index(ctx, target, index))
  311.       return;
  312.  
  313.    FLUSH_VERTICES(ctx, 0);
  314.  
  315.    bindpt = get_query_binding_point(ctx, target);
  316.    if (!bindpt) {
  317.       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
  318.       return;
  319.    }
  320.  
  321.    /* From the GL_ARB_occlusion_query spec:
  322.     *
  323.     *     "If BeginQueryARB is called while another query is already in
  324.     *      progress with the same target, an INVALID_OPERATION error is
  325.     *      generated."
  326.     */
  327.    if (*bindpt) {
  328.       _mesa_error(ctx, GL_INVALID_OPERATION,
  329.                   "glBeginQuery{Indexed}(target=%s is active)",
  330.                   _mesa_lookup_enum_by_nr(target));
  331.       return;
  332.    }
  333.  
  334.    if (id == 0) {
  335.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
  336.       return;
  337.    }
  338.  
  339.    q = _mesa_lookup_query_object(ctx, id);
  340.    if (!q) {
  341.       if (ctx->API != API_OPENGL_COMPAT) {
  342.          _mesa_error(ctx, GL_INVALID_OPERATION,
  343.                      "glBeginQuery{Indexed}(non-gen name)");
  344.          return;
  345.       } else {
  346.          /* create new object */
  347.          q = ctx->Driver.NewQueryObject(ctx, id);
  348.          if (!q) {
  349.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
  350.             return;
  351.          }
  352.          _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  353.       }
  354.    }
  355.    else {
  356.       /* pre-existing object */
  357.       if (q->Active) {
  358.          _mesa_error(ctx, GL_INVALID_OPERATION,
  359.                      "glBeginQuery{Indexed}(query already active)");
  360.          return;
  361.       }
  362.    }
  363.  
  364.    q->Target = target;
  365.    q->Active = GL_TRUE;
  366.    q->Result = 0;
  367.    q->Ready = GL_FALSE;
  368.    q->EverBound = GL_TRUE;
  369.  
  370.    /* XXX should probably refcount query objects */
  371.    *bindpt = q;
  372.  
  373.    ctx->Driver.BeginQuery(ctx, q);
  374. }
  375.  
  376.  
  377. void GLAPIENTRY
  378. _mesa_EndQueryIndexed(GLenum target, GLuint index)
  379. {
  380.    struct gl_query_object *q, **bindpt;
  381.    GET_CURRENT_CONTEXT(ctx);
  382.  
  383.    if (MESA_VERBOSE & VERBOSE_API)
  384.       _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
  385.                   _mesa_lookup_enum_by_nr(target), index);
  386.  
  387.    if (!query_error_check_index(ctx, target, index))
  388.       return;
  389.  
  390.    FLUSH_VERTICES(ctx, 0);
  391.  
  392.    bindpt = get_query_binding_point(ctx, target);
  393.    if (!bindpt) {
  394.       _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
  395.       return;
  396.    }
  397.  
  398.    /* XXX should probably refcount query objects */
  399.    q = *bindpt;
  400.  
  401.    /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
  402.    if (q && q->Target != target) {
  403.       _mesa_error(ctx, GL_INVALID_OPERATION,
  404.                   "glEndQuery(target=%s with active query of target %s)",
  405.                   _mesa_lookup_enum_by_nr(target),
  406.                   _mesa_lookup_enum_by_nr(q->Target));
  407.       return;
  408.    }
  409.  
  410.    *bindpt = NULL;
  411.  
  412.    if (!q || !q->Active) {
  413.       _mesa_error(ctx, GL_INVALID_OPERATION,
  414.                   "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
  415.       return;
  416.    }
  417.  
  418.    q->Active = GL_FALSE;
  419.    ctx->Driver.EndQuery(ctx, q);
  420. }
  421.  
  422. void GLAPIENTRY
  423. _mesa_BeginQuery(GLenum target, GLuint id)
  424. {
  425.    _mesa_BeginQueryIndexed(target, 0, id);
  426. }
  427.  
  428. void GLAPIENTRY
  429. _mesa_EndQuery(GLenum target)
  430. {
  431.    _mesa_EndQueryIndexed(target, 0);
  432. }
  433.  
  434. void GLAPIENTRY
  435. _mesa_QueryCounter(GLuint id, GLenum target)
  436. {
  437.    struct gl_query_object *q;
  438.    GET_CURRENT_CONTEXT(ctx);
  439.  
  440.    if (MESA_VERBOSE & VERBOSE_API)
  441.       _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
  442.                   _mesa_lookup_enum_by_nr(target));
  443.  
  444.    /* error checking */
  445.    if (target != GL_TIMESTAMP) {
  446.       _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
  447.       return;
  448.    }
  449.  
  450.    if (id == 0) {
  451.       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
  452.       return;
  453.    }
  454.  
  455.    q = _mesa_lookup_query_object(ctx, id);
  456.    if (!q) {
  457.       /* XXX the Core profile should throw INVALID_OPERATION here */
  458.  
  459.       /* create new object */
  460.       q = ctx->Driver.NewQueryObject(ctx, id);
  461.       if (!q) {
  462.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
  463.          return;
  464.       }
  465.       _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  466.    }
  467.    else {
  468.       if (q->Target && q->Target != GL_TIMESTAMP) {
  469.          _mesa_error(ctx, GL_INVALID_OPERATION,
  470.                      "glQueryCounter(id has an invalid target)");
  471.          return;
  472.       }
  473.    }
  474.  
  475.    if (q->Active) {
  476.       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
  477.       return;
  478.    }
  479.  
  480.    q->Target = target;
  481.    q->Result = 0;
  482.    q->Ready = GL_FALSE;
  483.    q->EverBound = GL_TRUE;
  484.  
  485.    if (ctx->Driver.QueryCounter) {
  486.       ctx->Driver.QueryCounter(ctx, q);
  487.    } else {
  488.       /* QueryCounter is implemented using EndQuery without BeginQuery
  489.        * in drivers. This is actually Direct3D and Gallium convention.
  490.        */
  491.       ctx->Driver.EndQuery(ctx, q);
  492.    }
  493. }
  494.  
  495.  
  496. void GLAPIENTRY
  497. _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
  498.                         GLint *params)
  499. {
  500.    struct gl_query_object *q = NULL, **bindpt = NULL;
  501.    GET_CURRENT_CONTEXT(ctx);
  502.  
  503.    if (MESA_VERBOSE & VERBOSE_API)
  504.       _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
  505.                   _mesa_lookup_enum_by_nr(target),
  506.                   index,
  507.                   _mesa_lookup_enum_by_nr(pname));
  508.  
  509.    if (!query_error_check_index(ctx, target, index))
  510.       return;
  511.  
  512.    if (target == GL_TIMESTAMP) {
  513.       if (!ctx->Extensions.ARB_timer_query) {
  514.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
  515.          return;
  516.       }
  517.    }
  518.    else {
  519.       bindpt = get_query_binding_point(ctx, target);
  520.       if (!bindpt) {
  521.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
  522.          return;
  523.       }
  524.  
  525.       q = *bindpt;
  526.    }
  527.  
  528.    switch (pname) {
  529.       case GL_QUERY_COUNTER_BITS_ARB:
  530.          switch (target) {
  531.          case GL_SAMPLES_PASSED:
  532.             *params = ctx->Const.QueryCounterBits.SamplesPassed;
  533.             break;
  534.          case GL_ANY_SAMPLES_PASSED:
  535.             /* The minimum value of this is 1 if it's nonzero, and the value
  536.              * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
  537.              * bits.
  538.              */
  539.             *params = 1;
  540.             break;
  541.          case GL_TIME_ELAPSED:
  542.             *params = ctx->Const.QueryCounterBits.TimeElapsed;
  543.             break;
  544.          case GL_TIMESTAMP:
  545.             *params = ctx->Const.QueryCounterBits.Timestamp;
  546.             break;
  547.          case GL_PRIMITIVES_GENERATED:
  548.             *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
  549.             break;
  550.          case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  551.             *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
  552.             break;
  553.          default:
  554.             _mesa_problem(ctx,
  555.                           "Unknown target in glGetQueryIndexediv(target = %s)",
  556.                           _mesa_lookup_enum_by_nr(target));
  557.             *params = 0;
  558.             break;
  559.          }
  560.          break;
  561.       case GL_CURRENT_QUERY_ARB:
  562.          *params = (q && q->Target == target) ? q->Id : 0;
  563.          break;
  564.       default:
  565.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
  566.          return;
  567.    }
  568. }
  569.  
  570. void GLAPIENTRY
  571. _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
  572. {
  573.    _mesa_GetQueryIndexediv(target, 0, pname, params);
  574. }
  575.  
  576. void GLAPIENTRY
  577. _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
  578. {
  579.    struct gl_query_object *q = NULL;
  580.    GET_CURRENT_CONTEXT(ctx);
  581.  
  582.    if (MESA_VERBOSE & VERBOSE_API)
  583.       _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
  584.                   _mesa_lookup_enum_by_nr(pname));
  585.  
  586.    if (id)
  587.       q = _mesa_lookup_query_object(ctx, id);
  588.  
  589.    if (!q || q->Active) {
  590.       _mesa_error(ctx, GL_INVALID_OPERATION,
  591.                   "glGetQueryObjectivARB(id=%d is invalid or active)", id);
  592.       return;
  593.    }
  594.  
  595.    switch (pname) {
  596.       case GL_QUERY_RESULT_ARB:
  597.          if (!q->Ready)
  598.             ctx->Driver.WaitQuery(ctx, q);
  599.          /* if result is too large for returned type, clamp to max value */
  600.          if (q->Target == GL_ANY_SAMPLES_PASSED
  601.              || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
  602.             if (q->Result)
  603.                *params = GL_TRUE;
  604.             else
  605.                *params = GL_FALSE;
  606.          } else {
  607.             if (q->Result > 0x7fffffff) {
  608.                *params = 0x7fffffff;
  609.             }
  610.             else {
  611.                *params = (GLint)q->Result;
  612.             }
  613.          }
  614.          break;
  615.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  616.          if (!q->Ready)
  617.             ctx->Driver.CheckQuery( ctx, q );
  618.          *params = q->Ready;
  619.          break;
  620.       default:
  621.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
  622.          return;
  623.    }
  624. }
  625.  
  626.  
  627. void GLAPIENTRY
  628. _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
  629. {
  630.    struct gl_query_object *q = NULL;
  631.    GET_CURRENT_CONTEXT(ctx);
  632.  
  633.    if (MESA_VERBOSE & VERBOSE_API)
  634.       _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
  635.                   _mesa_lookup_enum_by_nr(pname));
  636.  
  637.    if (id)
  638.       q = _mesa_lookup_query_object(ctx, id);
  639.  
  640.    if (!q || q->Active) {
  641.       _mesa_error(ctx, GL_INVALID_OPERATION,
  642.                   "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
  643.       return;
  644.    }
  645.  
  646.    switch (pname) {
  647.       case GL_QUERY_RESULT_ARB:
  648.          if (!q->Ready)
  649.             ctx->Driver.WaitQuery(ctx, q);
  650.          /* if result is too large for returned type, clamp to max value */
  651.          if (q->Target == GL_ANY_SAMPLES_PASSED
  652.              || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
  653.             if (q->Result)
  654.                *params = GL_TRUE;
  655.             else
  656.                *params = GL_FALSE;
  657.          } else {
  658.             if (q->Result > 0xffffffff) {
  659.                *params = 0xffffffff;
  660.             }
  661.             else {
  662.                *params = (GLuint)q->Result;
  663.             }
  664.          }
  665.          break;
  666.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  667.          if (!q->Ready)
  668.             ctx->Driver.CheckQuery( ctx, q );
  669.          *params = q->Ready;
  670.          break;
  671.       default:
  672.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
  673.          return;
  674.    }
  675. }
  676.  
  677.  
  678. /**
  679.  * New with GL_EXT_timer_query
  680.  */
  681. void GLAPIENTRY
  682. _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
  683. {
  684.    struct gl_query_object *q = NULL;
  685.    GET_CURRENT_CONTEXT(ctx);
  686.  
  687.    if (MESA_VERBOSE & VERBOSE_API)
  688.       _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
  689.                   _mesa_lookup_enum_by_nr(pname));
  690.  
  691.    if (id)
  692.       q = _mesa_lookup_query_object(ctx, id);
  693.  
  694.    if (!q || q->Active) {
  695.       _mesa_error(ctx, GL_INVALID_OPERATION,
  696.                   "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
  697.       return;
  698.    }
  699.  
  700.    switch (pname) {
  701.       case GL_QUERY_RESULT_ARB:
  702.          if (!q->Ready)
  703.             ctx->Driver.WaitQuery(ctx, q);
  704.          *params = q->Result;
  705.          break;
  706.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  707.          if (!q->Ready)
  708.             ctx->Driver.CheckQuery( ctx, q );
  709.          *params = q->Ready;
  710.          break;
  711.       default:
  712.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
  713.          return;
  714.    }
  715. }
  716.  
  717.  
  718. /**
  719.  * New with GL_EXT_timer_query
  720.  */
  721. void GLAPIENTRY
  722. _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
  723. {
  724.    struct gl_query_object *q = NULL;
  725.    GET_CURRENT_CONTEXT(ctx);
  726.  
  727.    if (MESA_VERBOSE & VERBOSE_API)
  728.       _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
  729.                   _mesa_lookup_enum_by_nr(pname));
  730.  
  731.    if (id)
  732.       q = _mesa_lookup_query_object(ctx, id);
  733.  
  734.    if (!q || q->Active) {
  735.       _mesa_error(ctx, GL_INVALID_OPERATION,
  736.                   "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
  737.       return;
  738.    }
  739.  
  740.    switch (pname) {
  741.       case GL_QUERY_RESULT_ARB:
  742.          if (!q->Ready)
  743.             ctx->Driver.WaitQuery(ctx, q);
  744.          *params = q->Result;
  745.          break;
  746.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  747.          if (!q->Ready)
  748.             ctx->Driver.CheckQuery( ctx, q );
  749.          *params = q->Ready;
  750.          break;
  751.       default:
  752.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
  753.          return;
  754.    }
  755. }
  756.  
  757. /**
  758.  * Allocate/init the context state related to query objects.
  759.  */
  760. void
  761. _mesa_init_queryobj(struct gl_context *ctx)
  762. {
  763.    ctx->Query.QueryObjects = _mesa_NewHashTable();
  764.    ctx->Query.CurrentOcclusionObject = NULL;
  765.  
  766.    ctx->Const.QueryCounterBits.SamplesPassed = 64;
  767.    ctx->Const.QueryCounterBits.TimeElapsed = 64;
  768.    ctx->Const.QueryCounterBits.Timestamp = 64;
  769.    ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
  770.    ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
  771. }
  772.  
  773.  
  774. /**
  775.  * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
  776.  */
  777. static void
  778. delete_queryobj_cb(GLuint id, void *data, void *userData)
  779. {
  780.    struct gl_query_object *q= (struct gl_query_object *) data;
  781.    struct gl_context *ctx = (struct gl_context *)userData;
  782.    ctx->Driver.DeleteQuery(ctx, q);
  783. }
  784.  
  785.  
  786. /**
  787.  * Free the context state related to query objects.
  788.  */
  789. void
  790. _mesa_free_queryobj_data(struct gl_context *ctx)
  791. {
  792.    _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
  793.    _mesa_DeleteHashTable(ctx->Query.QueryObjects);
  794. }
  795.