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"
317ec681f3Smrg
327117f1b4Smrg#include "queryobj.h"
337117f1b4Smrg#include "mtypes.h"
347ec681f3Smrg#include "util/u_memory.h"
354a49301eSmrg
364a49301eSmrg
377117f1b4Smrg/**
387117f1b4Smrg * Allocate a new query object.  This is a fallback routine called via
397117f1b4Smrg * ctx->Driver.NewQueryObject().
407117f1b4Smrg * \param ctx - rendering context
417117f1b4Smrg * \param id - the new object's ID
427117f1b4Smrg * \return pointer to new query_object object or NULL if out of memory.
437117f1b4Smrg */
444a49301eSmrgstatic struct gl_query_object *
453464ebd5Sriastradh_mesa_new_query_object(struct gl_context *ctx, GLuint id)
467117f1b4Smrg{
47af69d88dSmrg   struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
487117f1b4Smrg   (void) ctx;
497117f1b4Smrg   if (q) {
507117f1b4Smrg      q->Id = id;
517117f1b4Smrg      q->Result = 0;
527117f1b4Smrg      q->Active = GL_FALSE;
53af69d88dSmrg
54af69d88dSmrg      /* This is to satisfy the language of the specification: "In the initial
55af69d88dSmrg       * state of a query object, the result is available" (OpenGL 3.1 §
56af69d88dSmrg       * 2.13).
57af69d88dSmrg       */
58af69d88dSmrg      q->Ready = GL_TRUE;
59af69d88dSmrg
60af69d88dSmrg      /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as
61af69d88dSmrg       * used, but no object is associated with them until the first time they
62af69d88dSmrg       * are used by BeginQuery." Since our implementation actually does
63af69d88dSmrg       * allocate an object at this point, use a flag to indicate that this
64af69d88dSmrg       * object has not yet been bound so should not be considered a query.
65af69d88dSmrg       */
66af69d88dSmrg      q->EverBound = GL_FALSE;
677117f1b4Smrg   }
687117f1b4Smrg   return q;
697117f1b4Smrg}
707117f1b4Smrg
717117f1b4Smrg
727117f1b4Smrg/**
73c1f859d4Smrg * Begin a query.  Software driver fallback.
74c1f859d4Smrg * Called via ctx->Driver.BeginQuery().
75c1f859d4Smrg */
764a49301eSmrgstatic void
773464ebd5Sriastradh_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
78c1f859d4Smrg{
79af69d88dSmrg   ctx->NewState |= _NEW_DEPTH; /* for swrast */
80c1f859d4Smrg}
81c1f859d4Smrg
82c1f859d4Smrg
83c1f859d4Smrg/**
84c1f859d4Smrg * End a query.  Software driver fallback.
85c1f859d4Smrg * Called via ctx->Driver.EndQuery().
86c1f859d4Smrg */
874a49301eSmrgstatic void
883464ebd5Sriastradh_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
89c1f859d4Smrg{
90af69d88dSmrg   ctx->NewState |= _NEW_DEPTH; /* for swrast */
91c1f859d4Smrg   q->Ready = GL_TRUE;
92c1f859d4Smrg}
93c1f859d4Smrg
94c1f859d4Smrg
95c1f859d4Smrg/**
96c1f859d4Smrg * Wait for query to complete.  Software driver fallback.
97c1f859d4Smrg * Called via ctx->Driver.WaitQuery().
98c1f859d4Smrg */
994a49301eSmrgstatic void
1003464ebd5Sriastradh_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
101c1f859d4Smrg{
102c1f859d4Smrg   /* For software drivers, _mesa_end_query() should have completed the query.
1034a49301eSmrg    * For real hardware, implement a proper WaitQuery() driver function,
1044a49301eSmrg    * which may require issuing a flush.
105c1f859d4Smrg    */
106c1f859d4Smrg   assert(q->Ready);
107c1f859d4Smrg}
108c1f859d4Smrg
109c1f859d4Smrg
1104a49301eSmrg/**
1114a49301eSmrg * Check if a query results are ready.  Software driver fallback.
1124a49301eSmrg * Called via ctx->Driver.CheckQuery().
1134a49301eSmrg */
1144a49301eSmrgstatic void
1153464ebd5Sriastradh_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
1164a49301eSmrg{
1174a49301eSmrg   /* No-op for sw rendering.
1184a49301eSmrg    * HW drivers may need to flush at this time.
1194a49301eSmrg    */
1204a49301eSmrg}
1214a49301eSmrg
1224a49301eSmrg
123c1f859d4Smrg/**
1247ec681f3Smrg * Delete a query object.  Called via ctx->Driver.DeleteQuery(), if not
1257ec681f3Smrg * overwritten by driver.  In the latter case, called from the driver
1267ec681f3Smrg * after all driver-specific clean-up has been done.
1277117f1b4Smrg * Not removed from hash table here.
1287ec681f3Smrg *
1297ec681f3Smrg * \param ctx GL context to wich query object belongs.
1307ec681f3Smrg * \param q query object due to be deleted.
1317117f1b4Smrg */
1327ec681f3Smrgvoid
1333464ebd5Sriastradh_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
1347117f1b4Smrg{
135af69d88dSmrg   free(q->Label);
136cdc920a0Smrg   free(q);
1377117f1b4Smrg}
1387117f1b4Smrg
1397117f1b4Smrg
1404a49301eSmrgvoid
1414a49301eSmrg_mesa_init_query_object_functions(struct dd_function_table *driver)
1424a49301eSmrg{
1434a49301eSmrg   driver->NewQueryObject = _mesa_new_query_object;
1444a49301eSmrg   driver->DeleteQuery = _mesa_delete_query;
1454a49301eSmrg   driver->BeginQuery = _mesa_begin_query;
1464a49301eSmrg   driver->EndQuery = _mesa_end_query;
1474a49301eSmrg   driver->WaitQuery = _mesa_wait_query;
1484a49301eSmrg   driver->CheckQuery = _mesa_check_query;
1494a49301eSmrg}
1504a49301eSmrg
15101e04c3fSmrgstatic struct gl_query_object **
15201e04c3fSmrgget_pipe_stats_binding_point(struct gl_context *ctx,
15301e04c3fSmrg                             GLenum target)
15401e04c3fSmrg{
155b9abf16eSmaya   const int which = target - GL_VERTICES_SUBMITTED;
15601e04c3fSmrg   assert(which < MAX_PIPELINE_STATISTICS);
15701e04c3fSmrg
158b9abf16eSmaya   if (!_mesa_has_ARB_pipeline_statistics_query(ctx))
15901e04c3fSmrg      return NULL;
16001e04c3fSmrg
16101e04c3fSmrg   return &ctx->Query.pipeline_stats[which];
16201e04c3fSmrg}
1634a49301eSmrg
1643464ebd5Sriastradh/**
165af69d88dSmrg * Return pointer to the query object binding point for the given target and
166af69d88dSmrg * index.
1673464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point
1683464ebd5Sriastradh */
1693464ebd5Sriastradhstatic struct gl_query_object **
170af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
1713464ebd5Sriastradh{
1723464ebd5Sriastradh   switch (target) {
173b9abf16eSmaya   case GL_SAMPLES_PASSED:
174b9abf16eSmaya      if (_mesa_has_ARB_occlusion_query(ctx) ||
175b9abf16eSmaya          _mesa_has_ARB_occlusion_query2(ctx))
1763464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1773464ebd5Sriastradh      else
1783464ebd5Sriastradh         return NULL;
1793464ebd5Sriastradh   case GL_ANY_SAMPLES_PASSED:
180b9abf16eSmaya      if (_mesa_has_ARB_occlusion_query2(ctx) ||
181b9abf16eSmaya          _mesa_has_EXT_occlusion_query_boolean(ctx))
1823464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1833464ebd5Sriastradh      else
1843464ebd5Sriastradh         return NULL;
185af69d88dSmrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
186b9abf16eSmaya      if (_mesa_has_ARB_ES3_compatibility(ctx) ||
187b9abf16eSmaya          _mesa_has_EXT_occlusion_query_boolean(ctx))
188af69d88dSmrg         return &ctx->Query.CurrentOcclusionObject;
189af69d88dSmrg      else
190af69d88dSmrg         return NULL;
191b9abf16eSmaya   case GL_TIME_ELAPSED:
192b9abf16eSmaya      if (_mesa_has_EXT_timer_query(ctx) ||
193b9abf16eSmaya          _mesa_has_EXT_disjoint_timer_query(ctx))
1943464ebd5Sriastradh         return &ctx->Query.CurrentTimerObject;
1953464ebd5Sriastradh      else
1963464ebd5Sriastradh         return NULL;
1973464ebd5Sriastradh   case GL_PRIMITIVES_GENERATED:
198b9abf16eSmaya      if (_mesa_has_EXT_transform_feedback(ctx) ||
199b9abf16eSmaya          _mesa_has_EXT_tessellation_shader(ctx) ||
200b9abf16eSmaya          _mesa_has_OES_geometry_shader(ctx))
201af69d88dSmrg         return &ctx->Query.PrimitivesGenerated[index];
2023464ebd5Sriastradh      else
2033464ebd5Sriastradh         return NULL;
2043464ebd5Sriastradh   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
205b9abf16eSmaya      if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx))
206af69d88dSmrg         return &ctx->Query.PrimitivesWritten[index];
2073464ebd5Sriastradh      else
2083464ebd5Sriastradh         return NULL;
209b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
210b9abf16eSmaya      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
21101e04c3fSmrg         return &ctx->Query.TransformFeedbackOverflow[index];
21201e04c3fSmrg      else
21301e04c3fSmrg         return NULL;
214b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
215b9abf16eSmaya      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
21601e04c3fSmrg         return &ctx->Query.TransformFeedbackOverflowAny;
21701e04c3fSmrg      else
21801e04c3fSmrg         return NULL;
21901e04c3fSmrg
220b9abf16eSmaya   case GL_VERTICES_SUBMITTED:
221b9abf16eSmaya   case GL_PRIMITIVES_SUBMITTED:
222b9abf16eSmaya   case GL_VERTEX_SHADER_INVOCATIONS:
223b9abf16eSmaya   case GL_FRAGMENT_SHADER_INVOCATIONS:
224b9abf16eSmaya   case GL_CLIPPING_INPUT_PRIMITIVES:
225b9abf16eSmaya   case GL_CLIPPING_OUTPUT_PRIMITIVES:
22601e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
22701e04c3fSmrg
22801e04c3fSmrg   case GL_GEOMETRY_SHADER_INVOCATIONS:
22901e04c3fSmrg      /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
230b9abf16eSmaya      target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1;
2317ec681f3Smrg      FALLTHROUGH;
232b9abf16eSmaya   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
23301e04c3fSmrg      if (_mesa_has_geometry_shaders(ctx))
23401e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
23501e04c3fSmrg      else
23601e04c3fSmrg         return NULL;
23701e04c3fSmrg
238b9abf16eSmaya   case GL_TESS_CONTROL_SHADER_PATCHES:
239b9abf16eSmaya   case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
24001e04c3fSmrg      if (_mesa_has_tessellation(ctx))
24101e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
24201e04c3fSmrg      else
24301e04c3fSmrg         return NULL;
24401e04c3fSmrg
245b9abf16eSmaya   case GL_COMPUTE_SHADER_INVOCATIONS:
24601e04c3fSmrg      if (_mesa_has_compute_shaders(ctx))
24701e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
24801e04c3fSmrg      else
24901e04c3fSmrg         return NULL;
25001e04c3fSmrg
2513464ebd5Sriastradh   default:
2523464ebd5Sriastradh      return NULL;
2533464ebd5Sriastradh   }
2543464ebd5Sriastradh}
2553464ebd5Sriastradh
25601e04c3fSmrg/**
25701e04c3fSmrg * Create $n query objects and store them in *ids. Make them of type $target
25801e04c3fSmrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
25901e04c3fSmrg */
26001e04c3fSmrgstatic void
26101e04c3fSmrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
26201e04c3fSmrg               bool dsa)
2637117f1b4Smrg{
26401e04c3fSmrg   const char *func = dsa ? "glGenQueries" : "glCreateQueries";
2657117f1b4Smrg
2663464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
26701e04c3fSmrg      _mesa_debug(ctx, "%s(%d)\n", func, n);
2683464ebd5Sriastradh
2697117f1b4Smrg   if (n < 0) {
27001e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
2717117f1b4Smrg      return;
2727117f1b4Smrg   }
2737117f1b4Smrg
2747ec681f3Smrg   if (_mesa_HashFindFreeKeys(ctx->Query.QueryObjects, ids, n)) {
2757117f1b4Smrg      GLsizei i;
2767117f1b4Smrg      for (i = 0; i < n; i++) {
2777117f1b4Smrg         struct gl_query_object *q
2787ec681f3Smrg            = ctx->Driver.NewQueryObject(ctx, ids[i]);
2797117f1b4Smrg         if (!q) {
28001e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
2817117f1b4Smrg            return;
28201e04c3fSmrg         } else if (dsa) {
28301e04c3fSmrg            /* Do the equivalent of binding the buffer with a target */
28401e04c3fSmrg            q->Target = target;
28501e04c3fSmrg            q->EverBound = GL_TRUE;
2867117f1b4Smrg         }
2877ec681f3Smrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, ids[i], q, true);
2887117f1b4Smrg      }
2897117f1b4Smrg   }
2907117f1b4Smrg}
2917117f1b4Smrg
29201e04c3fSmrgvoid GLAPIENTRY
29301e04c3fSmrg_mesa_GenQueries(GLsizei n, GLuint *ids)
29401e04c3fSmrg{
29501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
29601e04c3fSmrg   create_queries(ctx, 0, n, ids, false);
29701e04c3fSmrg}
29801e04c3fSmrg
29901e04c3fSmrgvoid GLAPIENTRY
30001e04c3fSmrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
30101e04c3fSmrg{
30201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
30301e04c3fSmrg
30401e04c3fSmrg   switch (target) {
30501e04c3fSmrg   case GL_SAMPLES_PASSED:
30601e04c3fSmrg   case GL_ANY_SAMPLES_PASSED:
30701e04c3fSmrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
30801e04c3fSmrg   case GL_TIME_ELAPSED:
30901e04c3fSmrg   case GL_TIMESTAMP:
31001e04c3fSmrg   case GL_PRIMITIVES_GENERATED:
31101e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
312b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
313b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
31401e04c3fSmrg      break;
31501e04c3fSmrg   default:
31601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
31701e04c3fSmrg                  _mesa_enum_to_string(target));
31801e04c3fSmrg      return;
31901e04c3fSmrg   }
32001e04c3fSmrg
32101e04c3fSmrg   create_queries(ctx, target, n, ids, true);
32201e04c3fSmrg}
32301e04c3fSmrg
3247117f1b4Smrg
325af69d88dSmrgvoid GLAPIENTRY
326af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids)
3277117f1b4Smrg{
3287117f1b4Smrg   GLint i;
3297117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3307ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
3313464ebd5Sriastradh
3323464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
333af69d88dSmrg      _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
3347117f1b4Smrg
3357117f1b4Smrg   if (n < 0) {
3367117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
3377117f1b4Smrg      return;
3387117f1b4Smrg   }
3397117f1b4Smrg
3407117f1b4Smrg   for (i = 0; i < n; i++) {
3417117f1b4Smrg      if (ids[i] > 0) {
342cdc920a0Smrg         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
3437117f1b4Smrg         if (q) {
344af69d88dSmrg            if (q->Active) {
345af69d88dSmrg               struct gl_query_object **bindpt;
346af69d88dSmrg               bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
347af69d88dSmrg               assert(bindpt); /* Should be non-null for active q. */
348af69d88dSmrg               if (bindpt) {
349af69d88dSmrg                  *bindpt = NULL;
350af69d88dSmrg               }
351af69d88dSmrg               q->Active = GL_FALSE;
352af69d88dSmrg               ctx->Driver.EndQuery(ctx, q);
353af69d88dSmrg            }
35401e04c3fSmrg            _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]);
355c1f859d4Smrg            ctx->Driver.DeleteQuery(ctx, q);
3567117f1b4Smrg         }
3577117f1b4Smrg      }
3587117f1b4Smrg   }
3597117f1b4Smrg}
3607117f1b4Smrg
3617117f1b4Smrg
362af69d88dSmrgGLboolean GLAPIENTRY
363af69d88dSmrg_mesa_IsQuery(GLuint id)
3647117f1b4Smrg{
365af69d88dSmrg   struct gl_query_object *q;
366af69d88dSmrg
3677117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3687117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
3697117f1b4Smrg
3703464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
3713464ebd5Sriastradh      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
3723464ebd5Sriastradh
373af69d88dSmrg   if (id == 0)
374af69d88dSmrg      return GL_FALSE;
375af69d88dSmrg
376af69d88dSmrg   q = _mesa_lookup_query_object(ctx, id);
377af69d88dSmrg   if (q == NULL)
3787117f1b4Smrg      return GL_FALSE;
379af69d88dSmrg
380af69d88dSmrg   return q->EverBound;
3817117f1b4Smrg}
3827117f1b4Smrg
383af69d88dSmrgstatic GLboolean
384af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
385af69d88dSmrg{
386af69d88dSmrg   switch (target) {
387af69d88dSmrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
388af69d88dSmrg   case GL_PRIMITIVES_GENERATED:
389b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
390af69d88dSmrg      if (index >= ctx->Const.MaxVertexStreams) {
391af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
392af69d88dSmrg                     "glBeginQueryIndexed(index>=MaxVertexStreams)");
393af69d88dSmrg         return GL_FALSE;
394af69d88dSmrg      }
395af69d88dSmrg      break;
396af69d88dSmrg   default:
397af69d88dSmrg      if (index > 0) {
398af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
399af69d88dSmrg         return GL_FALSE;
400af69d88dSmrg      }
401af69d88dSmrg   }
402af69d88dSmrg   return GL_TRUE;
403af69d88dSmrg}
4047117f1b4Smrg
405af69d88dSmrgvoid GLAPIENTRY
406af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
4077117f1b4Smrg{
4083464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
4097117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4107117f1b4Smrg
4113464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
412af69d88dSmrg      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
41301e04c3fSmrg                  _mesa_enum_to_string(target), index, id);
4143464ebd5Sriastradh
415af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
416af69d88dSmrg      return;
417af69d88dSmrg
4187ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
4197117f1b4Smrg
420af69d88dSmrg   bindpt = get_query_binding_point(ctx, target, index);
4213464ebd5Sriastradh   if (!bindpt) {
422af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
423af69d88dSmrg      return;
424af69d88dSmrg   }
425af69d88dSmrg
426af69d88dSmrg   /* From the GL_ARB_occlusion_query spec:
427af69d88dSmrg    *
428af69d88dSmrg    *     "If BeginQueryARB is called while another query is already in
429af69d88dSmrg    *      progress with the same target, an INVALID_OPERATION error is
430af69d88dSmrg    *      generated."
431af69d88dSmrg    */
432af69d88dSmrg   if (*bindpt) {
433af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
434af69d88dSmrg                  "glBeginQuery{Indexed}(target=%s is active)",
43501e04c3fSmrg                  _mesa_enum_to_string(target));
4363464ebd5Sriastradh      return;
4377117f1b4Smrg   }
4387117f1b4Smrg
4397117f1b4Smrg   if (id == 0) {
440af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
4417117f1b4Smrg      return;
4427117f1b4Smrg   }
4437117f1b4Smrg
444cdc920a0Smrg   q = _mesa_lookup_query_object(ctx, id);
4457117f1b4Smrg   if (!q) {
446af69d88dSmrg      if (ctx->API != API_OPENGL_COMPAT) {
447af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
448af69d88dSmrg                     "glBeginQuery{Indexed}(non-gen name)");
4497117f1b4Smrg         return;
450af69d88dSmrg      } else {
451af69d88dSmrg         /* create new object */
452af69d88dSmrg         q = ctx->Driver.NewQueryObject(ctx, id);
453af69d88dSmrg         if (!q) {
454af69d88dSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
455af69d88dSmrg            return;
456af69d88dSmrg         }
4577ec681f3Smrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false);
4587117f1b4Smrg      }
4597117f1b4Smrg   }
4607117f1b4Smrg   else {
4617117f1b4Smrg      /* pre-existing object */
4627117f1b4Smrg      if (q->Active) {
4637117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
464af69d88dSmrg                     "glBeginQuery{Indexed}(query already active)");
4657117f1b4Smrg         return;
4667117f1b4Smrg      }
46701e04c3fSmrg
46801e04c3fSmrg      /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
46901e04c3fSmrg       * spec states:
47001e04c3fSmrg       *
47101e04c3fSmrg       *     "BeginQuery generates an INVALID_OPERATION error if any of the
47201e04c3fSmrg       *      following conditions hold: [...] id is the name of an
47301e04c3fSmrg       *      existing query object whose type does not match target; [...]
47401e04c3fSmrg       *
47501e04c3fSmrg       * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
47601e04c3fSmrg       * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
47701e04c3fSmrg       */
47801e04c3fSmrg      if (q->EverBound && q->Target != target) {
47901e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
48001e04c3fSmrg                     "glBeginQuery{Indexed}(target mismatch)");
48101e04c3fSmrg         return;
48201e04c3fSmrg      }
4837117f1b4Smrg   }
4847117f1b4Smrg
48501e04c3fSmrg   /* This possibly changes the target of a buffer allocated by
48601e04c3fSmrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
48701e04c3fSmrg    * the following:
48801e04c3fSmrg    *
48901e04c3fSmrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
49001e04c3fSmrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
49101e04c3fSmrg    * isn't a selector, so we decided not to change it."
49201e04c3fSmrg    *
49301e04c3fSmrg    * Updating the target of the query object should be acceptable, so let's
49401e04c3fSmrg    * do that.
49501e04c3fSmrg    */
49601e04c3fSmrg
497c1f859d4Smrg   q->Target = target;
4987117f1b4Smrg   q->Active = GL_TRUE;
4997117f1b4Smrg   q->Result = 0;
5007117f1b4Smrg   q->Ready = GL_FALSE;
501af69d88dSmrg   q->EverBound = GL_TRUE;
502af69d88dSmrg   q->Stream = index;
5037117f1b4Smrg
5043464ebd5Sriastradh   /* XXX should probably refcount query objects */
5053464ebd5Sriastradh   *bindpt = q;
5067117f1b4Smrg
507c1f859d4Smrg   ctx->Driver.BeginQuery(ctx, q);
5087117f1b4Smrg}
5097117f1b4Smrg
5107117f1b4Smrg
511af69d88dSmrgvoid GLAPIENTRY
512af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index)
5137117f1b4Smrg{
5143464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
5157117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5167117f1b4Smrg
5173464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
518af69d88dSmrg      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
51901e04c3fSmrg                  _mesa_enum_to_string(target), index);
5203464ebd5Sriastradh
521af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
522af69d88dSmrg      return;
5237117f1b4Smrg
5247ec681f3Smrg   FLUSH_VERTICES(ctx, 0, 0);
525af69d88dSmrg
526af69d88dSmrg   bindpt = get_query_binding_point(ctx, target, index);
5273464ebd5Sriastradh   if (!bindpt) {
528af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
5293464ebd5Sriastradh      return;
5307117f1b4Smrg   }
5317117f1b4Smrg
5323464ebd5Sriastradh   /* XXX should probably refcount query objects */
5333464ebd5Sriastradh   q = *bindpt;
534af69d88dSmrg
535af69d88dSmrg   /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
536af69d88dSmrg   if (q && q->Target != target) {
537af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
538af69d88dSmrg                  "glEndQuery(target=%s with active query of target %s)",
53901e04c3fSmrg                  _mesa_enum_to_string(target),
54001e04c3fSmrg                  _mesa_enum_to_string(q->Target));
541af69d88dSmrg      return;
542af69d88dSmrg   }
543af69d88dSmrg
5443464ebd5Sriastradh   *bindpt = NULL;
5453464ebd5Sriastradh
5467117f1b4Smrg   if (!q || !q->Active) {
5477117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
548af69d88dSmrg                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
5497117f1b4Smrg      return;
5507117f1b4Smrg   }
5517117f1b4Smrg
5527117f1b4Smrg   q->Active = GL_FALSE;
553c1f859d4Smrg   ctx->Driver.EndQuery(ctx, q);
5547117f1b4Smrg}
5557117f1b4Smrg
556af69d88dSmrgvoid GLAPIENTRY
557af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id)
558af69d88dSmrg{
559af69d88dSmrg   _mesa_BeginQueryIndexed(target, 0, id);
560af69d88dSmrg}
5617117f1b4Smrg
562af69d88dSmrgvoid GLAPIENTRY
563af69d88dSmrg_mesa_EndQuery(GLenum target)
5647117f1b4Smrg{
565af69d88dSmrg   _mesa_EndQueryIndexed(target, 0);
566af69d88dSmrg}
567af69d88dSmrg
568af69d88dSmrgvoid GLAPIENTRY
569af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target)
570af69d88dSmrg{
571af69d88dSmrg   struct gl_query_object *q;
5727117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5737117f1b4Smrg
5743464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
575af69d88dSmrg      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
57601e04c3fSmrg                  _mesa_enum_to_string(target));
577af69d88dSmrg
578af69d88dSmrg   /* error checking */
579af69d88dSmrg   if (target != GL_TIMESTAMP) {
580af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
581af69d88dSmrg      return;
582af69d88dSmrg   }
583af69d88dSmrg
584af69d88dSmrg   if (id == 0) {
585af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
586af69d88dSmrg      return;
587af69d88dSmrg   }
588af69d88dSmrg
589af69d88dSmrg   q = _mesa_lookup_query_object(ctx, id);
590af69d88dSmrg   if (!q) {
591af69d88dSmrg      /* XXX the Core profile should throw INVALID_OPERATION here */
592af69d88dSmrg
593af69d88dSmrg      /* create new object */
594af69d88dSmrg      q = ctx->Driver.NewQueryObject(ctx, id);
595af69d88dSmrg      if (!q) {
596af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
597af69d88dSmrg         return;
598af69d88dSmrg      }
5997ec681f3Smrg      _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false);
600af69d88dSmrg   }
601af69d88dSmrg   else {
602af69d88dSmrg      if (q->Target && q->Target != GL_TIMESTAMP) {
603af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
604af69d88dSmrg                     "glQueryCounter(id has an invalid target)");
605af69d88dSmrg         return;
606af69d88dSmrg      }
607af69d88dSmrg   }
608af69d88dSmrg
609af69d88dSmrg   if (q->Active) {
610af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
611af69d88dSmrg      return;
612af69d88dSmrg   }
613af69d88dSmrg
61401e04c3fSmrg   /* This possibly changes the target of a buffer allocated by
61501e04c3fSmrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
61601e04c3fSmrg    * the following:
61701e04c3fSmrg    *
61801e04c3fSmrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
61901e04c3fSmrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
62001e04c3fSmrg    * isn't a selector, so we decided not to change it."
62101e04c3fSmrg    *
62201e04c3fSmrg    * Updating the target of the query object should be acceptable, so let's
62301e04c3fSmrg    * do that.
62401e04c3fSmrg    */
62501e04c3fSmrg
626af69d88dSmrg   q->Target = target;
627af69d88dSmrg   q->Result = 0;
628af69d88dSmrg   q->Ready = GL_FALSE;
629af69d88dSmrg   q->EverBound = GL_TRUE;
630af69d88dSmrg
631af69d88dSmrg   if (ctx->Driver.QueryCounter) {
632af69d88dSmrg      ctx->Driver.QueryCounter(ctx, q);
633af69d88dSmrg   } else {
634af69d88dSmrg      /* QueryCounter is implemented using EndQuery without BeginQuery
635af69d88dSmrg       * in drivers. This is actually Direct3D and Gallium convention.
636af69d88dSmrg       */
637af69d88dSmrg      ctx->Driver.EndQuery(ctx, q);
638af69d88dSmrg   }
639af69d88dSmrg}
640af69d88dSmrg
641af69d88dSmrg
642af69d88dSmrgvoid GLAPIENTRY
643af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
644af69d88dSmrg                        GLint *params)
645af69d88dSmrg{
646af69d88dSmrg   struct gl_query_object *q = NULL, **bindpt = NULL;
647af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
648af69d88dSmrg
649af69d88dSmrg   if (MESA_VERBOSE & VERBOSE_API)
650af69d88dSmrg      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
65101e04c3fSmrg                  _mesa_enum_to_string(target),
652af69d88dSmrg                  index,
65301e04c3fSmrg                  _mesa_enum_to_string(pname));
6543464ebd5Sriastradh
655af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
6563464ebd5Sriastradh      return;
657af69d88dSmrg
65801e04c3fSmrg   /* From the GL_EXT_occlusion_query_boolean spec:
65901e04c3fSmrg    *
66001e04c3fSmrg    * "The error INVALID_ENUM is generated if GetQueryivEXT is called where
66101e04c3fSmrg    * <pname> is not CURRENT_QUERY_EXT."
66201e04c3fSmrg    *
66301e04c3fSmrg    * Same rule is present also in ES 3.2 spec.
6647ec681f3Smrg    *
6657ec681f3Smrg    * EXT_disjoint_timer_query extends this with GL_QUERY_COUNTER_BITS.
66601e04c3fSmrg    */
6677ec681f3Smrg   if (_mesa_is_gles(ctx)) {
6687ec681f3Smrg      switch (pname) {
6697ec681f3Smrg      case GL_CURRENT_QUERY:
6707ec681f3Smrg         break;
6717ec681f3Smrg      case GL_QUERY_COUNTER_BITS:
6727ec681f3Smrg         if (_mesa_has_EXT_disjoint_timer_query(ctx))
6737ec681f3Smrg            break;
6747ec681f3Smrg         FALLTHROUGH;
6757ec681f3Smrg      default:
6767ec681f3Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)",
6777ec681f3Smrg                     _mesa_enum_to_string(pname));
6787ec681f3Smrg      }
67901e04c3fSmrg   }
68001e04c3fSmrg
681af69d88dSmrg   if (target == GL_TIMESTAMP) {
682b9abf16eSmaya      if (!_mesa_has_ARB_timer_query(ctx) &&
683b9abf16eSmaya          !_mesa_has_EXT_disjoint_timer_query(ctx)) {
684af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
685af69d88dSmrg         return;
686af69d88dSmrg      }
6877117f1b4Smrg   }
688af69d88dSmrg   else {
689af69d88dSmrg      bindpt = get_query_binding_point(ctx, target, index);
690af69d88dSmrg      if (!bindpt) {
691af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
692af69d88dSmrg         return;
693af69d88dSmrg      }
6947117f1b4Smrg
695af69d88dSmrg      q = *bindpt;
696af69d88dSmrg   }
6973464ebd5Sriastradh
6987117f1b4Smrg   switch (pname) {
699b9abf16eSmaya      case GL_QUERY_COUNTER_BITS:
700af69d88dSmrg         switch (target) {
701af69d88dSmrg         case GL_SAMPLES_PASSED:
702af69d88dSmrg            *params = ctx->Const.QueryCounterBits.SamplesPassed;
703af69d88dSmrg            break;
704af69d88dSmrg         case GL_ANY_SAMPLES_PASSED:
70501e04c3fSmrg         case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
706af69d88dSmrg            /* The minimum value of this is 1 if it's nonzero, and the value
707af69d88dSmrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
708af69d88dSmrg             * bits.
709af69d88dSmrg             */
710af69d88dSmrg            *params = 1;
711af69d88dSmrg            break;
712af69d88dSmrg         case GL_TIME_ELAPSED:
713af69d88dSmrg            *params = ctx->Const.QueryCounterBits.TimeElapsed;
714af69d88dSmrg            break;
715af69d88dSmrg         case GL_TIMESTAMP:
716af69d88dSmrg            *params = ctx->Const.QueryCounterBits.Timestamp;
717af69d88dSmrg            break;
718af69d88dSmrg         case GL_PRIMITIVES_GENERATED:
719af69d88dSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
720af69d88dSmrg            break;
721af69d88dSmrg         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
722af69d88dSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
723af69d88dSmrg            break;
724b9abf16eSmaya         case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
725b9abf16eSmaya         case GL_TRANSFORM_FEEDBACK_OVERFLOW:
72601e04c3fSmrg            /* The minimum value of this is 1 if it's nonzero, and the value
72701e04c3fSmrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
72801e04c3fSmrg             * bits.
72901e04c3fSmrg             */
73001e04c3fSmrg            *params = 1;
73101e04c3fSmrg            break;
732b9abf16eSmaya         case GL_VERTICES_SUBMITTED:
73301e04c3fSmrg            *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
73401e04c3fSmrg            break;
735b9abf16eSmaya         case GL_PRIMITIVES_SUBMITTED:
73601e04c3fSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
73701e04c3fSmrg            break;
738b9abf16eSmaya         case GL_VERTEX_SHADER_INVOCATIONS:
73901e04c3fSmrg            *params = ctx->Const.QueryCounterBits.VsInvocations;
74001e04c3fSmrg            break;
741b9abf16eSmaya         case GL_TESS_CONTROL_SHADER_PATCHES:
74201e04c3fSmrg            *params = ctx->Const.QueryCounterBits.TessPatches;
74301e04c3fSmrg            break;
744b9abf16eSmaya         case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
74501e04c3fSmrg            *params = ctx->Const.QueryCounterBits.TessInvocations;
74601e04c3fSmrg            break;
74701e04c3fSmrg         case GL_GEOMETRY_SHADER_INVOCATIONS:
74801e04c3fSmrg            *params = ctx->Const.QueryCounterBits.GsInvocations;
74901e04c3fSmrg            break;
750b9abf16eSmaya         case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
75101e04c3fSmrg            *params = ctx->Const.QueryCounterBits.GsPrimitives;
75201e04c3fSmrg            break;
753b9abf16eSmaya         case GL_FRAGMENT_SHADER_INVOCATIONS:
75401e04c3fSmrg            *params = ctx->Const.QueryCounterBits.FsInvocations;
75501e04c3fSmrg            break;
756b9abf16eSmaya         case GL_COMPUTE_SHADER_INVOCATIONS:
75701e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ComputeInvocations;
75801e04c3fSmrg            break;
759b9abf16eSmaya         case GL_CLIPPING_INPUT_PRIMITIVES:
76001e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ClInPrimitives;
76101e04c3fSmrg            break;
762b9abf16eSmaya         case GL_CLIPPING_OUTPUT_PRIMITIVES:
76301e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
76401e04c3fSmrg            break;
765af69d88dSmrg         default:
766af69d88dSmrg            _mesa_problem(ctx,
767af69d88dSmrg                          "Unknown target in glGetQueryIndexediv(target = %s)",
76801e04c3fSmrg                          _mesa_enum_to_string(target));
769af69d88dSmrg            *params = 0;
770af69d88dSmrg            break;
771af69d88dSmrg         }
7727117f1b4Smrg         break;
773b9abf16eSmaya      case GL_CURRENT_QUERY:
774af69d88dSmrg         *params = (q && q->Target == target) ? q->Id : 0;
7757117f1b4Smrg         break;
7767117f1b4Smrg      default:
777af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
7787117f1b4Smrg         return;
7797117f1b4Smrg   }
7807117f1b4Smrg}
7817117f1b4Smrg
782af69d88dSmrgvoid GLAPIENTRY
783af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
784af69d88dSmrg{
785af69d88dSmrg   _mesa_GetQueryIndexediv(target, 0, pname, params);
786af69d88dSmrg}
7877117f1b4Smrg
78801e04c3fSmrgstatic void
78901e04c3fSmrgget_query_object(struct gl_context *ctx, const char *func,
79001e04c3fSmrg                 GLuint id, GLenum pname, GLenum ptype,
79101e04c3fSmrg                 struct gl_buffer_object *buf, intptr_t offset)
7927117f1b4Smrg{
7937117f1b4Smrg   struct gl_query_object *q = NULL;
79401e04c3fSmrg   uint64_t value;
7957117f1b4Smrg
7963464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
79701e04c3fSmrg      _mesa_debug(ctx, "%s(%u, %s)\n", func, id,
79801e04c3fSmrg                  _mesa_enum_to_string(pname));
7993464ebd5Sriastradh
8007117f1b4Smrg   if (id)
801cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
8027117f1b4Smrg
80301e04c3fSmrg   if (!q || q->Active || !q->EverBound) {
8047117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
80501e04c3fSmrg                  "%s(id=%d is invalid or active)", func, id);
80601e04c3fSmrg      return;
80701e04c3fSmrg   }
80801e04c3fSmrg
80901e04c3fSmrg   /* From GL_EXT_occlusion_query_boolean spec:
81001e04c3fSmrg    *
81101e04c3fSmrg    *    "Accepted by the <pname> parameter of GetQueryObjectivEXT and
81201e04c3fSmrg    *    GetQueryObjectuivEXT:
81301e04c3fSmrg    *
81401e04c3fSmrg    *    QUERY_RESULT_EXT                               0x8866
81501e04c3fSmrg    *    QUERY_RESULT_AVAILABLE_EXT                     0x8867"
81601e04c3fSmrg    *
81701e04c3fSmrg    * Same rule is present also in ES 3.2 spec.
81801e04c3fSmrg    */
81901e04c3fSmrg   if (_mesa_is_gles(ctx) &&
82001e04c3fSmrg       (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) {
82101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func,
82201e04c3fSmrg                  _mesa_enum_to_string(pname));
8237117f1b4Smrg      return;
8247117f1b4Smrg   }
8257117f1b4Smrg
8267ec681f3Smrg   if (buf) {
82701e04c3fSmrg      bool is_64bit = ptype == GL_INT64_ARB ||
82801e04c3fSmrg         ptype == GL_UNSIGNED_INT64_ARB;
829b9abf16eSmaya      if (!_mesa_has_ARB_query_buffer_object(ctx)) {
83001e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func);
83101e04c3fSmrg         return;
83201e04c3fSmrg      }
83301e04c3fSmrg      if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) {
83401e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func);
83501e04c3fSmrg         return;
83601e04c3fSmrg      }
83701e04c3fSmrg
83801e04c3fSmrg      if (offset < 0) {
83901e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func);
84001e04c3fSmrg         return;
84101e04c3fSmrg      }
84201e04c3fSmrg
84301e04c3fSmrg      switch (pname) {
84401e04c3fSmrg      case GL_QUERY_RESULT:
84501e04c3fSmrg      case GL_QUERY_RESULT_NO_WAIT:
84601e04c3fSmrg      case GL_QUERY_RESULT_AVAILABLE:
84701e04c3fSmrg      case GL_QUERY_TARGET:
84801e04c3fSmrg         ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype);
84901e04c3fSmrg         return;
85001e04c3fSmrg      }
85101e04c3fSmrg
85201e04c3fSmrg      /* fall through to get error below */
85301e04c3fSmrg   }
85401e04c3fSmrg
8557117f1b4Smrg   switch (pname) {
85601e04c3fSmrg   case GL_QUERY_RESULT:
85701e04c3fSmrg      if (!q->Ready)
85801e04c3fSmrg         ctx->Driver.WaitQuery(ctx, q);
85901e04c3fSmrg      value = q->Result;
86001e04c3fSmrg      break;
86101e04c3fSmrg   case GL_QUERY_RESULT_NO_WAIT:
862b9abf16eSmaya      if (!_mesa_has_ARB_query_buffer_object(ctx))
86301e04c3fSmrg         goto invalid_enum;
86401e04c3fSmrg      ctx->Driver.CheckQuery(ctx, q);
86501e04c3fSmrg      if (!q->Ready)
8667117f1b4Smrg         return;
86701e04c3fSmrg      value = q->Result;
86801e04c3fSmrg      break;
86901e04c3fSmrg   case GL_QUERY_RESULT_AVAILABLE:
87001e04c3fSmrg      if (!q->Ready)
87101e04c3fSmrg         ctx->Driver.CheckQuery(ctx, q);
87201e04c3fSmrg      value = q->Ready;
87301e04c3fSmrg      break;
87401e04c3fSmrg   case GL_QUERY_TARGET:
87501e04c3fSmrg      value = q->Target;
87601e04c3fSmrg      break;
87701e04c3fSmrg   default:
87801e04c3fSmrginvalid_enum:
87901e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)",
88001e04c3fSmrg                  func, _mesa_enum_to_string(pname));
88101e04c3fSmrg      return;
88201e04c3fSmrg   }
88301e04c3fSmrg
88401e04c3fSmrg   switch (ptype) {
88501e04c3fSmrg   case GL_INT: {
88601e04c3fSmrg      GLint *param = (GLint *)offset;
88701e04c3fSmrg      if (value > 0x7fffffff)
88801e04c3fSmrg         *param = 0x7fffffff;
88901e04c3fSmrg      else
89001e04c3fSmrg         *param = value;
89101e04c3fSmrg      break;
89201e04c3fSmrg   }
89301e04c3fSmrg   case GL_UNSIGNED_INT: {
89401e04c3fSmrg      GLuint *param = (GLuint *)offset;
89501e04c3fSmrg      if (value > 0xffffffff)
89601e04c3fSmrg         *param = 0xffffffff;
89701e04c3fSmrg      else
89801e04c3fSmrg         *param = value;
89901e04c3fSmrg      break;
90001e04c3fSmrg   }
90101e04c3fSmrg   case GL_INT64_ARB:
90201e04c3fSmrg   case GL_UNSIGNED_INT64_ARB: {
90301e04c3fSmrg      GLuint64EXT *param = (GLuint64EXT *)offset;
90401e04c3fSmrg      *param = value;
90501e04c3fSmrg      break;
9067117f1b4Smrg   }
90701e04c3fSmrg   default:
90801e04c3fSmrg      unreachable("unexpected ptype");
90901e04c3fSmrg   }
91001e04c3fSmrg}
91101e04c3fSmrg
91201e04c3fSmrgvoid GLAPIENTRY
91301e04c3fSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
91401e04c3fSmrg{
91501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
91601e04c3fSmrg
91701e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectiv",
91801e04c3fSmrg                    id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params);
9197117f1b4Smrg}
9207117f1b4Smrg
9217117f1b4Smrg
922af69d88dSmrgvoid GLAPIENTRY
923af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
9247117f1b4Smrg{
9257117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9267117f1b4Smrg
92701e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectuiv",
92801e04c3fSmrg                    id, pname, GL_UNSIGNED_INT,
92901e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
93001e04c3fSmrg}
9313464ebd5Sriastradh
9327117f1b4Smrg
93301e04c3fSmrg/**
93401e04c3fSmrg * New with GL_EXT_timer_query
93501e04c3fSmrg */
93601e04c3fSmrgvoid GLAPIENTRY
93701e04c3fSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
93801e04c3fSmrg{
93901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9407117f1b4Smrg
94101e04c3fSmrg   get_query_object(ctx, "glGetQueryObjecti64v",
94201e04c3fSmrg                    id, pname, GL_INT64_ARB,
94301e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
9447117f1b4Smrg}
9457117f1b4Smrg
9467117f1b4Smrg
9477117f1b4Smrg/**
9487117f1b4Smrg * New with GL_EXT_timer_query
9497117f1b4Smrg */
950af69d88dSmrgvoid GLAPIENTRY
95101e04c3fSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
9527117f1b4Smrg{
9537117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9547117f1b4Smrg
95501e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectui64v",
95601e04c3fSmrg                    id, pname, GL_UNSIGNED_INT64_ARB,
95701e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
95801e04c3fSmrg}
9593464ebd5Sriastradh
96001e04c3fSmrg/**
96101e04c3fSmrg * New with GL_ARB_query_buffer_object
96201e04c3fSmrg */
96301e04c3fSmrgvoid GLAPIENTRY
96401e04c3fSmrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
96501e04c3fSmrg                             GLintptr offset)
96601e04c3fSmrg{
96701e04c3fSmrg   struct gl_buffer_object *buf;
96801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9697117f1b4Smrg
97001e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv");
97101e04c3fSmrg   if (!buf)
9727117f1b4Smrg      return;
9737117f1b4Smrg
97401e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectiv",
97501e04c3fSmrg                    id, pname, GL_INT, buf, offset);
9767117f1b4Smrg}
9777117f1b4Smrg
9787117f1b4Smrg
979af69d88dSmrgvoid GLAPIENTRY
98001e04c3fSmrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
98101e04c3fSmrg                              GLintptr offset)
9827117f1b4Smrg{
98301e04c3fSmrg   struct gl_buffer_object *buf;
9847117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9857117f1b4Smrg
98601e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv");
98701e04c3fSmrg   if (!buf)
98801e04c3fSmrg      return;
9893464ebd5Sriastradh
99001e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectuiv",
99101e04c3fSmrg                    id, pname, GL_UNSIGNED_INT, buf, offset);
99201e04c3fSmrg}
9937117f1b4Smrg
99401e04c3fSmrg
99501e04c3fSmrgvoid GLAPIENTRY
99601e04c3fSmrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
99701e04c3fSmrg                               GLintptr offset)
99801e04c3fSmrg{
99901e04c3fSmrg   struct gl_buffer_object *buf;
100001e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
100101e04c3fSmrg
100201e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v");
100301e04c3fSmrg   if (!buf)
10047117f1b4Smrg      return;
10057117f1b4Smrg
100601e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjecti64v",
100701e04c3fSmrg                    id, pname, GL_INT64_ARB, buf, offset);
10087117f1b4Smrg}
10097117f1b4Smrg
101001e04c3fSmrg
101101e04c3fSmrgvoid GLAPIENTRY
101201e04c3fSmrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
101301e04c3fSmrg                                GLintptr offset)
101401e04c3fSmrg{
101501e04c3fSmrg   struct gl_buffer_object *buf;
101601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
101701e04c3fSmrg
101801e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v");
101901e04c3fSmrg   if (!buf)
102001e04c3fSmrg      return;
102101e04c3fSmrg
102201e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectui64v",
102301e04c3fSmrg                    id, pname, GL_UNSIGNED_INT64_ARB, buf, offset);
102401e04c3fSmrg}
102501e04c3fSmrg
102601e04c3fSmrg
10277117f1b4Smrg/**
10287117f1b4Smrg * Allocate/init the context state related to query objects.
10297117f1b4Smrg */
10307117f1b4Smrgvoid
10313464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx)
10327117f1b4Smrg{
10337117f1b4Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
10347117f1b4Smrg   ctx->Query.CurrentOcclusionObject = NULL;
1035af69d88dSmrg
1036af69d88dSmrg   ctx->Const.QueryCounterBits.SamplesPassed = 64;
1037af69d88dSmrg   ctx->Const.QueryCounterBits.TimeElapsed = 64;
1038af69d88dSmrg   ctx->Const.QueryCounterBits.Timestamp = 64;
1039af69d88dSmrg   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
1040af69d88dSmrg   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
104101e04c3fSmrg
104201e04c3fSmrg   ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
104301e04c3fSmrg   ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
104401e04c3fSmrg   ctx->Const.QueryCounterBits.VsInvocations = 64;
104501e04c3fSmrg   ctx->Const.QueryCounterBits.TessPatches = 64;
104601e04c3fSmrg   ctx->Const.QueryCounterBits.TessInvocations = 64;
104701e04c3fSmrg   ctx->Const.QueryCounterBits.GsInvocations = 64;
104801e04c3fSmrg   ctx->Const.QueryCounterBits.GsPrimitives = 64;
104901e04c3fSmrg   ctx->Const.QueryCounterBits.FsInvocations = 64;
105001e04c3fSmrg   ctx->Const.QueryCounterBits.ComputeInvocations = 64;
105101e04c3fSmrg   ctx->Const.QueryCounterBits.ClInPrimitives = 64;
105201e04c3fSmrg   ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
10537117f1b4Smrg}
10547117f1b4Smrg
10557117f1b4Smrg
10567117f1b4Smrg/**
10577117f1b4Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
10587117f1b4Smrg */
10597117f1b4Smrgstatic void
10607ec681f3Smrgdelete_queryobj_cb(void *data, void *userData)
10617117f1b4Smrg{
10627117f1b4Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
10633464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *)userData;
1064c1f859d4Smrg   ctx->Driver.DeleteQuery(ctx, q);
10657117f1b4Smrg}
10667117f1b4Smrg
10677117f1b4Smrg
10687117f1b4Smrg/**
10697117f1b4Smrg * Free the context state related to query objects.
10707117f1b4Smrg */
10717117f1b4Smrgvoid
10723464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx)
10737117f1b4Smrg{
1074c1f859d4Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
10757117f1b4Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
10767117f1b4Smrg}
1077