queryobj.c revision b9abf16e
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{
149b9abf16eSmaya   const int which = target - GL_VERTICES_SUBMITTED;
15001e04c3fSmrg   assert(which < MAX_PIPELINE_STATISTICS);
15101e04c3fSmrg
152b9abf16eSmaya   if (!_mesa_has_ARB_pipeline_statistics_query(ctx))
15301e04c3fSmrg      return NULL;
15401e04c3fSmrg
15501e04c3fSmrg   return &ctx->Query.pipeline_stats[which];
15601e04c3fSmrg}
1574a49301eSmrg
1583464ebd5Sriastradh/**
159af69d88dSmrg * Return pointer to the query object binding point for the given target and
160af69d88dSmrg * index.
1613464ebd5Sriastradh * \return NULL if invalid target, else the address of binding point
1623464ebd5Sriastradh */
1633464ebd5Sriastradhstatic struct gl_query_object **
164af69d88dSmrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
1653464ebd5Sriastradh{
1663464ebd5Sriastradh   switch (target) {
167b9abf16eSmaya   case GL_SAMPLES_PASSED:
168b9abf16eSmaya      if (_mesa_has_ARB_occlusion_query(ctx) ||
169b9abf16eSmaya          _mesa_has_ARB_occlusion_query2(ctx))
1703464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1713464ebd5Sriastradh      else
1723464ebd5Sriastradh         return NULL;
1733464ebd5Sriastradh   case GL_ANY_SAMPLES_PASSED:
174b9abf16eSmaya      if (_mesa_has_ARB_occlusion_query2(ctx) ||
175b9abf16eSmaya          _mesa_has_EXT_occlusion_query_boolean(ctx))
1763464ebd5Sriastradh         return &ctx->Query.CurrentOcclusionObject;
1773464ebd5Sriastradh      else
1783464ebd5Sriastradh         return NULL;
179af69d88dSmrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
180b9abf16eSmaya      if (_mesa_has_ARB_ES3_compatibility(ctx) ||
181b9abf16eSmaya          _mesa_has_EXT_occlusion_query_boolean(ctx))
182af69d88dSmrg         return &ctx->Query.CurrentOcclusionObject;
183af69d88dSmrg      else
184af69d88dSmrg         return NULL;
185b9abf16eSmaya   case GL_TIME_ELAPSED:
186b9abf16eSmaya      if (_mesa_has_EXT_timer_query(ctx) ||
187b9abf16eSmaya          _mesa_has_EXT_disjoint_timer_query(ctx))
1883464ebd5Sriastradh         return &ctx->Query.CurrentTimerObject;
1893464ebd5Sriastradh      else
1903464ebd5Sriastradh         return NULL;
1913464ebd5Sriastradh   case GL_PRIMITIVES_GENERATED:
192b9abf16eSmaya      if (_mesa_has_EXT_transform_feedback(ctx) ||
193b9abf16eSmaya          _mesa_has_EXT_tessellation_shader(ctx) ||
194b9abf16eSmaya          _mesa_has_OES_geometry_shader(ctx))
195af69d88dSmrg         return &ctx->Query.PrimitivesGenerated[index];
1963464ebd5Sriastradh      else
1973464ebd5Sriastradh         return NULL;
1983464ebd5Sriastradh   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
199b9abf16eSmaya      if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx))
200af69d88dSmrg         return &ctx->Query.PrimitivesWritten[index];
2013464ebd5Sriastradh      else
2023464ebd5Sriastradh         return NULL;
203b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
204b9abf16eSmaya      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
20501e04c3fSmrg         return &ctx->Query.TransformFeedbackOverflow[index];
20601e04c3fSmrg      else
20701e04c3fSmrg         return NULL;
208b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
209b9abf16eSmaya      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
21001e04c3fSmrg         return &ctx->Query.TransformFeedbackOverflowAny;
21101e04c3fSmrg      else
21201e04c3fSmrg         return NULL;
21301e04c3fSmrg
214b9abf16eSmaya   case GL_VERTICES_SUBMITTED:
215b9abf16eSmaya   case GL_PRIMITIVES_SUBMITTED:
216b9abf16eSmaya   case GL_VERTEX_SHADER_INVOCATIONS:
217b9abf16eSmaya   case GL_FRAGMENT_SHADER_INVOCATIONS:
218b9abf16eSmaya   case GL_CLIPPING_INPUT_PRIMITIVES:
219b9abf16eSmaya   case GL_CLIPPING_OUTPUT_PRIMITIVES:
22001e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
22101e04c3fSmrg
22201e04c3fSmrg   case GL_GEOMETRY_SHADER_INVOCATIONS:
22301e04c3fSmrg      /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
224b9abf16eSmaya      target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1;
22501e04c3fSmrg      /* fallthrough */
226b9abf16eSmaya   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
22701e04c3fSmrg      if (_mesa_has_geometry_shaders(ctx))
22801e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
22901e04c3fSmrg      else
23001e04c3fSmrg         return NULL;
23101e04c3fSmrg
232b9abf16eSmaya   case GL_TESS_CONTROL_SHADER_PATCHES:
233b9abf16eSmaya   case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
23401e04c3fSmrg      if (_mesa_has_tessellation(ctx))
23501e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
23601e04c3fSmrg      else
23701e04c3fSmrg         return NULL;
23801e04c3fSmrg
239b9abf16eSmaya   case GL_COMPUTE_SHADER_INVOCATIONS:
24001e04c3fSmrg      if (_mesa_has_compute_shaders(ctx))
24101e04c3fSmrg         return get_pipe_stats_binding_point(ctx, target);
24201e04c3fSmrg      else
24301e04c3fSmrg         return NULL;
24401e04c3fSmrg
2453464ebd5Sriastradh   default:
2463464ebd5Sriastradh      return NULL;
2473464ebd5Sriastradh   }
2483464ebd5Sriastradh}
2493464ebd5Sriastradh
25001e04c3fSmrg/**
25101e04c3fSmrg * Create $n query objects and store them in *ids. Make them of type $target
25201e04c3fSmrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
25301e04c3fSmrg */
25401e04c3fSmrgstatic void
25501e04c3fSmrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
25601e04c3fSmrg               bool dsa)
2577117f1b4Smrg{
25801e04c3fSmrg   const char *func = dsa ? "glGenQueries" : "glCreateQueries";
2597117f1b4Smrg   GLuint first;
2607117f1b4Smrg
2613464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
26201e04c3fSmrg      _mesa_debug(ctx, "%s(%d)\n", func, n);
2633464ebd5Sriastradh
2647117f1b4Smrg   if (n < 0) {
26501e04c3fSmrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
2667117f1b4Smrg      return;
2677117f1b4Smrg   }
2687117f1b4Smrg
2697117f1b4Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
2707117f1b4Smrg   if (first) {
2717117f1b4Smrg      GLsizei i;
2727117f1b4Smrg      for (i = 0; i < n; i++) {
2737117f1b4Smrg         struct gl_query_object *q
2747117f1b4Smrg            = ctx->Driver.NewQueryObject(ctx, first + i);
2757117f1b4Smrg         if (!q) {
27601e04c3fSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
2777117f1b4Smrg            return;
27801e04c3fSmrg         } else if (dsa) {
27901e04c3fSmrg            /* Do the equivalent of binding the buffer with a target */
28001e04c3fSmrg            q->Target = target;
28101e04c3fSmrg            q->EverBound = GL_TRUE;
2827117f1b4Smrg         }
2837117f1b4Smrg         ids[i] = first + i;
28401e04c3fSmrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, first + i, q);
2857117f1b4Smrg      }
2867117f1b4Smrg   }
2877117f1b4Smrg}
2887117f1b4Smrg
28901e04c3fSmrgvoid GLAPIENTRY
29001e04c3fSmrg_mesa_GenQueries(GLsizei n, GLuint *ids)
29101e04c3fSmrg{
29201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
29301e04c3fSmrg   create_queries(ctx, 0, n, ids, false);
29401e04c3fSmrg}
29501e04c3fSmrg
29601e04c3fSmrgvoid GLAPIENTRY
29701e04c3fSmrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
29801e04c3fSmrg{
29901e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
30001e04c3fSmrg
30101e04c3fSmrg   switch (target) {
30201e04c3fSmrg   case GL_SAMPLES_PASSED:
30301e04c3fSmrg   case GL_ANY_SAMPLES_PASSED:
30401e04c3fSmrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
30501e04c3fSmrg   case GL_TIME_ELAPSED:
30601e04c3fSmrg   case GL_TIMESTAMP:
30701e04c3fSmrg   case GL_PRIMITIVES_GENERATED:
30801e04c3fSmrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
309b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
310b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
31101e04c3fSmrg      break;
31201e04c3fSmrg   default:
31301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
31401e04c3fSmrg                  _mesa_enum_to_string(target));
31501e04c3fSmrg      return;
31601e04c3fSmrg   }
31701e04c3fSmrg
31801e04c3fSmrg   create_queries(ctx, target, n, ids, true);
31901e04c3fSmrg}
32001e04c3fSmrg
3217117f1b4Smrg
322af69d88dSmrgvoid GLAPIENTRY
323af69d88dSmrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids)
3247117f1b4Smrg{
3257117f1b4Smrg   GLint i;
3267117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3273464ebd5Sriastradh   FLUSH_VERTICES(ctx, 0);
3283464ebd5Sriastradh
3293464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
330af69d88dSmrg      _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
3317117f1b4Smrg
3327117f1b4Smrg   if (n < 0) {
3337117f1b4Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
3347117f1b4Smrg      return;
3357117f1b4Smrg   }
3367117f1b4Smrg
3377117f1b4Smrg   for (i = 0; i < n; i++) {
3387117f1b4Smrg      if (ids[i] > 0) {
339cdc920a0Smrg         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
3407117f1b4Smrg         if (q) {
341af69d88dSmrg            if (q->Active) {
342af69d88dSmrg               struct gl_query_object **bindpt;
343af69d88dSmrg               bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
344af69d88dSmrg               assert(bindpt); /* Should be non-null for active q. */
345af69d88dSmrg               if (bindpt) {
346af69d88dSmrg                  *bindpt = NULL;
347af69d88dSmrg               }
348af69d88dSmrg               q->Active = GL_FALSE;
349af69d88dSmrg               ctx->Driver.EndQuery(ctx, q);
350af69d88dSmrg            }
35101e04c3fSmrg            _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]);
352c1f859d4Smrg            ctx->Driver.DeleteQuery(ctx, q);
3537117f1b4Smrg         }
3547117f1b4Smrg      }
3557117f1b4Smrg   }
3567117f1b4Smrg}
3577117f1b4Smrg
3587117f1b4Smrg
359af69d88dSmrgGLboolean GLAPIENTRY
360af69d88dSmrg_mesa_IsQuery(GLuint id)
3617117f1b4Smrg{
362af69d88dSmrg   struct gl_query_object *q;
363af69d88dSmrg
3647117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
3657117f1b4Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
3667117f1b4Smrg
3673464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
3683464ebd5Sriastradh      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
3693464ebd5Sriastradh
370af69d88dSmrg   if (id == 0)
371af69d88dSmrg      return GL_FALSE;
372af69d88dSmrg
373af69d88dSmrg   q = _mesa_lookup_query_object(ctx, id);
374af69d88dSmrg   if (q == NULL)
3757117f1b4Smrg      return GL_FALSE;
376af69d88dSmrg
377af69d88dSmrg   return q->EverBound;
3787117f1b4Smrg}
3797117f1b4Smrg
380af69d88dSmrgstatic GLboolean
381af69d88dSmrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
382af69d88dSmrg{
383af69d88dSmrg   switch (target) {
384af69d88dSmrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
385af69d88dSmrg   case GL_PRIMITIVES_GENERATED:
386b9abf16eSmaya   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
387af69d88dSmrg      if (index >= ctx->Const.MaxVertexStreams) {
388af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
389af69d88dSmrg                     "glBeginQueryIndexed(index>=MaxVertexStreams)");
390af69d88dSmrg         return GL_FALSE;
391af69d88dSmrg      }
392af69d88dSmrg      break;
393af69d88dSmrg   default:
394af69d88dSmrg      if (index > 0) {
395af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
396af69d88dSmrg         return GL_FALSE;
397af69d88dSmrg      }
398af69d88dSmrg   }
399af69d88dSmrg   return GL_TRUE;
400af69d88dSmrg}
4017117f1b4Smrg
402af69d88dSmrgvoid GLAPIENTRY
403af69d88dSmrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
4047117f1b4Smrg{
4053464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
4067117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
4077117f1b4Smrg
4083464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
409af69d88dSmrg      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
41001e04c3fSmrg                  _mesa_enum_to_string(target), index, id);
4113464ebd5Sriastradh
412af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
413af69d88dSmrg      return;
414af69d88dSmrg
415af69d88dSmrg   FLUSH_VERTICES(ctx, 0);
4167117f1b4Smrg
417af69d88dSmrg   bindpt = get_query_binding_point(ctx, target, index);
4183464ebd5Sriastradh   if (!bindpt) {
419af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
420af69d88dSmrg      return;
421af69d88dSmrg   }
422af69d88dSmrg
423af69d88dSmrg   /* From the GL_ARB_occlusion_query spec:
424af69d88dSmrg    *
425af69d88dSmrg    *     "If BeginQueryARB is called while another query is already in
426af69d88dSmrg    *      progress with the same target, an INVALID_OPERATION error is
427af69d88dSmrg    *      generated."
428af69d88dSmrg    */
429af69d88dSmrg   if (*bindpt) {
430af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
431af69d88dSmrg                  "glBeginQuery{Indexed}(target=%s is active)",
43201e04c3fSmrg                  _mesa_enum_to_string(target));
4333464ebd5Sriastradh      return;
4347117f1b4Smrg   }
4357117f1b4Smrg
4367117f1b4Smrg   if (id == 0) {
437af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
4387117f1b4Smrg      return;
4397117f1b4Smrg   }
4407117f1b4Smrg
441cdc920a0Smrg   q = _mesa_lookup_query_object(ctx, id);
4427117f1b4Smrg   if (!q) {
443af69d88dSmrg      if (ctx->API != API_OPENGL_COMPAT) {
444af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
445af69d88dSmrg                     "glBeginQuery{Indexed}(non-gen name)");
4467117f1b4Smrg         return;
447af69d88dSmrg      } else {
448af69d88dSmrg         /* create new object */
449af69d88dSmrg         q = ctx->Driver.NewQueryObject(ctx, id);
450af69d88dSmrg         if (!q) {
451af69d88dSmrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
452af69d88dSmrg            return;
453af69d88dSmrg         }
45401e04c3fSmrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q);
4557117f1b4Smrg      }
4567117f1b4Smrg   }
4577117f1b4Smrg   else {
4587117f1b4Smrg      /* pre-existing object */
4597117f1b4Smrg      if (q->Active) {
4607117f1b4Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
461af69d88dSmrg                     "glBeginQuery{Indexed}(query already active)");
4627117f1b4Smrg         return;
4637117f1b4Smrg      }
46401e04c3fSmrg
46501e04c3fSmrg      /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
46601e04c3fSmrg       * spec states:
46701e04c3fSmrg       *
46801e04c3fSmrg       *     "BeginQuery generates an INVALID_OPERATION error if any of the
46901e04c3fSmrg       *      following conditions hold: [...] id is the name of an
47001e04c3fSmrg       *      existing query object whose type does not match target; [...]
47101e04c3fSmrg       *
47201e04c3fSmrg       * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
47301e04c3fSmrg       * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
47401e04c3fSmrg       */
47501e04c3fSmrg      if (q->EverBound && q->Target != target) {
47601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
47701e04c3fSmrg                     "glBeginQuery{Indexed}(target mismatch)");
47801e04c3fSmrg         return;
47901e04c3fSmrg      }
4807117f1b4Smrg   }
4817117f1b4Smrg
48201e04c3fSmrg   /* This possibly changes the target of a buffer allocated by
48301e04c3fSmrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
48401e04c3fSmrg    * the following:
48501e04c3fSmrg    *
48601e04c3fSmrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
48701e04c3fSmrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
48801e04c3fSmrg    * isn't a selector, so we decided not to change it."
48901e04c3fSmrg    *
49001e04c3fSmrg    * Updating the target of the query object should be acceptable, so let's
49101e04c3fSmrg    * do that.
49201e04c3fSmrg    */
49301e04c3fSmrg
494c1f859d4Smrg   q->Target = target;
4957117f1b4Smrg   q->Active = GL_TRUE;
4967117f1b4Smrg   q->Result = 0;
4977117f1b4Smrg   q->Ready = GL_FALSE;
498af69d88dSmrg   q->EverBound = GL_TRUE;
499af69d88dSmrg   q->Stream = index;
5007117f1b4Smrg
5013464ebd5Sriastradh   /* XXX should probably refcount query objects */
5023464ebd5Sriastradh   *bindpt = q;
5037117f1b4Smrg
504c1f859d4Smrg   ctx->Driver.BeginQuery(ctx, q);
5057117f1b4Smrg}
5067117f1b4Smrg
5077117f1b4Smrg
508af69d88dSmrgvoid GLAPIENTRY
509af69d88dSmrg_mesa_EndQueryIndexed(GLenum target, GLuint index)
5107117f1b4Smrg{
5113464ebd5Sriastradh   struct gl_query_object *q, **bindpt;
5127117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5137117f1b4Smrg
5143464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
515af69d88dSmrg      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
51601e04c3fSmrg                  _mesa_enum_to_string(target), index);
5173464ebd5Sriastradh
518af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
519af69d88dSmrg      return;
5207117f1b4Smrg
521af69d88dSmrg   FLUSH_VERTICES(ctx, 0);
522af69d88dSmrg
523af69d88dSmrg   bindpt = get_query_binding_point(ctx, target, index);
5243464ebd5Sriastradh   if (!bindpt) {
525af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
5263464ebd5Sriastradh      return;
5277117f1b4Smrg   }
5287117f1b4Smrg
5293464ebd5Sriastradh   /* XXX should probably refcount query objects */
5303464ebd5Sriastradh   q = *bindpt;
531af69d88dSmrg
532af69d88dSmrg   /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
533af69d88dSmrg   if (q && q->Target != target) {
534af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION,
535af69d88dSmrg                  "glEndQuery(target=%s with active query of target %s)",
53601e04c3fSmrg                  _mesa_enum_to_string(target),
53701e04c3fSmrg                  _mesa_enum_to_string(q->Target));
538af69d88dSmrg      return;
539af69d88dSmrg   }
540af69d88dSmrg
5413464ebd5Sriastradh   *bindpt = NULL;
5423464ebd5Sriastradh
5437117f1b4Smrg   if (!q || !q->Active) {
5447117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
545af69d88dSmrg                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
5467117f1b4Smrg      return;
5477117f1b4Smrg   }
5487117f1b4Smrg
5497117f1b4Smrg   q->Active = GL_FALSE;
550c1f859d4Smrg   ctx->Driver.EndQuery(ctx, q);
5517117f1b4Smrg}
5527117f1b4Smrg
553af69d88dSmrgvoid GLAPIENTRY
554af69d88dSmrg_mesa_BeginQuery(GLenum target, GLuint id)
555af69d88dSmrg{
556af69d88dSmrg   _mesa_BeginQueryIndexed(target, 0, id);
557af69d88dSmrg}
5587117f1b4Smrg
559af69d88dSmrgvoid GLAPIENTRY
560af69d88dSmrg_mesa_EndQuery(GLenum target)
5617117f1b4Smrg{
562af69d88dSmrg   _mesa_EndQueryIndexed(target, 0);
563af69d88dSmrg}
564af69d88dSmrg
565af69d88dSmrgvoid GLAPIENTRY
566af69d88dSmrg_mesa_QueryCounter(GLuint id, GLenum target)
567af69d88dSmrg{
568af69d88dSmrg   struct gl_query_object *q;
5697117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
5707117f1b4Smrg
5713464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
572af69d88dSmrg      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
57301e04c3fSmrg                  _mesa_enum_to_string(target));
574af69d88dSmrg
575af69d88dSmrg   /* error checking */
576af69d88dSmrg   if (target != GL_TIMESTAMP) {
577af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
578af69d88dSmrg      return;
579af69d88dSmrg   }
580af69d88dSmrg
581af69d88dSmrg   if (id == 0) {
582af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
583af69d88dSmrg      return;
584af69d88dSmrg   }
585af69d88dSmrg
586af69d88dSmrg   q = _mesa_lookup_query_object(ctx, id);
587af69d88dSmrg   if (!q) {
588af69d88dSmrg      /* XXX the Core profile should throw INVALID_OPERATION here */
589af69d88dSmrg
590af69d88dSmrg      /* create new object */
591af69d88dSmrg      q = ctx->Driver.NewQueryObject(ctx, id);
592af69d88dSmrg      if (!q) {
593af69d88dSmrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
594af69d88dSmrg         return;
595af69d88dSmrg      }
59601e04c3fSmrg      _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q);
597af69d88dSmrg   }
598af69d88dSmrg   else {
599af69d88dSmrg      if (q->Target && q->Target != GL_TIMESTAMP) {
600af69d88dSmrg         _mesa_error(ctx, GL_INVALID_OPERATION,
601af69d88dSmrg                     "glQueryCounter(id has an invalid target)");
602af69d88dSmrg         return;
603af69d88dSmrg      }
604af69d88dSmrg   }
605af69d88dSmrg
606af69d88dSmrg   if (q->Active) {
607af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
608af69d88dSmrg      return;
609af69d88dSmrg   }
610af69d88dSmrg
61101e04c3fSmrg   /* This possibly changes the target of a buffer allocated by
61201e04c3fSmrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
61301e04c3fSmrg    * the following:
61401e04c3fSmrg    *
61501e04c3fSmrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
61601e04c3fSmrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
61701e04c3fSmrg    * isn't a selector, so we decided not to change it."
61801e04c3fSmrg    *
61901e04c3fSmrg    * Updating the target of the query object should be acceptable, so let's
62001e04c3fSmrg    * do that.
62101e04c3fSmrg    */
62201e04c3fSmrg
623af69d88dSmrg   q->Target = target;
624af69d88dSmrg   q->Result = 0;
625af69d88dSmrg   q->Ready = GL_FALSE;
626af69d88dSmrg   q->EverBound = GL_TRUE;
627af69d88dSmrg
628af69d88dSmrg   if (ctx->Driver.QueryCounter) {
629af69d88dSmrg      ctx->Driver.QueryCounter(ctx, q);
630af69d88dSmrg   } else {
631af69d88dSmrg      /* QueryCounter is implemented using EndQuery without BeginQuery
632af69d88dSmrg       * in drivers. This is actually Direct3D and Gallium convention.
633af69d88dSmrg       */
634af69d88dSmrg      ctx->Driver.EndQuery(ctx, q);
635af69d88dSmrg   }
636af69d88dSmrg}
637af69d88dSmrg
638af69d88dSmrg
639af69d88dSmrgvoid GLAPIENTRY
640af69d88dSmrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
641af69d88dSmrg                        GLint *params)
642af69d88dSmrg{
643af69d88dSmrg   struct gl_query_object *q = NULL, **bindpt = NULL;
644af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
645af69d88dSmrg
646af69d88dSmrg   if (MESA_VERBOSE & VERBOSE_API)
647af69d88dSmrg      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
64801e04c3fSmrg                  _mesa_enum_to_string(target),
649af69d88dSmrg                  index,
65001e04c3fSmrg                  _mesa_enum_to_string(pname));
6513464ebd5Sriastradh
652af69d88dSmrg   if (!query_error_check_index(ctx, target, index))
6533464ebd5Sriastradh      return;
654af69d88dSmrg
65501e04c3fSmrg   /* From the GL_EXT_occlusion_query_boolean spec:
65601e04c3fSmrg    *
65701e04c3fSmrg    * "The error INVALID_ENUM is generated if GetQueryivEXT is called where
65801e04c3fSmrg    * <pname> is not CURRENT_QUERY_EXT."
65901e04c3fSmrg    *
66001e04c3fSmrg    * Same rule is present also in ES 3.2 spec.
66101e04c3fSmrg    */
66201e04c3fSmrg   if (_mesa_is_gles(ctx) && pname != GL_CURRENT_QUERY) {
66301e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)",
66401e04c3fSmrg                  _mesa_enum_to_string(pname));
66501e04c3fSmrg      return;
66601e04c3fSmrg   }
66701e04c3fSmrg
668af69d88dSmrg   if (target == GL_TIMESTAMP) {
669b9abf16eSmaya      if (!_mesa_has_ARB_timer_query(ctx) &&
670b9abf16eSmaya          !_mesa_has_EXT_disjoint_timer_query(ctx)) {
671af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
672af69d88dSmrg         return;
673af69d88dSmrg      }
6747117f1b4Smrg   }
675af69d88dSmrg   else {
676af69d88dSmrg      bindpt = get_query_binding_point(ctx, target, index);
677af69d88dSmrg      if (!bindpt) {
678af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
679af69d88dSmrg         return;
680af69d88dSmrg      }
6817117f1b4Smrg
682af69d88dSmrg      q = *bindpt;
683af69d88dSmrg   }
6843464ebd5Sriastradh
6857117f1b4Smrg   switch (pname) {
686b9abf16eSmaya      case GL_QUERY_COUNTER_BITS:
687af69d88dSmrg         switch (target) {
688af69d88dSmrg         case GL_SAMPLES_PASSED:
689af69d88dSmrg            *params = ctx->Const.QueryCounterBits.SamplesPassed;
690af69d88dSmrg            break;
691af69d88dSmrg         case GL_ANY_SAMPLES_PASSED:
69201e04c3fSmrg         case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
693af69d88dSmrg            /* The minimum value of this is 1 if it's nonzero, and the value
694af69d88dSmrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
695af69d88dSmrg             * bits.
696af69d88dSmrg             */
697af69d88dSmrg            *params = 1;
698af69d88dSmrg            break;
699af69d88dSmrg         case GL_TIME_ELAPSED:
700af69d88dSmrg            *params = ctx->Const.QueryCounterBits.TimeElapsed;
701af69d88dSmrg            break;
702af69d88dSmrg         case GL_TIMESTAMP:
703af69d88dSmrg            *params = ctx->Const.QueryCounterBits.Timestamp;
704af69d88dSmrg            break;
705af69d88dSmrg         case GL_PRIMITIVES_GENERATED:
706af69d88dSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
707af69d88dSmrg            break;
708af69d88dSmrg         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
709af69d88dSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
710af69d88dSmrg            break;
711b9abf16eSmaya         case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
712b9abf16eSmaya         case GL_TRANSFORM_FEEDBACK_OVERFLOW:
71301e04c3fSmrg            /* The minimum value of this is 1 if it's nonzero, and the value
71401e04c3fSmrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
71501e04c3fSmrg             * bits.
71601e04c3fSmrg             */
71701e04c3fSmrg            *params = 1;
71801e04c3fSmrg            break;
719b9abf16eSmaya         case GL_VERTICES_SUBMITTED:
72001e04c3fSmrg            *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
72101e04c3fSmrg            break;
722b9abf16eSmaya         case GL_PRIMITIVES_SUBMITTED:
72301e04c3fSmrg            *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
72401e04c3fSmrg            break;
725b9abf16eSmaya         case GL_VERTEX_SHADER_INVOCATIONS:
72601e04c3fSmrg            *params = ctx->Const.QueryCounterBits.VsInvocations;
72701e04c3fSmrg            break;
728b9abf16eSmaya         case GL_TESS_CONTROL_SHADER_PATCHES:
72901e04c3fSmrg            *params = ctx->Const.QueryCounterBits.TessPatches;
73001e04c3fSmrg            break;
731b9abf16eSmaya         case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
73201e04c3fSmrg            *params = ctx->Const.QueryCounterBits.TessInvocations;
73301e04c3fSmrg            break;
73401e04c3fSmrg         case GL_GEOMETRY_SHADER_INVOCATIONS:
73501e04c3fSmrg            *params = ctx->Const.QueryCounterBits.GsInvocations;
73601e04c3fSmrg            break;
737b9abf16eSmaya         case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
73801e04c3fSmrg            *params = ctx->Const.QueryCounterBits.GsPrimitives;
73901e04c3fSmrg            break;
740b9abf16eSmaya         case GL_FRAGMENT_SHADER_INVOCATIONS:
74101e04c3fSmrg            *params = ctx->Const.QueryCounterBits.FsInvocations;
74201e04c3fSmrg            break;
743b9abf16eSmaya         case GL_COMPUTE_SHADER_INVOCATIONS:
74401e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ComputeInvocations;
74501e04c3fSmrg            break;
746b9abf16eSmaya         case GL_CLIPPING_INPUT_PRIMITIVES:
74701e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ClInPrimitives;
74801e04c3fSmrg            break;
749b9abf16eSmaya         case GL_CLIPPING_OUTPUT_PRIMITIVES:
75001e04c3fSmrg            *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
75101e04c3fSmrg            break;
752af69d88dSmrg         default:
753af69d88dSmrg            _mesa_problem(ctx,
754af69d88dSmrg                          "Unknown target in glGetQueryIndexediv(target = %s)",
75501e04c3fSmrg                          _mesa_enum_to_string(target));
756af69d88dSmrg            *params = 0;
757af69d88dSmrg            break;
758af69d88dSmrg         }
7597117f1b4Smrg         break;
760b9abf16eSmaya      case GL_CURRENT_QUERY:
761af69d88dSmrg         *params = (q && q->Target == target) ? q->Id : 0;
7627117f1b4Smrg         break;
7637117f1b4Smrg      default:
764af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
7657117f1b4Smrg         return;
7667117f1b4Smrg   }
7677117f1b4Smrg}
7687117f1b4Smrg
769af69d88dSmrgvoid GLAPIENTRY
770af69d88dSmrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
771af69d88dSmrg{
772af69d88dSmrg   _mesa_GetQueryIndexediv(target, 0, pname, params);
773af69d88dSmrg}
7747117f1b4Smrg
77501e04c3fSmrgstatic void
77601e04c3fSmrgget_query_object(struct gl_context *ctx, const char *func,
77701e04c3fSmrg                 GLuint id, GLenum pname, GLenum ptype,
77801e04c3fSmrg                 struct gl_buffer_object *buf, intptr_t offset)
7797117f1b4Smrg{
7807117f1b4Smrg   struct gl_query_object *q = NULL;
78101e04c3fSmrg   uint64_t value;
7827117f1b4Smrg
7833464ebd5Sriastradh   if (MESA_VERBOSE & VERBOSE_API)
78401e04c3fSmrg      _mesa_debug(ctx, "%s(%u, %s)\n", func, id,
78501e04c3fSmrg                  _mesa_enum_to_string(pname));
7863464ebd5Sriastradh
7877117f1b4Smrg   if (id)
788cdc920a0Smrg      q = _mesa_lookup_query_object(ctx, id);
7897117f1b4Smrg
79001e04c3fSmrg   if (!q || q->Active || !q->EverBound) {
7917117f1b4Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
79201e04c3fSmrg                  "%s(id=%d is invalid or active)", func, id);
79301e04c3fSmrg      return;
79401e04c3fSmrg   }
79501e04c3fSmrg
79601e04c3fSmrg   /* From GL_EXT_occlusion_query_boolean spec:
79701e04c3fSmrg    *
79801e04c3fSmrg    *    "Accepted by the <pname> parameter of GetQueryObjectivEXT and
79901e04c3fSmrg    *    GetQueryObjectuivEXT:
80001e04c3fSmrg    *
80101e04c3fSmrg    *    QUERY_RESULT_EXT                               0x8866
80201e04c3fSmrg    *    QUERY_RESULT_AVAILABLE_EXT                     0x8867"
80301e04c3fSmrg    *
80401e04c3fSmrg    * Same rule is present also in ES 3.2 spec.
80501e04c3fSmrg    */
80601e04c3fSmrg   if (_mesa_is_gles(ctx) &&
80701e04c3fSmrg       (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) {
80801e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func,
80901e04c3fSmrg                  _mesa_enum_to_string(pname));
8107117f1b4Smrg      return;
8117117f1b4Smrg   }
8127117f1b4Smrg
81301e04c3fSmrg   if (buf && buf != ctx->Shared->NullBufferObj) {
81401e04c3fSmrg      bool is_64bit = ptype == GL_INT64_ARB ||
81501e04c3fSmrg         ptype == GL_UNSIGNED_INT64_ARB;
816b9abf16eSmaya      if (!_mesa_has_ARB_query_buffer_object(ctx)) {
81701e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func);
81801e04c3fSmrg         return;
81901e04c3fSmrg      }
82001e04c3fSmrg      if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) {
82101e04c3fSmrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func);
82201e04c3fSmrg         return;
82301e04c3fSmrg      }
82401e04c3fSmrg
82501e04c3fSmrg      if (offset < 0) {
82601e04c3fSmrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func);
82701e04c3fSmrg         return;
82801e04c3fSmrg      }
82901e04c3fSmrg
83001e04c3fSmrg      switch (pname) {
83101e04c3fSmrg      case GL_QUERY_RESULT:
83201e04c3fSmrg      case GL_QUERY_RESULT_NO_WAIT:
83301e04c3fSmrg      case GL_QUERY_RESULT_AVAILABLE:
83401e04c3fSmrg      case GL_QUERY_TARGET:
83501e04c3fSmrg         ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype);
83601e04c3fSmrg         return;
83701e04c3fSmrg      }
83801e04c3fSmrg
83901e04c3fSmrg      /* fall through to get error below */
84001e04c3fSmrg   }
84101e04c3fSmrg
8427117f1b4Smrg   switch (pname) {
84301e04c3fSmrg   case GL_QUERY_RESULT:
84401e04c3fSmrg      if (!q->Ready)
84501e04c3fSmrg         ctx->Driver.WaitQuery(ctx, q);
84601e04c3fSmrg      value = q->Result;
84701e04c3fSmrg      break;
84801e04c3fSmrg   case GL_QUERY_RESULT_NO_WAIT:
849b9abf16eSmaya      if (!_mesa_has_ARB_query_buffer_object(ctx))
85001e04c3fSmrg         goto invalid_enum;
85101e04c3fSmrg      ctx->Driver.CheckQuery(ctx, q);
85201e04c3fSmrg      if (!q->Ready)
8537117f1b4Smrg         return;
85401e04c3fSmrg      value = q->Result;
85501e04c3fSmrg      break;
85601e04c3fSmrg   case GL_QUERY_RESULT_AVAILABLE:
85701e04c3fSmrg      if (!q->Ready)
85801e04c3fSmrg         ctx->Driver.CheckQuery(ctx, q);
85901e04c3fSmrg      value = q->Ready;
86001e04c3fSmrg      break;
86101e04c3fSmrg   case GL_QUERY_TARGET:
86201e04c3fSmrg      value = q->Target;
86301e04c3fSmrg      break;
86401e04c3fSmrg   default:
86501e04c3fSmrginvalid_enum:
86601e04c3fSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)",
86701e04c3fSmrg                  func, _mesa_enum_to_string(pname));
86801e04c3fSmrg      return;
86901e04c3fSmrg   }
87001e04c3fSmrg
87101e04c3fSmrg   switch (ptype) {
87201e04c3fSmrg   case GL_INT: {
87301e04c3fSmrg      GLint *param = (GLint *)offset;
87401e04c3fSmrg      if (value > 0x7fffffff)
87501e04c3fSmrg         *param = 0x7fffffff;
87601e04c3fSmrg      else
87701e04c3fSmrg         *param = value;
87801e04c3fSmrg      break;
87901e04c3fSmrg   }
88001e04c3fSmrg   case GL_UNSIGNED_INT: {
88101e04c3fSmrg      GLuint *param = (GLuint *)offset;
88201e04c3fSmrg      if (value > 0xffffffff)
88301e04c3fSmrg         *param = 0xffffffff;
88401e04c3fSmrg      else
88501e04c3fSmrg         *param = value;
88601e04c3fSmrg      break;
88701e04c3fSmrg   }
88801e04c3fSmrg   case GL_INT64_ARB:
88901e04c3fSmrg   case GL_UNSIGNED_INT64_ARB: {
89001e04c3fSmrg      GLuint64EXT *param = (GLuint64EXT *)offset;
89101e04c3fSmrg      *param = value;
89201e04c3fSmrg      break;
8937117f1b4Smrg   }
89401e04c3fSmrg   default:
89501e04c3fSmrg      unreachable("unexpected ptype");
89601e04c3fSmrg   }
89701e04c3fSmrg}
89801e04c3fSmrg
89901e04c3fSmrgvoid GLAPIENTRY
90001e04c3fSmrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
90101e04c3fSmrg{
90201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
90301e04c3fSmrg
90401e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectiv",
90501e04c3fSmrg                    id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params);
9067117f1b4Smrg}
9077117f1b4Smrg
9087117f1b4Smrg
909af69d88dSmrgvoid GLAPIENTRY
910af69d88dSmrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
9117117f1b4Smrg{
9127117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9137117f1b4Smrg
91401e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectuiv",
91501e04c3fSmrg                    id, pname, GL_UNSIGNED_INT,
91601e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
91701e04c3fSmrg}
9183464ebd5Sriastradh
9197117f1b4Smrg
92001e04c3fSmrg/**
92101e04c3fSmrg * New with GL_EXT_timer_query
92201e04c3fSmrg */
92301e04c3fSmrgvoid GLAPIENTRY
92401e04c3fSmrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
92501e04c3fSmrg{
92601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9277117f1b4Smrg
92801e04c3fSmrg   get_query_object(ctx, "glGetQueryObjecti64v",
92901e04c3fSmrg                    id, pname, GL_INT64_ARB,
93001e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
9317117f1b4Smrg}
9327117f1b4Smrg
9337117f1b4Smrg
9347117f1b4Smrg/**
9357117f1b4Smrg * New with GL_EXT_timer_query
9367117f1b4Smrg */
937af69d88dSmrgvoid GLAPIENTRY
93801e04c3fSmrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
9397117f1b4Smrg{
9407117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9417117f1b4Smrg
94201e04c3fSmrg   get_query_object(ctx, "glGetQueryObjectui64v",
94301e04c3fSmrg                    id, pname, GL_UNSIGNED_INT64_ARB,
94401e04c3fSmrg                    ctx->QueryBuffer, (intptr_t)params);
94501e04c3fSmrg}
9463464ebd5Sriastradh
94701e04c3fSmrg/**
94801e04c3fSmrg * New with GL_ARB_query_buffer_object
94901e04c3fSmrg */
95001e04c3fSmrgvoid GLAPIENTRY
95101e04c3fSmrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
95201e04c3fSmrg                             GLintptr offset)
95301e04c3fSmrg{
95401e04c3fSmrg   struct gl_buffer_object *buf;
95501e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9567117f1b4Smrg
95701e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv");
95801e04c3fSmrg   if (!buf)
9597117f1b4Smrg      return;
9607117f1b4Smrg
96101e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectiv",
96201e04c3fSmrg                    id, pname, GL_INT, buf, offset);
9637117f1b4Smrg}
9647117f1b4Smrg
9657117f1b4Smrg
966af69d88dSmrgvoid GLAPIENTRY
96701e04c3fSmrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
96801e04c3fSmrg                              GLintptr offset)
9697117f1b4Smrg{
97001e04c3fSmrg   struct gl_buffer_object *buf;
9717117f1b4Smrg   GET_CURRENT_CONTEXT(ctx);
9727117f1b4Smrg
97301e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv");
97401e04c3fSmrg   if (!buf)
97501e04c3fSmrg      return;
9763464ebd5Sriastradh
97701e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectuiv",
97801e04c3fSmrg                    id, pname, GL_UNSIGNED_INT, buf, offset);
97901e04c3fSmrg}
9807117f1b4Smrg
98101e04c3fSmrg
98201e04c3fSmrgvoid GLAPIENTRY
98301e04c3fSmrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
98401e04c3fSmrg                               GLintptr offset)
98501e04c3fSmrg{
98601e04c3fSmrg   struct gl_buffer_object *buf;
98701e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
98801e04c3fSmrg
98901e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v");
99001e04c3fSmrg   if (!buf)
9917117f1b4Smrg      return;
9927117f1b4Smrg
99301e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjecti64v",
99401e04c3fSmrg                    id, pname, GL_INT64_ARB, buf, offset);
9957117f1b4Smrg}
9967117f1b4Smrg
99701e04c3fSmrg
99801e04c3fSmrgvoid GLAPIENTRY
99901e04c3fSmrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
100001e04c3fSmrg                                GLintptr offset)
100101e04c3fSmrg{
100201e04c3fSmrg   struct gl_buffer_object *buf;
100301e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
100401e04c3fSmrg
100501e04c3fSmrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v");
100601e04c3fSmrg   if (!buf)
100701e04c3fSmrg      return;
100801e04c3fSmrg
100901e04c3fSmrg   get_query_object(ctx, "glGetQueryBufferObjectui64v",
101001e04c3fSmrg                    id, pname, GL_UNSIGNED_INT64_ARB, buf, offset);
101101e04c3fSmrg}
101201e04c3fSmrg
101301e04c3fSmrg
10147117f1b4Smrg/**
10157117f1b4Smrg * Allocate/init the context state related to query objects.
10167117f1b4Smrg */
10177117f1b4Smrgvoid
10183464ebd5Sriastradh_mesa_init_queryobj(struct gl_context *ctx)
10197117f1b4Smrg{
10207117f1b4Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
10217117f1b4Smrg   ctx->Query.CurrentOcclusionObject = NULL;
1022af69d88dSmrg
1023af69d88dSmrg   ctx->Const.QueryCounterBits.SamplesPassed = 64;
1024af69d88dSmrg   ctx->Const.QueryCounterBits.TimeElapsed = 64;
1025af69d88dSmrg   ctx->Const.QueryCounterBits.Timestamp = 64;
1026af69d88dSmrg   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
1027af69d88dSmrg   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
102801e04c3fSmrg
102901e04c3fSmrg   ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
103001e04c3fSmrg   ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
103101e04c3fSmrg   ctx->Const.QueryCounterBits.VsInvocations = 64;
103201e04c3fSmrg   ctx->Const.QueryCounterBits.TessPatches = 64;
103301e04c3fSmrg   ctx->Const.QueryCounterBits.TessInvocations = 64;
103401e04c3fSmrg   ctx->Const.QueryCounterBits.GsInvocations = 64;
103501e04c3fSmrg   ctx->Const.QueryCounterBits.GsPrimitives = 64;
103601e04c3fSmrg   ctx->Const.QueryCounterBits.FsInvocations = 64;
103701e04c3fSmrg   ctx->Const.QueryCounterBits.ComputeInvocations = 64;
103801e04c3fSmrg   ctx->Const.QueryCounterBits.ClInPrimitives = 64;
103901e04c3fSmrg   ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
10407117f1b4Smrg}
10417117f1b4Smrg
10427117f1b4Smrg
10437117f1b4Smrg/**
10447117f1b4Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
10457117f1b4Smrg */
10467117f1b4Smrgstatic void
10477117f1b4Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData)
10487117f1b4Smrg{
10497117f1b4Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
10503464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *)userData;
1051c1f859d4Smrg   ctx->Driver.DeleteQuery(ctx, q);
10527117f1b4Smrg}
10537117f1b4Smrg
10547117f1b4Smrg
10557117f1b4Smrg/**
10567117f1b4Smrg * Free the context state related to query objects.
10577117f1b4Smrg */
10587117f1b4Smrgvoid
10593464ebd5Sriastradh_mesa_free_queryobj_data(struct gl_context *ctx)
10607117f1b4Smrg{
1061c1f859d4Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
10627117f1b4Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
10637117f1b4Smrg}
1064