Subversion Repositories Kolibri OS

Rev

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 = CALLOC_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->Label);
  130.    free(q);
  131. }
  132.  
  133.  
  134. void
  135. _mesa_init_query_object_functions(struct dd_function_table *driver)
  136. {
  137.    driver->NewQueryObject = _mesa_new_query_object;
  138.    driver->DeleteQuery = _mesa_delete_query;
  139.    driver->BeginQuery = _mesa_begin_query;
  140.    driver->EndQuery = _mesa_end_query;
  141.    driver->WaitQuery = _mesa_wait_query;
  142.    driver->CheckQuery = _mesa_check_query;
  143. }
  144.  
  145. static struct gl_query_object **
  146. get_pipe_stats_binding_point(struct gl_context *ctx,
  147.                              GLenum target)
  148. {
  149.    const int which = target - GL_VERTICES_SUBMITTED_ARB;
  150.    assert(which < MAX_PIPELINE_STATISTICS);
  151.  
  152.    if (!_mesa_is_desktop_gl(ctx) ||
  153.        !ctx->Extensions.ARB_pipeline_statistics_query)
  154.       return NULL;
  155.  
  156.    return &ctx->Query.pipeline_stats[which];
  157. }
  158.  
  159. /**
  160.  * Return pointer to the query object binding point for the given target and
  161.  * index.
  162.  * \return NULL if invalid target, else the address of binding point
  163.  */
  164. static struct gl_query_object **
  165. get_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
  166. {
  167.    switch (target) {
  168.    case GL_SAMPLES_PASSED_ARB:
  169.       if (ctx->Extensions.ARB_occlusion_query)
  170.          return &ctx->Query.CurrentOcclusionObject;
  171.       else
  172.          return NULL;
  173.    case GL_ANY_SAMPLES_PASSED:
  174.       if (ctx->Extensions.ARB_occlusion_query2)
  175.          return &ctx->Query.CurrentOcclusionObject;
  176.       else
  177.          return NULL;
  178.    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
  179.       if (ctx->Extensions.ARB_ES3_compatibility
  180.           || (ctx->API == API_OPENGLES2 && ctx->Version >= 30))
  181.          return &ctx->Query.CurrentOcclusionObject;
  182.       else
  183.          return NULL;
  184.    case GL_TIME_ELAPSED_EXT:
  185.       if (ctx->Extensions.EXT_timer_query)
  186.          return &ctx->Query.CurrentTimerObject;
  187.       else
  188.          return NULL;
  189.    case GL_PRIMITIVES_GENERATED:
  190.       if (ctx->Extensions.EXT_transform_feedback)
  191.          return &ctx->Query.PrimitivesGenerated[index];
  192.       else
  193.          return NULL;
  194.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  195.       if (ctx->Extensions.EXT_transform_feedback)
  196.          return &ctx->Query.PrimitivesWritten[index];
  197.       else
  198.          return NULL;
  199.  
  200.    case GL_VERTICES_SUBMITTED_ARB:
  201.    case GL_PRIMITIVES_SUBMITTED_ARB:
  202.    case GL_VERTEX_SHADER_INVOCATIONS_ARB:
  203.    case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
  204.    case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
  205.    case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
  206.          return get_pipe_stats_binding_point(ctx, target);
  207.  
  208.    case GL_GEOMETRY_SHADER_INVOCATIONS:
  209.       /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
  210.       target = GL_VERTICES_SUBMITTED_ARB + MAX_PIPELINE_STATISTICS - 1;
  211.       /* fallthrough */
  212.    case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
  213.       if (_mesa_has_geometry_shaders(ctx))
  214.          return get_pipe_stats_binding_point(ctx, target);
  215.       else
  216.          return NULL;
  217.  
  218.    case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
  219.    case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
  220.       if (ctx->Extensions.ARB_tessellation_shader)
  221.          return get_pipe_stats_binding_point(ctx, target);
  222.       else
  223.          return NULL;
  224.  
  225.    case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
  226.       if (_mesa_has_compute_shaders(ctx))
  227.          return get_pipe_stats_binding_point(ctx, target);
  228.       else
  229.          return NULL;
  230.  
  231.    default:
  232.       return NULL;
  233.    }
  234. }
  235.  
  236. /**
  237.  * Create $n query objects and store them in *ids. Make them of type $target
  238.  * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
  239.  */
  240. static void
  241. create_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
  242.                bool dsa)
  243. {
  244.    const char *func = dsa ? "glGenQueries" : "glCreateQueries";
  245.    GLuint first;
  246.  
  247.    if (MESA_VERBOSE & VERBOSE_API)
  248.       _mesa_debug(ctx, "%s(%d)\n", func, n);
  249.  
  250.    if (n < 0) {
  251.       _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
  252.       return;
  253.    }
  254.  
  255.    first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
  256.    if (first) {
  257.       GLsizei i;
  258.       for (i = 0; i < n; i++) {
  259.          struct gl_query_object *q
  260.             = ctx->Driver.NewQueryObject(ctx, first + i);
  261.          if (!q) {
  262.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
  263.             return;
  264.          } else if (dsa) {
  265.             /* Do the equivalent of binding the buffer with a target */
  266.             q->Target = target;
  267.             q->EverBound = GL_TRUE;
  268.          }
  269.          ids[i] = first + i;
  270.          _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
  271.       }
  272.    }
  273. }
  274.  
  275. void GLAPIENTRY
  276. _mesa_GenQueries(GLsizei n, GLuint *ids)
  277. {
  278.    GET_CURRENT_CONTEXT(ctx);
  279.    create_queries(ctx, 0, n, ids, false);
  280. }
  281.  
  282. void GLAPIENTRY
  283. _mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
  284. {
  285.    GET_CURRENT_CONTEXT(ctx);
  286.  
  287.    if (!ctx->Extensions.ARB_direct_state_access) {
  288.       _mesa_error(ctx, GL_INVALID_OPERATION,
  289.                   "glCreateQueries(GL_ARB_direct_state_access "
  290.                   "is not supported)");
  291.       return;
  292.    }
  293.  
  294.    switch (target) {
  295.    case GL_SAMPLES_PASSED:
  296.    case GL_ANY_SAMPLES_PASSED:
  297.    case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
  298.    case GL_TIME_ELAPSED:
  299.    case GL_TIMESTAMP:
  300.    case GL_PRIMITIVES_GENERATED:
  301.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  302.       break;
  303.    default:
  304.       _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
  305.                   _mesa_lookup_enum_by_nr(target));
  306.       return;
  307.    }
  308.  
  309.    create_queries(ctx, target, n, ids, true);
  310. }
  311.  
  312.  
  313. void GLAPIENTRY
  314. _mesa_DeleteQueries(GLsizei n, const GLuint *ids)
  315. {
  316.    GLint i;
  317.    GET_CURRENT_CONTEXT(ctx);
  318.    FLUSH_VERTICES(ctx, 0);
  319.  
  320.    if (MESA_VERBOSE & VERBOSE_API)
  321.       _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
  322.  
  323.    if (n < 0) {
  324.       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
  325.       return;
  326.    }
  327.  
  328.    for (i = 0; i < n; i++) {
  329.       if (ids[i] > 0) {
  330.          struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
  331.          if (q) {
  332.             if (q->Active) {
  333.                struct gl_query_object **bindpt;
  334.                bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
  335.                assert(bindpt); /* Should be non-null for active q. */
  336.                if (bindpt) {
  337.                   *bindpt = NULL;
  338.                }
  339.                q->Active = GL_FALSE;
  340.                ctx->Driver.EndQuery(ctx, q);
  341.             }
  342.             _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
  343.             ctx->Driver.DeleteQuery(ctx, q);
  344.          }
  345.       }
  346.    }
  347. }
  348.  
  349.  
  350. GLboolean GLAPIENTRY
  351. _mesa_IsQuery(GLuint id)
  352. {
  353.    struct gl_query_object *q;
  354.  
  355.    GET_CURRENT_CONTEXT(ctx);
  356.    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
  357.  
  358.    if (MESA_VERBOSE & VERBOSE_API)
  359.       _mesa_debug(ctx, "glIsQuery(%u)\n", id);
  360.  
  361.    if (id == 0)
  362.       return GL_FALSE;
  363.  
  364.    q = _mesa_lookup_query_object(ctx, id);
  365.    if (q == NULL)
  366.       return GL_FALSE;
  367.  
  368.    return q->EverBound;
  369. }
  370.  
  371. static GLboolean
  372. query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
  373. {
  374.    switch (target) {
  375.    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  376.    case GL_PRIMITIVES_GENERATED:
  377.       if (index >= ctx->Const.MaxVertexStreams) {
  378.          _mesa_error(ctx, GL_INVALID_VALUE,
  379.                      "glBeginQueryIndexed(index>=MaxVertexStreams)");
  380.          return GL_FALSE;
  381.       }
  382.       break;
  383.    default:
  384.       if (index > 0) {
  385.          _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
  386.          return GL_FALSE;
  387.       }
  388.    }
  389.    return GL_TRUE;
  390. }
  391.  
  392. void GLAPIENTRY
  393. _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
  394. {
  395.    struct gl_query_object *q, **bindpt;
  396.    GET_CURRENT_CONTEXT(ctx);
  397.  
  398.    if (MESA_VERBOSE & VERBOSE_API)
  399.       _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
  400.                   _mesa_lookup_enum_by_nr(target), index, id);
  401.  
  402.    if (!query_error_check_index(ctx, target, index))
  403.       return;
  404.  
  405.    FLUSH_VERTICES(ctx, 0);
  406.  
  407.    bindpt = get_query_binding_point(ctx, target, index);
  408.    if (!bindpt) {
  409.       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
  410.       return;
  411.    }
  412.  
  413.    /* From the GL_ARB_occlusion_query spec:
  414.     *
  415.     *     "If BeginQueryARB is called while another query is already in
  416.     *      progress with the same target, an INVALID_OPERATION error is
  417.     *      generated."
  418.     */
  419.    if (*bindpt) {
  420.       _mesa_error(ctx, GL_INVALID_OPERATION,
  421.                   "glBeginQuery{Indexed}(target=%s is active)",
  422.                   _mesa_lookup_enum_by_nr(target));
  423.       return;
  424.    }
  425.  
  426.    if (id == 0) {
  427.       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
  428.       return;
  429.    }
  430.  
  431.    q = _mesa_lookup_query_object(ctx, id);
  432.    if (!q) {
  433.       if (ctx->API != API_OPENGL_COMPAT) {
  434.          _mesa_error(ctx, GL_INVALID_OPERATION,
  435.                      "glBeginQuery{Indexed}(non-gen name)");
  436.          return;
  437.       } else {
  438.          /* create new object */
  439.          q = ctx->Driver.NewQueryObject(ctx, id);
  440.          if (!q) {
  441.             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
  442.             return;
  443.          }
  444.          _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  445.       }
  446.    }
  447.    else {
  448.       /* pre-existing object */
  449.       if (q->Active) {
  450.          _mesa_error(ctx, GL_INVALID_OPERATION,
  451.                      "glBeginQuery{Indexed}(query already active)");
  452.          return;
  453.       }
  454.  
  455.       /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
  456.        * spec states:
  457.        *
  458.        *     "BeginQuery generates an INVALID_OPERATION error if any of the
  459.        *      following conditions hold: [...] id is the name of an
  460.        *      existing query object whose type does not match target; [...]
  461.        *
  462.        * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
  463.        * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
  464.        */
  465.       if (q->EverBound && q->Target != target) {
  466.          _mesa_error(ctx, GL_INVALID_OPERATION,
  467.                      "glBeginQuery{Indexed}(target mismatch)");
  468.          return;
  469.       }
  470.    }
  471.  
  472.    /* This possibly changes the target of a buffer allocated by
  473.     * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
  474.     * the following:
  475.     *
  476.     * "CreateQueries adds a <target>, so strictly speaking the <target>
  477.     * command isn't needed for BeginQuery/EndQuery, but in the end, this also
  478.     * isn't a selector, so we decided not to change it."
  479.     *
  480.     * Updating the target of the query object should be acceptable, so let's
  481.     * do that.
  482.     */
  483.  
  484.    q->Target = target;
  485.    q->Active = GL_TRUE;
  486.    q->Result = 0;
  487.    q->Ready = GL_FALSE;
  488.    q->EverBound = GL_TRUE;
  489.    q->Stream = index;
  490.  
  491.    /* XXX should probably refcount query objects */
  492.    *bindpt = q;
  493.  
  494.    ctx->Driver.BeginQuery(ctx, q);
  495. }
  496.  
  497.  
  498. void GLAPIENTRY
  499. _mesa_EndQueryIndexed(GLenum target, GLuint index)
  500. {
  501.    struct gl_query_object *q, **bindpt;
  502.    GET_CURRENT_CONTEXT(ctx);
  503.  
  504.    if (MESA_VERBOSE & VERBOSE_API)
  505.       _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
  506.                   _mesa_lookup_enum_by_nr(target), index);
  507.  
  508.    if (!query_error_check_index(ctx, target, index))
  509.       return;
  510.  
  511.    FLUSH_VERTICES(ctx, 0);
  512.  
  513.    bindpt = get_query_binding_point(ctx, target, index);
  514.    if (!bindpt) {
  515.       _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
  516.       return;
  517.    }
  518.  
  519.    /* XXX should probably refcount query objects */
  520.    q = *bindpt;
  521.  
  522.    /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
  523.    if (q && q->Target != target) {
  524.       _mesa_error(ctx, GL_INVALID_OPERATION,
  525.                   "glEndQuery(target=%s with active query of target %s)",
  526.                   _mesa_lookup_enum_by_nr(target),
  527.                   _mesa_lookup_enum_by_nr(q->Target));
  528.       return;
  529.    }
  530.  
  531.    *bindpt = NULL;
  532.  
  533.    if (!q || !q->Active) {
  534.       _mesa_error(ctx, GL_INVALID_OPERATION,
  535.                   "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
  536.       return;
  537.    }
  538.  
  539.    q->Active = GL_FALSE;
  540.    ctx->Driver.EndQuery(ctx, q);
  541. }
  542.  
  543. void GLAPIENTRY
  544. _mesa_BeginQuery(GLenum target, GLuint id)
  545. {
  546.    _mesa_BeginQueryIndexed(target, 0, id);
  547. }
  548.  
  549. void GLAPIENTRY
  550. _mesa_EndQuery(GLenum target)
  551. {
  552.    _mesa_EndQueryIndexed(target, 0);
  553. }
  554.  
  555. void GLAPIENTRY
  556. _mesa_QueryCounter(GLuint id, GLenum target)
  557. {
  558.    struct gl_query_object *q;
  559.    GET_CURRENT_CONTEXT(ctx);
  560.  
  561.    if (MESA_VERBOSE & VERBOSE_API)
  562.       _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
  563.                   _mesa_lookup_enum_by_nr(target));
  564.  
  565.    /* error checking */
  566.    if (target != GL_TIMESTAMP) {
  567.       _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
  568.       return;
  569.    }
  570.  
  571.    if (id == 0) {
  572.       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
  573.       return;
  574.    }
  575.  
  576.    q = _mesa_lookup_query_object(ctx, id);
  577.    if (!q) {
  578.       /* XXX the Core profile should throw INVALID_OPERATION here */
  579.  
  580.       /* create new object */
  581.       q = ctx->Driver.NewQueryObject(ctx, id);
  582.       if (!q) {
  583.          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
  584.          return;
  585.       }
  586.       _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
  587.    }
  588.    else {
  589.       if (q->Target && q->Target != GL_TIMESTAMP) {
  590.          _mesa_error(ctx, GL_INVALID_OPERATION,
  591.                      "glQueryCounter(id has an invalid target)");
  592.          return;
  593.       }
  594.    }
  595.  
  596.    if (q->Active) {
  597.       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
  598.       return;
  599.    }
  600.  
  601.    /* This possibly changes the target of a buffer allocated by
  602.     * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
  603.     * the following:
  604.     *
  605.     * "CreateQueries adds a <target>, so strictly speaking the <target>
  606.     * command isn't needed for BeginQuery/EndQuery, but in the end, this also
  607.     * isn't a selector, so we decided not to change it."
  608.     *
  609.     * Updating the target of the query object should be acceptable, so let's
  610.     * do that.
  611.     */
  612.  
  613.    q->Target = target;
  614.    q->Result = 0;
  615.    q->Ready = GL_FALSE;
  616.    q->EverBound = GL_TRUE;
  617.  
  618.    if (ctx->Driver.QueryCounter) {
  619.       ctx->Driver.QueryCounter(ctx, q);
  620.    } else {
  621.       /* QueryCounter is implemented using EndQuery without BeginQuery
  622.        * in drivers. This is actually Direct3D and Gallium convention.
  623.        */
  624.       ctx->Driver.EndQuery(ctx, q);
  625.    }
  626. }
  627.  
  628.  
  629. void GLAPIENTRY
  630. _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
  631.                         GLint *params)
  632. {
  633.    struct gl_query_object *q = NULL, **bindpt = NULL;
  634.    GET_CURRENT_CONTEXT(ctx);
  635.  
  636.    if (MESA_VERBOSE & VERBOSE_API)
  637.       _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
  638.                   _mesa_lookup_enum_by_nr(target),
  639.                   index,
  640.                   _mesa_lookup_enum_by_nr(pname));
  641.  
  642.    if (!query_error_check_index(ctx, target, index))
  643.       return;
  644.  
  645.    if (target == GL_TIMESTAMP) {
  646.       if (!ctx->Extensions.ARB_timer_query) {
  647.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
  648.          return;
  649.       }
  650.    }
  651.    else {
  652.       bindpt = get_query_binding_point(ctx, target, index);
  653.       if (!bindpt) {
  654.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
  655.          return;
  656.       }
  657.  
  658.       q = *bindpt;
  659.    }
  660.  
  661.    switch (pname) {
  662.       case GL_QUERY_COUNTER_BITS_ARB:
  663.          switch (target) {
  664.          case GL_SAMPLES_PASSED:
  665.             *params = ctx->Const.QueryCounterBits.SamplesPassed;
  666.             break;
  667.          case GL_ANY_SAMPLES_PASSED:
  668.             /* The minimum value of this is 1 if it's nonzero, and the value
  669.              * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
  670.              * bits.
  671.              */
  672.             *params = 1;
  673.             break;
  674.          case GL_TIME_ELAPSED:
  675.             *params = ctx->Const.QueryCounterBits.TimeElapsed;
  676.             break;
  677.          case GL_TIMESTAMP:
  678.             *params = ctx->Const.QueryCounterBits.Timestamp;
  679.             break;
  680.          case GL_PRIMITIVES_GENERATED:
  681.             *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
  682.             break;
  683.          case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
  684.             *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
  685.             break;
  686.          case GL_VERTICES_SUBMITTED_ARB:
  687.             *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
  688.             break;
  689.          case GL_PRIMITIVES_SUBMITTED_ARB:
  690.             *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
  691.             break;
  692.          case GL_VERTEX_SHADER_INVOCATIONS_ARB:
  693.             *params = ctx->Const.QueryCounterBits.VsInvocations;
  694.             break;
  695.          case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
  696.             *params = ctx->Const.QueryCounterBits.TessPatches;
  697.             break;
  698.          case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
  699.             *params = ctx->Const.QueryCounterBits.TessInvocations;
  700.             break;
  701.          case GL_GEOMETRY_SHADER_INVOCATIONS:
  702.             *params = ctx->Const.QueryCounterBits.GsInvocations;
  703.             break;
  704.          case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
  705.             *params = ctx->Const.QueryCounterBits.GsPrimitives;
  706.             break;
  707.          case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
  708.             *params = ctx->Const.QueryCounterBits.FsInvocations;
  709.             break;
  710.          case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
  711.             *params = ctx->Const.QueryCounterBits.ComputeInvocations;
  712.             break;
  713.          case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
  714.             *params = ctx->Const.QueryCounterBits.ClInPrimitives;
  715.             break;
  716.          case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
  717.             *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
  718.             break;
  719.          default:
  720.             _mesa_problem(ctx,
  721.                           "Unknown target in glGetQueryIndexediv(target = %s)",
  722.                           _mesa_lookup_enum_by_nr(target));
  723.             *params = 0;
  724.             break;
  725.          }
  726.          break;
  727.       case GL_CURRENT_QUERY_ARB:
  728.          *params = (q && q->Target == target) ? q->Id : 0;
  729.          break;
  730.       default:
  731.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
  732.          return;
  733.    }
  734. }
  735.  
  736. void GLAPIENTRY
  737. _mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
  738. {
  739.    _mesa_GetQueryIndexediv(target, 0, pname, params);
  740. }
  741.  
  742. void GLAPIENTRY
  743. _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
  744. {
  745.    struct gl_query_object *q = NULL;
  746.    GET_CURRENT_CONTEXT(ctx);
  747.  
  748.    if (MESA_VERBOSE & VERBOSE_API)
  749.       _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
  750.                   _mesa_lookup_enum_by_nr(pname));
  751.  
  752.    if (id)
  753.       q = _mesa_lookup_query_object(ctx, id);
  754.  
  755.    if (!q || q->Active || !q->EverBound) {
  756.       _mesa_error(ctx, GL_INVALID_OPERATION,
  757.                   "glGetQueryObjectivARB(id=%d is invalid or active)", id);
  758.       return;
  759.    }
  760.  
  761.    switch (pname) {
  762.       case GL_QUERY_RESULT_ARB:
  763.          if (!q->Ready)
  764.             ctx->Driver.WaitQuery(ctx, q);
  765.          /* if result is too large for returned type, clamp to max value */
  766.          if (q->Target == GL_ANY_SAMPLES_PASSED
  767.              || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
  768.             if (q->Result)
  769.                *params = GL_TRUE;
  770.             else
  771.                *params = GL_FALSE;
  772.          } else {
  773.             if (q->Result > 0x7fffffff) {
  774.                *params = 0x7fffffff;
  775.             }
  776.             else {
  777.                *params = (GLint)q->Result;
  778.             }
  779.          }
  780.          break;
  781.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  782.          if (!q->Ready)
  783.             ctx->Driver.CheckQuery( ctx, q );
  784.          *params = q->Ready;
  785.          break;
  786.       case GL_QUERY_TARGET:
  787.          *params = q->Target;
  788.          break;
  789.       default:
  790.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
  791.          return;
  792.    }
  793. }
  794.  
  795.  
  796. void GLAPIENTRY
  797. _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
  798. {
  799.    struct gl_query_object *q = NULL;
  800.    GET_CURRENT_CONTEXT(ctx);
  801.  
  802.    if (MESA_VERBOSE & VERBOSE_API)
  803.       _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
  804.                   _mesa_lookup_enum_by_nr(pname));
  805.  
  806.    if (id)
  807.       q = _mesa_lookup_query_object(ctx, id);
  808.  
  809.    if (!q || q->Active || !q->EverBound) {
  810.       _mesa_error(ctx, GL_INVALID_OPERATION,
  811.                   "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
  812.       return;
  813.    }
  814.  
  815.    switch (pname) {
  816.       case GL_QUERY_RESULT_ARB:
  817.          if (!q->Ready)
  818.             ctx->Driver.WaitQuery(ctx, q);
  819.          /* if result is too large for returned type, clamp to max value */
  820.          if (q->Target == GL_ANY_SAMPLES_PASSED
  821.              || q->Target == GL_ANY_SAMPLES_PASSED_CONSERVATIVE) {
  822.             if (q->Result)
  823.                *params = GL_TRUE;
  824.             else
  825.                *params = GL_FALSE;
  826.          } else {
  827.             if (q->Result > 0xffffffff) {
  828.                *params = 0xffffffff;
  829.             }
  830.             else {
  831.                *params = (GLuint)q->Result;
  832.             }
  833.          }
  834.          break;
  835.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  836.          if (!q->Ready)
  837.             ctx->Driver.CheckQuery( ctx, q );
  838.          *params = q->Ready;
  839.          break;
  840.       case GL_QUERY_TARGET:
  841.          *params = q->Target;
  842.          break;
  843.       default:
  844.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
  845.          return;
  846.    }
  847. }
  848.  
  849.  
  850. /**
  851.  * New with GL_EXT_timer_query
  852.  */
  853. void GLAPIENTRY
  854. _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
  855. {
  856.    struct gl_query_object *q = NULL;
  857.    GET_CURRENT_CONTEXT(ctx);
  858.  
  859.    if (MESA_VERBOSE & VERBOSE_API)
  860.       _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
  861.                   _mesa_lookup_enum_by_nr(pname));
  862.  
  863.    if (id)
  864.       q = _mesa_lookup_query_object(ctx, id);
  865.  
  866.    if (!q || q->Active || !q->EverBound) {
  867.       _mesa_error(ctx, GL_INVALID_OPERATION,
  868.                   "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
  869.       return;
  870.    }
  871.  
  872.    switch (pname) {
  873.       case GL_QUERY_RESULT_ARB:
  874.          if (!q->Ready)
  875.             ctx->Driver.WaitQuery(ctx, q);
  876.          *params = q->Result;
  877.          break;
  878.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  879.          if (!q->Ready)
  880.             ctx->Driver.CheckQuery( ctx, q );
  881.          *params = q->Ready;
  882.          break;
  883.       case GL_QUERY_TARGET:
  884.          *params = q->Target;
  885.          break;
  886.       default:
  887.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
  888.          return;
  889.    }
  890. }
  891.  
  892.  
  893. /**
  894.  * New with GL_EXT_timer_query
  895.  */
  896. void GLAPIENTRY
  897. _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
  898. {
  899.    struct gl_query_object *q = NULL;
  900.    GET_CURRENT_CONTEXT(ctx);
  901.  
  902.    if (MESA_VERBOSE & VERBOSE_API)
  903.       _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
  904.                   _mesa_lookup_enum_by_nr(pname));
  905.  
  906.    if (id)
  907.       q = _mesa_lookup_query_object(ctx, id);
  908.  
  909.    if (!q || q->Active || !q->EverBound) {
  910.       _mesa_error(ctx, GL_INVALID_OPERATION,
  911.                   "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
  912.       return;
  913.    }
  914.  
  915.    switch (pname) {
  916.       case GL_QUERY_RESULT_ARB:
  917.          if (!q->Ready)
  918.             ctx->Driver.WaitQuery(ctx, q);
  919.          *params = q->Result;
  920.          break;
  921.       case GL_QUERY_RESULT_AVAILABLE_ARB:
  922.          if (!q->Ready)
  923.             ctx->Driver.CheckQuery( ctx, q );
  924.          *params = q->Ready;
  925.          break;
  926.       case GL_QUERY_TARGET:
  927.          *params = q->Target;
  928.          break;
  929.       default:
  930.          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
  931.          return;
  932.    }
  933. }
  934.  
  935. /**
  936.  * New with GL_ARB_query_buffer_object
  937.  */
  938. void GLAPIENTRY
  939. _mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
  940.                              GLintptr offset)
  941. {
  942.    GET_CURRENT_CONTEXT(ctx);
  943.    _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjectiv");
  944. }
  945.  
  946.  
  947. void GLAPIENTRY
  948. _mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
  949.                               GLintptr offset)
  950. {
  951.    GET_CURRENT_CONTEXT(ctx);
  952.    _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjectuiv");
  953. }
  954.  
  955.  
  956. void GLAPIENTRY
  957. _mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
  958.                                GLintptr offset)
  959. {
  960.    GET_CURRENT_CONTEXT(ctx);
  961.    _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjecti64v");
  962. }
  963.  
  964.  
  965. void GLAPIENTRY
  966. _mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
  967.                                 GLintptr offset)
  968. {
  969.    GET_CURRENT_CONTEXT(ctx);
  970.    _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryBufferObjectui64v");
  971. }
  972.  
  973.  
  974. /**
  975.  * Allocate/init the context state related to query objects.
  976.  */
  977. void
  978. _mesa_init_queryobj(struct gl_context *ctx)
  979. {
  980.    ctx->Query.QueryObjects = _mesa_NewHashTable();
  981.    ctx->Query.CurrentOcclusionObject = NULL;
  982.  
  983.    ctx->Const.QueryCounterBits.SamplesPassed = 64;
  984.    ctx->Const.QueryCounterBits.TimeElapsed = 64;
  985.    ctx->Const.QueryCounterBits.Timestamp = 64;
  986.    ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
  987.    ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
  988.  
  989.    ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
  990.    ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
  991.    ctx->Const.QueryCounterBits.VsInvocations = 64;
  992.    ctx->Const.QueryCounterBits.TessPatches = 64;
  993.    ctx->Const.QueryCounterBits.TessInvocations = 64;
  994.    ctx->Const.QueryCounterBits.GsInvocations = 64;
  995.    ctx->Const.QueryCounterBits.GsPrimitives = 64;
  996.    ctx->Const.QueryCounterBits.FsInvocations = 64;
  997.    ctx->Const.QueryCounterBits.ComputeInvocations = 64;
  998.    ctx->Const.QueryCounterBits.ClInPrimitives = 64;
  999.    ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
  1000. }
  1001.  
  1002.  
  1003. /**
  1004.  * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
  1005.  */
  1006. static void
  1007. delete_queryobj_cb(GLuint id, void *data, void *userData)
  1008. {
  1009.    struct gl_query_object *q= (struct gl_query_object *) data;
  1010.    struct gl_context *ctx = (struct gl_context *)userData;
  1011.    ctx->Driver.DeleteQuery(ctx, q);
  1012. }
  1013.  
  1014.  
  1015. /**
  1016.  * Free the context state related to query objects.
  1017.  */
  1018. void
  1019. _mesa_free_queryobj_data(struct gl_context *ctx)
  1020. {
  1021.    _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
  1022.    _mesa_DeleteHashTable(ctx->Query.QueryObjects);
  1023. }
  1024.