queryobj.c revision 01e04c3f
17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
4c1f859d4Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
257117f1b4Smrg
2601e04c3fSmrg#include "bufferobj.h"
277117f1b4Smrg#include "glheader.h"
287117f1b4Smrg#include "context.h"
293464ebd5Sriastradh#include "enums.h"
307117f1b4Smrg#include "hash.h"
317117f1b4Smrg#include "imports.h"
327117f1b4Smrg#include "queryobj.h"
337117f1b4Smrg#include "mtypes.h"
344a49301eSmrg
354a49301eSmrg
367117f1b4Smrg/**
377117f1b4Smrg * Allocate a new query object.  This is a fallback routine called via
387117f1b4Smrg * ctx->Driver.NewQueryObject().
397117f1b4Smrg * \param ctx - rendering context
407117f1b4Smrg * \param id - the new object's ID
417117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory.
427117f1b4Smrg */
434a49301eSmrgstatic struct gl_query_object *
443464ebd5Sriastradh_mesa_new_query_object(struct gl_context *ctx, GLuint id)
457117f1b4Smrg{
46af69d88dSmrg   struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
477117f1b4Smrg   (void) ctx;
487117f1b4Smrg   if (q) {
497117f1b4Smrg      q->Id = id;
507117f1b4Smrg      q->Result = 0;
517117f1b4Smrg      q->Active = GL_FALSE;
52af69d88dSmrg
53af69d88dSmrg      /* This is to satisfy the language of the specification: "In the initial
54af69d88dSmrg       * state of a query object, the result is available" (OpenGL 3.1 §
55af69d88dSmrg       * 2.13).
56af69d88dSmrg       */
57af69d88dSmrg      q->Ready = GL_TRUE;
58af69d88dSmrg
59af69d88dSmrg      /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as
60af69d88dSmrg       * used, but no object is associated with them until the first time they
61af69d88dSmrg       * are used by BeginQuery." Since our implementation actually does
62af69d88dSmrg       * allocate an object at this point, use a flag to indicate that this
63af69d88dSmrg       * object has not yet been bound so should not be considered a query.
64af69d88dSmrg       */
65af69d88dSmrg      q->EverBound = GL_FALSE;
667117f1b4Smrg   }
677117f1b4Smrg   return q;
687117f1b4Smrg}
697117f1b4Smrg
707117f1b4Smrg
717117f1b4Smrg/**
72c1f859d4Smrg * Begin a query.  Software driver fallback.
73c1f859d4Smrg * Called via ctx->Driver.BeginQuery().
74c1f859d4Smrg */
754a49301eSmrgstatic void
763464ebd5Sriastradh_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
77c1f859d4Smrg{
78af69d88dSmrg   ctx->NewState |= _NEW_DEPTH; /* for swrast */
79c1f859d4Smrg}
80c1f859d4Smrg
81c1f859d4Smrg
82c1f859d4Smrg/**
83c1f859d4Smrg * End a query.  Software driver fallback.
84c1f859d4Smrg * Called via ctx->Driver.EndQuery().
85c1f859d4Smrg */
864a49301eSmrgstatic void
873464ebd5Sriastradh_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
88c1f859d4Smrg{
89af69d88dSmrg   ctx->NewState |= _NEW_DEPTH; /* for swrast */
90c1f859d4Smrg   q->Ready = GL_TRUE;
91c1f859d4Smrg}
92c1f859d4Smrg
93c1f859d4Smrg
94c1f859d4Smrg/**
95c1f859d4Smrg * Wait for query to complete.  Software driver fallback.
96c1f859d4Smrg * Called via ctx->Driver.WaitQuery().
97c1f859d4Smrg */
984a49301eSmrgstatic void
993464ebd5Sriastradh_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
100c1f859d4Smrg{
101c1f859d4Smrg   /* For software drivers, _mesa_end_query() should have completed the query.
1024a49301eSmrg    * For real hardware, implement a proper WaitQuery() driver function,
1034a49301eSmrg    * which may require issuing a flush.
104c1f859d4Smrg    */
105c1f859d4Smrg   assert(q->Ready);
106c1f859d4Smrg}
107c1f859d4Smrg
108c1f859d4Smrg
1094a49301eSmrg/**
1104a49301eSmrg * Check if a query results are ready.  Software driver fallback.
1114a49301eSmrg * Called via ctx->Driver.CheckQuery().
1124a49301eSmrg */
1134a49301eSmrgstatic void
1143464ebd5Sriastradh_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
1154a49301eSmrg{
1164a49301eSmrg   /* No-op for sw rendering.
1174a49301eSmrg    * HW drivers may need to flush at this time.
1184a49301eSmrg    */
1194a49301eSmrg}
1204a49301eSmrg
1214a49301eSmrg
122c1f859d4Smrg/**
123c1f859d4Smrg * Delete a query object.  Called via ctx->Driver.DeleteQuery().
1247117f1b4Smrg * Not removed from hash table here.
1257117f1b4Smrg */
1264a49301eSmrgstatic void
1273464ebd5Sriastradh_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
1287117f1b4Smrg{
129af69d88dSmrg   free(q->Label);
130cdc920a0Smrg   free(q);
1317117f1b4Smrg}
1327117f1b4Smrg
1337117f1b4Smrg
1344a49301eSmrgvoid
1354a49301eSmrg_mesa_init_query_object_functions(struct dd_function_table *driver)
1364a49301eSmrg{
1374a49301eSmrg   driver->NewQueryObject = _mesa_new_query_object;
1384a49301eSmrg   driver->DeleteQuery = _mesa_delete_query;
1394a49301eSmrg   driver->BeginQuery = _mesa_begin_query;
1404a49301eSmrg   driver->EndQuery = _mesa_end_query;
1414a49301eSmrg   driver->WaitQuery = _mesa_wait_query;
1424a49301eSmrg   driver->CheckQuery = _mesa_check_query;
1434a49301eSmrg}
1444a49301eSmrg
14501e04c3fSmrgstatic struct gl_query_object **
14601e04c3fSmrgget_pipe_stats_binding_point(struct gl_context *ctx,
14701e04c3fSmrg                             GLenum target)
14801e04c3fSmrg{
14901e04c3fSmrg   const int which = target - GL_VERTICES_SUBMITTED_ARB;
15001e04c3fSmrg   assert(which < MAX_PIPELINE_STATISTICS);
15101e04c3fSmrg
15201e04c3fSmrg   if (!_mesa_is_desktop_gl(ctx) ||
15301e04c3fSmrg       !ctx->Extensions.ARB_pipeline_statistics_query)
15401e04c3fSmrg      return NULL;
15501e04c3fSmrg
15601e04c3fSmrg   return &ctx->Query.pipeline_stats[which];
15701e04c3fSmrg}
1584a49301eSmrg
1593464ebd5Sriastradh/**
160af69d88dSmrg * Return pointer to the query object binding point for the given target and
161af69d88dSmrg * index.
1623464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point
1633464ebd5Sriastradh */
1643464ebd5Sriastradhstatic struct gl_query_object **
165af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
1663464ebd5Sriastradh{
16701e04c3fSmrg
16801e04c3fSmrg   /* From GL_EXT_occlusion_query_boolean spec:
16901e04c3fSmrg    *
17001e04c3fSmrg    *    "Accepted by the <target> parameter of BeginQueryEXT, EndQueryEXT,
17101e04c3fSmrg    *    and GetQueryivEXT:
17201e04c3fSmrg    *
17301e04c3fSmrg    *   ANY_SAMPLES_PASSED_EXT                         0x8C2F
17401e04c3fSmrg    *   ANY_SAMPLES_PASSED_CONSERVATIVE_EXT            0x8D6A"
17501e04c3fSmrg    */
17601e04c3fSmrg   if ((_mesa_is_gles(ctx) && ctx->Version == 20) &&
17701e04c3fSmrg       (target != GL_ANY_SAMPLES_PASSED &&
17801e04c3fSmrg        target != GL_ANY_SAMPLES_PASSED_CONSERVATIVE))
17901e04c3fSmrg      return NULL;
18001e04c3fSmrg
1813464ebd5Sriastradh   switch (target) {
1823464ebd5Sriastradh   case GL_SAMPLES_PASSED_ARB:
1833464ebd5Sriastradh      if (ctx->Extensions.ARB_occlusion_query)
1843464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1853464ebd5Sriastradh      else
1863464ebd5Sriastradh         return NULL;
1873464ebd5Sriastradh   case GL_ANY_SAMPLES_PASSED:
1883464ebd5Sriastradh      if (ctx->Extensions.ARB_occlusion_query2)
1893464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1903464ebd5Sriastradh      else
1913464ebd5Sriastradh         return NULL;
192af69d88dSmrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
193af69d88dSmrg      if (ctx->Extensions.ARB_ES3_compatibility
194af69d88dSmrg          || (ctx->API == API_OPENGLES2 && ctx->Version >= 30))
195af69d88dSmrg         return &ctx->Query.CurrentOcclusionObject;
196af69d88dSmrg      else
197af69d88dSmrg         return NULL;
1983464ebd5Sriastradh   case GL_TIME_ELAPSED_EXT:
1993464ebd5Sriastradh      if (ctx->Extensions.EXT_timer_query)
2003464ebd5Sriastradh         return &ctx->Query.CurrentTimerObject;
2013464ebd5Sriastradh      else
2023464ebd5Sriastradh         return NULL;
2033464ebd5Sriastradh   case GL_PRIMITIVES_GENERATED:
2043464ebd5Sriastradh      if (ctx->Extensions.EXT_transform_feedback)
205af69d88dSmrg         return &ctx->Query.PrimitivesGenerated[index];
2063464ebd5Sriastradh      else
2073464ebd5Sriastradh         return NULL;
2083464ebd5Sriastradh   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
2093464ebd5Sriastradh      if (ctx->Extensions.EXT_transform_feedback)
210af69d88dSmrg         return &ctx->Query.PrimitivesWritten[index];
2113464ebd5Sriastradh      else
2123464ebd5Sriastradh         return NULL;
21301e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
21401e04c3fSmrg      if (ctx->Extensions.ARB_transform_feedback_overflow_query)
21501e04c3fSmrg         return &ctx->Query.TransformFeedbackOverflow[index];
21601e04c3fSmrg      else
21701e04c3fSmrg         return NULL;
21801e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB:
21901e04c3fSmrg      if (ctx->Extensions.ARB_transform_feedback_overflow_query)
22001e04c3fSmrg         return &ctx->Query.TransformFeedbackOverflowAny;
22101e04c3fSmrg      else
22201e04c3fSmrg         return NULL;
22301e04c3fSmrg
22401e04c3fSmrg   case GL_VERTICES_SUBMITTED_ARB:
22501e04c3fSmrg   case GL_PRIMITIVES_SUBMITTED_ARB:
22601e04c3fSmrg   case GL_VERTEX_SHADER_INVOCATIONS_ARB:
22701e04c3fSmrg   case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
22801e04c3fSmrg   case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
22901e04c3fSmrg   case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
23001e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
23101e04c3fSmrg
23201e04c3fSmrg   case GL_GEOMETRY_SHADER_INVOCATIONS:
23301e04c3fSmrg      /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
23401e04c3fSmrg      target = GL_VERTICES_SUBMITTED_ARB + MAX_PIPELINE_STATISTICS - 1;
23501e04c3fSmrg      /* fallthrough */
23601e04c3fSmrg   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
23701e04c3fSmrg      if (_mesa_has_geometry_shaders(ctx))
23801e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
23901e04c3fSmrg      else
24001e04c3fSmrg         return NULL;
24101e04c3fSmrg
24201e04c3fSmrg   case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
24301e04c3fSmrg   case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
24401e04c3fSmrg      if (_mesa_has_tessellation(ctx))
24501e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
24601e04c3fSmrg      else
24701e04c3fSmrg         return NULL;
24801e04c3fSmrg
24901e04c3fSmrg   case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
25001e04c3fSmrg      if (_mesa_has_compute_shaders(ctx))
25101e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
25201e04c3fSmrg      else
25301e04c3fSmrg         return NULL;
25401e04c3fSmrg
2553464ebd5Sriastradh   default:
2563464ebd5Sriastradh      return NULL;
2573464ebd5Sriastradh   }
2583464ebd5Sriastradh}
2593464ebd5Sriastradh
26001e04c3fSmrg/**
26101e04c3fSmrg * Create $n query objects and store them in *ids. Make them of type $target
26201e04c3fSmrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
26301e04c3fSmrg */
26401e04c3fSmrgstatic void
26501e04c3fSmrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
26601e04c3fSmrg               bool dsa)
2677117f1b4Smrg{
26801e04c3fSmrg   const char *func = dsa ? "glGenQueries" : "glCreateQueries";
2697117f1b4Smrg   GLuint first;
2707117f1b4Smrg
2713464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
27201e04c3fSmrg      _mesa_debug(ctx, "%s(%d)\n", func, n);
2733464ebd5Sriastradh
2747117f1b4Smrg   if (n < 0) {
27501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
2767117f1b4Smrg      return;
2777117f1b4Smrg   }
2787117f1b4Smrg
2797117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
2807117f1b4Smrg   if (first) {
2817117f1b4Smrg      GLsizei i;
2827117f1b4Smrg      for (i = 0; i < n; i++) {
2837117f1b4Smrg         struct gl_query_object *q
2847117f1b4Smrg            = ctx->Driver.NewQueryObject(ctx, first + i);
2857117f1b4Smrg         if (!q) {
28601e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
2877117f1b4Smrg            return;
28801e04c3fSmrg         } else if (dsa) {
28901e04c3fSmrg            /* Do the equivalent of binding the buffer with a target */
29001e04c3fSmrg            q->Target = target;
29101e04c3fSmrg            q->EverBound = GL_TRUE;
2927117f1b4Smrg         }
2937117f1b4Smrg         ids[i] = first + i;
29401e04c3fSmrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, first + i, q);
2957117f1b4Smrg      }
2967117f1b4Smrg   }
2977117f1b4Smrg}
2987117f1b4Smrg
29901e04c3fSmrgvoid GLAPIENTRY
30001e04c3fSmrg_mesa_GenQueries(GLsizei n, GLuint *ids)
30101e04c3fSmrg{
30201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
30301e04c3fSmrg   create_queries(ctx, 0, n, ids, false);
30401e04c3fSmrg}
30501e04c3fSmrg
30601e04c3fSmrgvoid GLAPIENTRY
30701e04c3fSmrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
30801e04c3fSmrg{
30901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
31001e04c3fSmrg
31101e04c3fSmrg   switch (target) {
31201e04c3fSmrg   case GL_SAMPLES_PASSED:
31301e04c3fSmrg   case GL_ANY_SAMPLES_PASSED:
31401e04c3fSmrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
31501e04c3fSmrg   case GL_TIME_ELAPSED:
31601e04c3fSmrg   case GL_TIMESTAMP:
31701e04c3fSmrg   case GL_PRIMITIVES_GENERATED:
31801e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
31901e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
32001e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB:
32101e04c3fSmrg      break;
32201e04c3fSmrg   default:
32301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
32401e04c3fSmrg                  _mesa_enum_to_string(target));
32501e04c3fSmrg      return;
32601e04c3fSmrg   }
32701e04c3fSmrg
32801e04c3fSmrg   create_queries(ctx, target, n, ids, true);
32901e04c3fSmrg}
33001e04c3fSmrg
3317117f1b4Smrg
332af69d88dSmrgvoid GLAPIENTRY
333af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids)
3347117f1b4Smrg{
3357117f1b4Smrg   GLint i;
3367117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3373464ebd5Sriastradh   FLUSH_VERTICES(ctx, 0);
3383464ebd5Sriastradh
3393464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
340af69d88dSmrg      _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
3417117f1b4Smrg
3427117f1b4Smrg   if (n < 0) {
3437117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
3447117f1b4Smrg      return;
3457117f1b4Smrg   }
3467117f1b4Smrg
3477117f1b4Smrg   for (i = 0; i < n; i++) {
3487117f1b4Smrg      if (ids[i] > 0) {
349cdc920a0Smrg         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
3507117f1b4Smrg         if (q) {
351af69d88dSmrg            if (q->Active) {
352af69d88dSmrg               struct gl_query_object **bindpt;
353af69d88dSmrg               bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
354af69d88dSmrg               assert(bindpt); /* Should be non-null for active q. */
355af69d88dSmrg               if (bindpt) {
356af69d88dSmrg                  *bindpt = NULL;
357af69d88dSmrg               }
358af69d88dSmrg               q->Active = GL_FALSE;
359af69d88dSmrg               ctx->Driver.EndQuery(ctx, q);
360af69d88dSmrg            }
36101e04c3fSmrg            _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]);
362c1f859d4Smrg            ctx->Driver.DeleteQuery(ctx, q);
3637117f1b4Smrg         }
3647117f1b4Smrg      }
3657117f1b4Smrg   }
3667117f1b4Smrg}
3677117f1b4Smrg
3687117f1b4Smrg
369af69d88dSmrgGLboolean GLAPIENTRY
370af69d88dSmrg_mesa_IsQuery(GLuint id)
3717117f1b4Smrg{
372af69d88dSmrg   struct gl_query_object *q;
373af69d88dSmrg
3747117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3757117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
3767117f1b4Smrg
3773464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
3783464ebd5Sriastradh      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
3793464ebd5Sriastradh
380af69d88dSmrg   if (id == 0)
381af69d88dSmrg      return GL_FALSE;
382af69d88dSmrg
383af69d88dSmrg   q = _mesa_lookup_query_object(ctx, id);
384af69d88dSmrg   if (q == NULL)
3857117f1b4Smrg      return GL_FALSE;
386af69d88dSmrg
387af69d88dSmrg   return q->EverBound;
3887117f1b4Smrg}
3897117f1b4Smrg
390af69d88dSmrgstatic GLboolean
391af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
392af69d88dSmrg{
393af69d88dSmrg   switch (target) {
394af69d88dSmrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
395af69d88dSmrg   case GL_PRIMITIVES_GENERATED:
39601e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
397af69d88dSmrg      if (index >= ctx->Const.MaxVertexStreams) {
398af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
399af69d88dSmrg                     "glBeginQueryIndexed(index>=MaxVertexStreams)");
400af69d88dSmrg         return GL_FALSE;
401af69d88dSmrg      }
402af69d88dSmrg      break;
403af69d88dSmrg   default:
404af69d88dSmrg      if (index > 0) {
405af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
406af69d88dSmrg         return GL_FALSE;
407af69d88dSmrg      }
408af69d88dSmrg   }
409af69d88dSmrg   return GL_TRUE;
410af69d88dSmrg}
4117117f1b4Smrg
412af69d88dSmrgvoid GLAPIENTRY
413af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
4147117f1b4Smrg{
4153464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
4167117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4177117f1b4Smrg
4183464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
419af69d88dSmrg      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
42001e04c3fSmrg                  _mesa_enum_to_string(target), index, id);
4213464ebd5Sriastradh
422af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
423af69d88dSmrg      return;
424af69d88dSmrg
425af69d88dSmrg   FLUSH_VERTICES(ctx, 0);
4267117f1b4Smrg
427af69d88dSmrg   bindpt = get_query_binding_point(ctx, target, index);
4283464ebd5Sriastradh   if (!bindpt) {
429af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
430af69d88dSmrg      return;
431af69d88dSmrg   }
432af69d88dSmrg
433af69d88dSmrg   /* From the GL_ARB_occlusion_query spec:
434af69d88dSmrg    *
435af69d88dSmrg    *     "If BeginQueryARB is called while another query is already in
436af69d88dSmrg    *      progress with the same target, an INVALID_OPERATION error is
437af69d88dSmrg    *      generated."
438af69d88dSmrg    */
439af69d88dSmrg   if (*bindpt) {
440af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
441af69d88dSmrg                  "glBeginQuery{Indexed}(target=%s is active)",
44201e04c3fSmrg                  _mesa_enum_to_string(target));
4433464ebd5Sriastradh      return;
4447117f1b4Smrg   }
4457117f1b4Smrg
4467117f1b4Smrg   if (id == 0) {
447af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
4487117f1b4Smrg      return;
4497117f1b4Smrg   }
4507117f1b4Smrg
451cdc920a0Smrg   q = _mesa_lookup_query_object(ctx, id);
4527117f1b4Smrg   if (!q) {
453af69d88dSmrg      if (ctx->API != API_OPENGL_COMPAT) {
454af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
455af69d88dSmrg                     "glBeginQuery{Indexed}(non-gen name)");
4567117f1b4Smrg         return;
457af69d88dSmrg      } else {
458af69d88dSmrg         /* create new object */
459af69d88dSmrg         q = ctx->Driver.NewQueryObject(ctx, id);
460af69d88dSmrg         if (!q) {
461af69d88dSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
462af69d88dSmrg            return;
463af69d88dSmrg         }
46401e04c3fSmrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q);
4657117f1b4Smrg      }
4667117f1b4Smrg   }
4677117f1b4Smrg   else {
4687117f1b4Smrg      /* pre-existing object */
4697117f1b4Smrg      if (q->Active) {
4707117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
471af69d88dSmrg                     "glBeginQuery{Indexed}(query already active)");
4727117f1b4Smrg         return;
4737117f1b4Smrg      }
47401e04c3fSmrg
47501e04c3fSmrg      /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
47601e04c3fSmrg       * spec states:
47701e04c3fSmrg       *
47801e04c3fSmrg       *     "BeginQuery generates an INVALID_OPERATION error if any of the
47901e04c3fSmrg       *      following conditions hold: [...] id is the name of an
48001e04c3fSmrg       *      existing query object whose type does not match target; [...]
48101e04c3fSmrg       *
48201e04c3fSmrg       * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
48301e04c3fSmrg       * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
48401e04c3fSmrg       */
48501e04c3fSmrg      if (q->EverBound && q->Target != target) {
48601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
48701e04c3fSmrg                     "glBeginQuery{Indexed}(target mismatch)");
48801e04c3fSmrg         return;
48901e04c3fSmrg      }
4907117f1b4Smrg   }
4917117f1b4Smrg
49201e04c3fSmrg   /* This possibly changes the target of a buffer allocated by
49301e04c3fSmrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
49401e04c3fSmrg    * the following:
49501e04c3fSmrg    *
49601e04c3fSmrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
49701e04c3fSmrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
49801e04c3fSmrg    * isn't a selector, so we decided not to change it."
49901e04c3fSmrg    *
50001e04c3fSmrg    * Updating the target of the query object should be acceptable, so let's
50101e04c3fSmrg    * do that.
50201e04c3fSmrg    */
50301e04c3fSmrg
504c1f859d4Smrg   q->Target = target;
5057117f1b4Smrg   q->Active = GL_TRUE;
5067117f1b4Smrg   q->Result = 0;
5077117f1b4Smrg   q->Ready = GL_FALSE;
508af69d88dSmrg   q->EverBound = GL_TRUE;
509af69d88dSmrg   q->Stream = index;
5107117f1b4Smrg
5113464ebd5Sriastradh   /* XXX should probably refcount query objects */
5123464ebd5Sriastradh   *bindpt = q;
5137117f1b4Smrg
514c1f859d4Smrg   ctx->Driver.BeginQuery(ctx, q);
5157117f1b4Smrg}
5167117f1b4Smrg
5177117f1b4Smrg
518af69d88dSmrgvoid GLAPIENTRY
519af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index)
5207117f1b4Smrg{
5213464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
5227117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5237117f1b4Smrg
5243464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
525af69d88dSmrg      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
52601e04c3fSmrg                  _mesa_enum_to_string(target), index);
5273464ebd5Sriastradh
528af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
529af69d88dSmrg      return;
5307117f1b4Smrg
531af69d88dSmrg   FLUSH_VERTICES(ctx, 0);
532af69d88dSmrg
533af69d88dSmrg   bindpt = get_query_binding_point(ctx, target, index);
5343464ebd5Sriastradh   if (!bindpt) {
535af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
5363464ebd5Sriastradh      return;
5377117f1b4Smrg   }
5387117f1b4Smrg
5393464ebd5Sriastradh   /* XXX should probably refcount query objects */
5403464ebd5Sriastradh   q = *bindpt;
541af69d88dSmrg
542af69d88dSmrg   /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
543af69d88dSmrg   if (q && q->Target != target) {
544af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
545af69d88dSmrg                  "glEndQuery(target=%s with active query of target %s)",
54601e04c3fSmrg                  _mesa_enum_to_string(target),
54701e04c3fSmrg                  _mesa_enum_to_string(q->Target));
548af69d88dSmrg      return;
549af69d88dSmrg   }
550af69d88dSmrg
5513464ebd5Sriastradh   *bindpt = NULL;
5523464ebd5Sriastradh
5537117f1b4Smrg   if (!q || !q->Active) {
5547117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
555af69d88dSmrg                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
5567117f1b4Smrg      return;
5577117f1b4Smrg   }
5587117f1b4Smrg
5597117f1b4Smrg   q->Active = GL_FALSE;
560c1f859d4Smrg   ctx->Driver.EndQuery(ctx, q);
5617117f1b4Smrg}
5627117f1b4Smrg
563af69d88dSmrgvoid GLAPIENTRY
564af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id)
565af69d88dSmrg{
566af69d88dSmrg   _mesa_BeginQueryIndexed(target, 0, id);
567af69d88dSmrg}
5687117f1b4Smrg
569af69d88dSmrgvoid GLAPIENTRY
570af69d88dSmrg_mesa_EndQuery(GLenum target)
5717117f1b4Smrg{
572af69d88dSmrg   _mesa_EndQueryIndexed(target, 0);
573af69d88dSmrg}
574af69d88dSmrg
575af69d88dSmrgvoid GLAPIENTRY
576af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target)
577af69d88dSmrg{
578af69d88dSmrg   struct gl_query_object *q;
5797117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5807117f1b4Smrg
5813464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
582af69d88dSmrg      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
58301e04c3fSmrg                  _mesa_enum_to_string(target));
584af69d88dSmrg
585af69d88dSmrg   /* error checking */
586af69d88dSmrg   if (target != GL_TIMESTAMP) {
587af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
588af69d88dSmrg      return;
589af69d88dSmrg   }
590af69d88dSmrg
591af69d88dSmrg   if (id == 0) {
592af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
593af69d88dSmrg      return;
594af69d88dSmrg   }
595af69d88dSmrg
596af69d88dSmrg   q = _mesa_lookup_query_object(ctx, id);
597af69d88dSmrg   if (!q) {
598af69d88dSmrg      /* XXX the Core profile should throw INVALID_OPERATION here */
599af69d88dSmrg
600af69d88dSmrg      /* create new object */
601af69d88dSmrg      q = ctx->Driver.NewQueryObject(ctx, id);
602af69d88dSmrg      if (!q) {
603af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
604af69d88dSmrg         return;
605af69d88dSmrg      }
60601e04c3fSmrg      _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q);
607af69d88dSmrg   }
608af69d88dSmrg   else {
609af69d88dSmrg      if (q->Target && q->Target != GL_TIMESTAMP) {
610af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
611af69d88dSmrg                     "glQueryCounter(id has an invalid target)");
612af69d88dSmrg         return;
613af69d88dSmrg      }
614af69d88dSmrg   }
615af69d88dSmrg
616af69d88dSmrg   if (q->Active) {
617af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
618af69d88dSmrg      return;
619af69d88dSmrg   }
620af69d88dSmrg
62101e04c3fSmrg   /* This possibly changes the target of a buffer allocated by
62201e04c3fSmrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
62301e04c3fSmrg    * the following:
62401e04c3fSmrg    *
62501e04c3fSmrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
62601e04c3fSmrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
62701e04c3fSmrg    * isn't a selector, so we decided not to change it."
62801e04c3fSmrg    *
62901e04c3fSmrg    * Updating the target of the query object should be acceptable, so let's
63001e04c3fSmrg    * do that.
63101e04c3fSmrg    */
63201e04c3fSmrg
633af69d88dSmrg   q->Target = target;
634af69d88dSmrg   q->Result = 0;
635af69d88dSmrg   q->Ready = GL_FALSE;
636af69d88dSmrg   q->EverBound = GL_TRUE;
637af69d88dSmrg
638af69d88dSmrg   if (ctx->Driver.QueryCounter) {
639af69d88dSmrg      ctx->Driver.QueryCounter(ctx, q);
640af69d88dSmrg   } else {
641af69d88dSmrg      /* QueryCounter is implemented using EndQuery without BeginQuery
642af69d88dSmrg       * in drivers. This is actually Direct3D and Gallium convention.
643af69d88dSmrg       */
644af69d88dSmrg      ctx->Driver.EndQuery(ctx, q);
645af69d88dSmrg   }
646af69d88dSmrg}
647af69d88dSmrg
648af69d88dSmrg
649af69d88dSmrgvoid GLAPIENTRY
650af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
651af69d88dSmrg                        GLint *params)
652af69d88dSmrg{
653af69d88dSmrg   struct gl_query_object *q = NULL, **bindpt = NULL;
654af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
655af69d88dSmrg
656af69d88dSmrg   if (MESA_VERBOSE & VERBOSE_API)
657af69d88dSmrg      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
65801e04c3fSmrg                  _mesa_enum_to_string(target),
659af69d88dSmrg                  index,
66001e04c3fSmrg                  _mesa_enum_to_string(pname));
6613464ebd5Sriastradh
662af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
6633464ebd5Sriastradh      return;
664af69d88dSmrg
66501e04c3fSmrg   /* From the GL_EXT_occlusion_query_boolean spec:
66601e04c3fSmrg    *
66701e04c3fSmrg    * "The error INVALID_ENUM is generated if GetQueryivEXT is called where
66801e04c3fSmrg    * <pname> is not CURRENT_QUERY_EXT."
66901e04c3fSmrg    *
67001e04c3fSmrg    * Same rule is present also in ES 3.2 spec.
67101e04c3fSmrg    */
67201e04c3fSmrg   if (_mesa_is_gles(ctx) && pname != GL_CURRENT_QUERY) {
67301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)",
67401e04c3fSmrg                  _mesa_enum_to_string(pname));
67501e04c3fSmrg      return;
67601e04c3fSmrg   }
67701e04c3fSmrg
678af69d88dSmrg   if (target == GL_TIMESTAMP) {
679af69d88dSmrg      if (!ctx->Extensions.ARB_timer_query) {
680af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
681af69d88dSmrg         return;
682af69d88dSmrg      }
6837117f1b4Smrg   }
684af69d88dSmrg   else {
685af69d88dSmrg      bindpt = get_query_binding_point(ctx, target, index);
686af69d88dSmrg      if (!bindpt) {
687af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
688af69d88dSmrg         return;
689af69d88dSmrg      }
6907117f1b4Smrg
691af69d88dSmrg      q = *bindpt;
692af69d88dSmrg   }
6933464ebd5Sriastradh
6947117f1b4Smrg   switch (pname) {
6957117f1b4Smrg      case GL_QUERY_COUNTER_BITS_ARB:
696af69d88dSmrg         switch (target) {
697af69d88dSmrg         case GL_SAMPLES_PASSED:
698af69d88dSmrg            *params = ctx->Const.QueryCounterBits.SamplesPassed;
699af69d88dSmrg            break;
700af69d88dSmrg         case GL_ANY_SAMPLES_PASSED:
70101e04c3fSmrg         case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
702af69d88dSmrg            /* The minimum value of this is 1 if it's nonzero, and the value
703af69d88dSmrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
704af69d88dSmrg             * bits.
705af69d88dSmrg             */
706af69d88dSmrg            *params = 1;
707af69d88dSmrg            break;
708af69d88dSmrg         case GL_TIME_ELAPSED:
709af69d88dSmrg            *params = ctx->Const.QueryCounterBits.TimeElapsed;
710af69d88dSmrg            break;
711af69d88dSmrg         case GL_TIMESTAMP:
712af69d88dSmrg            *params = ctx->Const.QueryCounterBits.Timestamp;
713af69d88dSmrg            break;
714af69d88dSmrg         case GL_PRIMITIVES_GENERATED:
715af69d88dSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
716af69d88dSmrg            break;
717af69d88dSmrg         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
718af69d88dSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
719af69d88dSmrg            break;
72001e04c3fSmrg         case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
72101e04c3fSmrg         case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB:
72201e04c3fSmrg            /* The minimum value of this is 1 if it's nonzero, and the value
72301e04c3fSmrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
72401e04c3fSmrg             * bits.
72501e04c3fSmrg             */
72601e04c3fSmrg            *params = 1;
72701e04c3fSmrg            break;
72801e04c3fSmrg         case GL_VERTICES_SUBMITTED_ARB:
72901e04c3fSmrg            *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
73001e04c3fSmrg            break;
73101e04c3fSmrg         case GL_PRIMITIVES_SUBMITTED_ARB:
73201e04c3fSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
73301e04c3fSmrg            break;
73401e04c3fSmrg         case GL_VERTEX_SHADER_INVOCATIONS_ARB:
73501e04c3fSmrg            *params = ctx->Const.QueryCounterBits.VsInvocations;
73601e04c3fSmrg            break;
73701e04c3fSmrg         case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
73801e04c3fSmrg            *params = ctx->Const.QueryCounterBits.TessPatches;
73901e04c3fSmrg            break;
74001e04c3fSmrg         case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
74101e04c3fSmrg            *params = ctx->Const.QueryCounterBits.TessInvocations;
74201e04c3fSmrg            break;
74301e04c3fSmrg         case GL_GEOMETRY_SHADER_INVOCATIONS:
74401e04c3fSmrg            *params = ctx->Const.QueryCounterBits.GsInvocations;
74501e04c3fSmrg            break;
74601e04c3fSmrg         case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
74701e04c3fSmrg            *params = ctx->Const.QueryCounterBits.GsPrimitives;
74801e04c3fSmrg            break;
74901e04c3fSmrg         case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
75001e04c3fSmrg            *params = ctx->Const.QueryCounterBits.FsInvocations;
75101e04c3fSmrg            break;
75201e04c3fSmrg         case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
75301e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ComputeInvocations;
75401e04c3fSmrg            break;
75501e04c3fSmrg         case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
75601e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ClInPrimitives;
75701e04c3fSmrg            break;
75801e04c3fSmrg         case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
75901e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
76001e04c3fSmrg            break;
761af69d88dSmrg         default:
762af69d88dSmrg            _mesa_problem(ctx,
763af69d88dSmrg                          "Unknown target in glGetQueryIndexediv(target = %s)",
76401e04c3fSmrg                          _mesa_enum_to_string(target));
765af69d88dSmrg            *params = 0;
766af69d88dSmrg            break;
767af69d88dSmrg         }
7687117f1b4Smrg         break;
7697117f1b4Smrg      case GL_CURRENT_QUERY_ARB:
770af69d88dSmrg         *params = (q && q->Target == target) ? q->Id : 0;
7717117f1b4Smrg         break;
7727117f1b4Smrg      default:
773af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
7747117f1b4Smrg         return;
7757117f1b4Smrg   }
7767117f1b4Smrg}
7777117f1b4Smrg
778af69d88dSmrgvoid GLAPIENTRY
779af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
780af69d88dSmrg{
781af69d88dSmrg   _mesa_GetQueryIndexediv(target, 0, pname, params);
782af69d88dSmrg}
7837117f1b4Smrg
78401e04c3fSmrgstatic void
78501e04c3fSmrgget_query_object(struct gl_context *ctx, const char *func,
78601e04c3fSmrg                 GLuint id, GLenum pname, GLenum ptype,
78701e04c3fSmrg                 struct gl_buffer_object *buf, intptr_t offset)
7887117f1b4Smrg{
7897117f1b4Smrg   struct gl_query_object *q = NULL;
79001e04c3fSmrg   uint64_t value;
7917117f1b4Smrg
7923464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
79301e04c3fSmrg      _mesa_debug(ctx, "%s(%u, %s)\n", func, id,
79401e04c3fSmrg                  _mesa_enum_to_string(pname));
7953464ebd5Sriastradh
7967117f1b4Smrg   if (id)
797cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
7987117f1b4Smrg
79901e04c3fSmrg   if (!q || q->Active || !q->EverBound) {
8007117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
80101e04c3fSmrg                  "%s(id=%d is invalid or active)", func, id);
80201e04c3fSmrg      return;
80301e04c3fSmrg   }
80401e04c3fSmrg
80501e04c3fSmrg   /* From GL_EXT_occlusion_query_boolean spec:
80601e04c3fSmrg    *
80701e04c3fSmrg    *    "Accepted by the <pname> parameter of GetQueryObjectivEXT and
80801e04c3fSmrg    *    GetQueryObjectuivEXT:
80901e04c3fSmrg    *
81001e04c3fSmrg    *    QUERY_RESULT_EXT                               0x8866
81101e04c3fSmrg    *    QUERY_RESULT_AVAILABLE_EXT                     0x8867"
81201e04c3fSmrg    *
81301e04c3fSmrg    * Same rule is present also in ES 3.2 spec.
81401e04c3fSmrg    */
81501e04c3fSmrg   if (_mesa_is_gles(ctx) &&
81601e04c3fSmrg       (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) {
81701e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func,
81801e04c3fSmrg                  _mesa_enum_to_string(pname));
8197117f1b4Smrg      return;
8207117f1b4Smrg   }
8217117f1b4Smrg
82201e04c3fSmrg   if (buf && buf != ctx->Shared->NullBufferObj) {
82301e04c3fSmrg      bool is_64bit = ptype == GL_INT64_ARB ||
82401e04c3fSmrg         ptype == GL_UNSIGNED_INT64_ARB;
82501e04c3fSmrg      if (!ctx->Extensions.ARB_query_buffer_object) {
82601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func);
82701e04c3fSmrg         return;
82801e04c3fSmrg      }
82901e04c3fSmrg      if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) {
83001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func);
83101e04c3fSmrg         return;
83201e04c3fSmrg      }
83301e04c3fSmrg
83401e04c3fSmrg      if (offset < 0) {
83501e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func);
83601e04c3fSmrg         return;
83701e04c3fSmrg      }
83801e04c3fSmrg
83901e04c3fSmrg      switch (pname) {
84001e04c3fSmrg      case GL_QUERY_RESULT:
84101e04c3fSmrg      case GL_QUERY_RESULT_NO_WAIT:
84201e04c3fSmrg      case GL_QUERY_RESULT_AVAILABLE:
84301e04c3fSmrg      case GL_QUERY_TARGET:
84401e04c3fSmrg         ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype);
84501e04c3fSmrg         return;
84601e04c3fSmrg      }
84701e04c3fSmrg
84801e04c3fSmrg      /* fall through to get error below */
84901e04c3fSmrg   }
85001e04c3fSmrg
8517117f1b4Smrg   switch (pname) {
85201e04c3fSmrg   case GL_QUERY_RESULT:
85301e04c3fSmrg      if (!q->Ready)
85401e04c3fSmrg         ctx->Driver.WaitQuery(ctx, q);
85501e04c3fSmrg      value = q->Result;
85601e04c3fSmrg      break;
85701e04c3fSmrg   case GL_QUERY_RESULT_NO_WAIT:
85801e04c3fSmrg      if (!ctx->Extensions.ARB_query_buffer_object)
85901e04c3fSmrg         goto invalid_enum;
86001e04c3fSmrg      ctx->Driver.CheckQuery(ctx, q);
86101e04c3fSmrg      if (!q->Ready)
8627117f1b4Smrg         return;
86301e04c3fSmrg      value = q->Result;
86401e04c3fSmrg      break;
86501e04c3fSmrg   case GL_QUERY_RESULT_AVAILABLE:
86601e04c3fSmrg      if (!q->Ready)
86701e04c3fSmrg         ctx->Driver.CheckQuery(ctx, q);
86801e04c3fSmrg      value = q->Ready;
86901e04c3fSmrg      break;
87001e04c3fSmrg   case GL_QUERY_TARGET:
87101e04c3fSmrg      value = q->Target;
87201e04c3fSmrg      break;
87301e04c3fSmrg   default:
87401e04c3fSmrginvalid_enum:
87501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)",
87601e04c3fSmrg                  func, _mesa_enum_to_string(pname));
87701e04c3fSmrg      return;
87801e04c3fSmrg   }
87901e04c3fSmrg
88001e04c3fSmrg   switch (ptype) {
88101e04c3fSmrg   case GL_INT: {
88201e04c3fSmrg      GLint *param = (GLint *)offset;
88301e04c3fSmrg      if (value > 0x7fffffff)
88401e04c3fSmrg         *param = 0x7fffffff;
88501e04c3fSmrg      else
88601e04c3fSmrg         *param = value;
88701e04c3fSmrg      break;
88801e04c3fSmrg   }
88901e04c3fSmrg   case GL_UNSIGNED_INT: {
89001e04c3fSmrg      GLuint *param = (GLuint *)offset;
89101e04c3fSmrg      if (value > 0xffffffff)
89201e04c3fSmrg         *param = 0xffffffff;
89301e04c3fSmrg      else
89401e04c3fSmrg         *param = value;
89501e04c3fSmrg      break;
89601e04c3fSmrg   }
89701e04c3fSmrg   case GL_INT64_ARB:
89801e04c3fSmrg   case GL_UNSIGNED_INT64_ARB: {
89901e04c3fSmrg      GLuint64EXT *param = (GLuint64EXT *)offset;
90001e04c3fSmrg      *param = value;
90101e04c3fSmrg      break;
9027117f1b4Smrg   }
90301e04c3fSmrg   default:
90401e04c3fSmrg      unreachable("unexpected ptype");
90501e04c3fSmrg   }
90601e04c3fSmrg}
90701e04c3fSmrg
90801e04c3fSmrgvoid GLAPIENTRY
90901e04c3fSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
91001e04c3fSmrg{
91101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
91201e04c3fSmrg
91301e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectiv",
91401e04c3fSmrg                    id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params);
9157117f1b4Smrg}
9167117f1b4Smrg
9177117f1b4Smrg
918af69d88dSmrgvoid GLAPIENTRY
919af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
9207117f1b4Smrg{
9217117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9227117f1b4Smrg
92301e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectuiv",
92401e04c3fSmrg                    id, pname, GL_UNSIGNED_INT,
92501e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
92601e04c3fSmrg}
9273464ebd5Sriastradh
9287117f1b4Smrg
92901e04c3fSmrg/**
93001e04c3fSmrg * New with GL_EXT_timer_query
93101e04c3fSmrg */
93201e04c3fSmrgvoid GLAPIENTRY
93301e04c3fSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
93401e04c3fSmrg{
93501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9367117f1b4Smrg
93701e04c3fSmrg   get_query_object(ctx, "glGetQueryObjecti64v",
93801e04c3fSmrg                    id, pname, GL_INT64_ARB,
93901e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
9407117f1b4Smrg}
9417117f1b4Smrg
9427117f1b4Smrg
9437117f1b4Smrg/**
9447117f1b4Smrg * New with GL_EXT_timer_query
9457117f1b4Smrg */
946af69d88dSmrgvoid GLAPIENTRY
94701e04c3fSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
9487117f1b4Smrg{
9497117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9507117f1b4Smrg
95101e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectui64v",
95201e04c3fSmrg                    id, pname, GL_UNSIGNED_INT64_ARB,
95301e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
95401e04c3fSmrg}
9553464ebd5Sriastradh
95601e04c3fSmrg/**
95701e04c3fSmrg * New with GL_ARB_query_buffer_object
95801e04c3fSmrg */
95901e04c3fSmrgvoid GLAPIENTRY
96001e04c3fSmrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
96101e04c3fSmrg                             GLintptr offset)
96201e04c3fSmrg{
96301e04c3fSmrg   struct gl_buffer_object *buf;
96401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9657117f1b4Smrg
96601e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv");
96701e04c3fSmrg   if (!buf)
9687117f1b4Smrg      return;
9697117f1b4Smrg
97001e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectiv",
97101e04c3fSmrg                    id, pname, GL_INT, buf, offset);
9727117f1b4Smrg}
9737117f1b4Smrg
9747117f1b4Smrg
975af69d88dSmrgvoid GLAPIENTRY
97601e04c3fSmrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
97701e04c3fSmrg                              GLintptr offset)
9787117f1b4Smrg{
97901e04c3fSmrg   struct gl_buffer_object *buf;
9807117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9817117f1b4Smrg
98201e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv");
98301e04c3fSmrg   if (!buf)
98401e04c3fSmrg      return;
9853464ebd5Sriastradh
98601e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectuiv",
98701e04c3fSmrg                    id, pname, GL_UNSIGNED_INT, buf, offset);
98801e04c3fSmrg}
9897117f1b4Smrg
99001e04c3fSmrg
99101e04c3fSmrgvoid GLAPIENTRY
99201e04c3fSmrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
99301e04c3fSmrg                               GLintptr offset)
99401e04c3fSmrg{
99501e04c3fSmrg   struct gl_buffer_object *buf;
99601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
99701e04c3fSmrg
99801e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v");
99901e04c3fSmrg   if (!buf)
10007117f1b4Smrg      return;
10017117f1b4Smrg
100201e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjecti64v",
100301e04c3fSmrg                    id, pname, GL_INT64_ARB, buf, offset);
10047117f1b4Smrg}
10057117f1b4Smrg
100601e04c3fSmrg
100701e04c3fSmrgvoid GLAPIENTRY
100801e04c3fSmrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
100901e04c3fSmrg                                GLintptr offset)
101001e04c3fSmrg{
101101e04c3fSmrg   struct gl_buffer_object *buf;
101201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
101301e04c3fSmrg
101401e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v");
101501e04c3fSmrg   if (!buf)
101601e04c3fSmrg      return;
101701e04c3fSmrg
101801e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectui64v",
101901e04c3fSmrg                    id, pname, GL_UNSIGNED_INT64_ARB, buf, offset);
102001e04c3fSmrg}
102101e04c3fSmrg
102201e04c3fSmrg
10237117f1b4Smrg/**
10247117f1b4Smrg * Allocate/init the context state related to query objects.
10257117f1b4Smrg */
10267117f1b4Smrgvoid
10273464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx)
10287117f1b4Smrg{
10297117f1b4Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
10307117f1b4Smrg   ctx->Query.CurrentOcclusionObject = NULL;
1031af69d88dSmrg
1032af69d88dSmrg   ctx->Const.QueryCounterBits.SamplesPassed = 64;
1033af69d88dSmrg   ctx->Const.QueryCounterBits.TimeElapsed = 64;
1034af69d88dSmrg   ctx->Const.QueryCounterBits.Timestamp = 64;
1035af69d88dSmrg   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
1036af69d88dSmrg   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
103701e04c3fSmrg
103801e04c3fSmrg   ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
103901e04c3fSmrg   ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
104001e04c3fSmrg   ctx->Const.QueryCounterBits.VsInvocations = 64;
104101e04c3fSmrg   ctx->Const.QueryCounterBits.TessPatches = 64;
104201e04c3fSmrg   ctx->Const.QueryCounterBits.TessInvocations = 64;
104301e04c3fSmrg   ctx->Const.QueryCounterBits.GsInvocations = 64;
104401e04c3fSmrg   ctx->Const.QueryCounterBits.GsPrimitives = 64;
104501e04c3fSmrg   ctx->Const.QueryCounterBits.FsInvocations = 64;
104601e04c3fSmrg   ctx->Const.QueryCounterBits.ComputeInvocations = 64;
104701e04c3fSmrg   ctx->Const.QueryCounterBits.ClInPrimitives = 64;
104801e04c3fSmrg   ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
10497117f1b4Smrg}
10507117f1b4Smrg
10517117f1b4Smrg
10527117f1b4Smrg/**
10537117f1b4Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
10547117f1b4Smrg */
10557117f1b4Smrgstatic void
10567117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData)
10577117f1b4Smrg{
10587117f1b4Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
10593464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *)userData;
1060c1f859d4Smrg   ctx->Driver.DeleteQuery(ctx, q);
10617117f1b4Smrg}
10627117f1b4Smrg
10637117f1b4Smrg
10647117f1b4Smrg/**
10657117f1b4Smrg * Free the context state related to query objects.
10667117f1b4Smrg */
10677117f1b4Smrgvoid
10683464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx)
10697117f1b4Smrg{
1070c1f859d4Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
10717117f1b4Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
10727117f1b4Smrg}
1073