1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26b8e80941Smrg#include "bufferobj.h"
27848b8605Smrg#include "glheader.h"
28848b8605Smrg#include "context.h"
29848b8605Smrg#include "enums.h"
30848b8605Smrg#include "hash.h"
31848b8605Smrg#include "imports.h"
32848b8605Smrg#include "queryobj.h"
33848b8605Smrg#include "mtypes.h"
34848b8605Smrg
35848b8605Smrg
36848b8605Smrg/**
37848b8605Smrg * Allocate a new query object.  This is a fallback routine called via
38848b8605Smrg * ctx->Driver.NewQueryObject().
39848b8605Smrg * \param ctx - rendering context
40848b8605Smrg * \param id - the new object's ID
41848b8605Smrg * \return pointer to new query_object object or NULL if out of memory.
42848b8605Smrg */
43848b8605Smrgstatic struct gl_query_object *
44848b8605Smrg_mesa_new_query_object(struct gl_context *ctx, GLuint id)
45848b8605Smrg{
46848b8605Smrg   struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
47848b8605Smrg   (void) ctx;
48848b8605Smrg   if (q) {
49848b8605Smrg      q->Id = id;
50848b8605Smrg      q->Result = 0;
51848b8605Smrg      q->Active = GL_FALSE;
52848b8605Smrg
53848b8605Smrg      /* This is to satisfy the language of the specification: "In the initial
54848b8605Smrg       * state of a query object, the result is available" (OpenGL 3.1 §
55848b8605Smrg       * 2.13).
56848b8605Smrg       */
57848b8605Smrg      q->Ready = GL_TRUE;
58848b8605Smrg
59848b8605Smrg      /* OpenGL 3.1 § 2.13 says about GenQueries, "These names are marked as
60848b8605Smrg       * used, but no object is associated with them until the first time they
61848b8605Smrg       * are used by BeginQuery." Since our implementation actually does
62848b8605Smrg       * allocate an object at this point, use a flag to indicate that this
63848b8605Smrg       * object has not yet been bound so should not be considered a query.
64848b8605Smrg       */
65848b8605Smrg      q->EverBound = GL_FALSE;
66848b8605Smrg   }
67848b8605Smrg   return q;
68848b8605Smrg}
69848b8605Smrg
70848b8605Smrg
71848b8605Smrg/**
72848b8605Smrg * Begin a query.  Software driver fallback.
73848b8605Smrg * Called via ctx->Driver.BeginQuery().
74848b8605Smrg */
75848b8605Smrgstatic void
76848b8605Smrg_mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
77848b8605Smrg{
78848b8605Smrg   ctx->NewState |= _NEW_DEPTH; /* for swrast */
79848b8605Smrg}
80848b8605Smrg
81848b8605Smrg
82848b8605Smrg/**
83848b8605Smrg * End a query.  Software driver fallback.
84848b8605Smrg * Called via ctx->Driver.EndQuery().
85848b8605Smrg */
86848b8605Smrgstatic void
87848b8605Smrg_mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
88848b8605Smrg{
89848b8605Smrg   ctx->NewState |= _NEW_DEPTH; /* for swrast */
90848b8605Smrg   q->Ready = GL_TRUE;
91848b8605Smrg}
92848b8605Smrg
93848b8605Smrg
94848b8605Smrg/**
95848b8605Smrg * Wait for query to complete.  Software driver fallback.
96848b8605Smrg * Called via ctx->Driver.WaitQuery().
97848b8605Smrg */
98848b8605Smrgstatic void
99848b8605Smrg_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
100848b8605Smrg{
101848b8605Smrg   /* For software drivers, _mesa_end_query() should have completed the query.
102848b8605Smrg    * For real hardware, implement a proper WaitQuery() driver function,
103848b8605Smrg    * which may require issuing a flush.
104848b8605Smrg    */
105848b8605Smrg   assert(q->Ready);
106848b8605Smrg}
107848b8605Smrg
108848b8605Smrg
109848b8605Smrg/**
110848b8605Smrg * Check if a query results are ready.  Software driver fallback.
111848b8605Smrg * Called via ctx->Driver.CheckQuery().
112848b8605Smrg */
113848b8605Smrgstatic void
114848b8605Smrg_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
115848b8605Smrg{
116848b8605Smrg   /* No-op for sw rendering.
117848b8605Smrg    * HW drivers may need to flush at this time.
118848b8605Smrg    */
119848b8605Smrg}
120848b8605Smrg
121848b8605Smrg
122848b8605Smrg/**
123848b8605Smrg * Delete a query object.  Called via ctx->Driver.DeleteQuery().
124848b8605Smrg * Not removed from hash table here.
125848b8605Smrg */
126848b8605Smrgstatic void
127848b8605Smrg_mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
128848b8605Smrg{
129848b8605Smrg   free(q->Label);
130848b8605Smrg   free(q);
131848b8605Smrg}
132848b8605Smrg
133848b8605Smrg
134848b8605Smrgvoid
135848b8605Smrg_mesa_init_query_object_functions(struct dd_function_table *driver)
136848b8605Smrg{
137848b8605Smrg   driver->NewQueryObject = _mesa_new_query_object;
138848b8605Smrg   driver->DeleteQuery = _mesa_delete_query;
139848b8605Smrg   driver->BeginQuery = _mesa_begin_query;
140848b8605Smrg   driver->EndQuery = _mesa_end_query;
141848b8605Smrg   driver->WaitQuery = _mesa_wait_query;
142848b8605Smrg   driver->CheckQuery = _mesa_check_query;
143848b8605Smrg}
144848b8605Smrg
145b8e80941Smrgstatic struct gl_query_object **
146b8e80941Smrgget_pipe_stats_binding_point(struct gl_context *ctx,
147b8e80941Smrg                             GLenum target)
148b8e80941Smrg{
149b8e80941Smrg   const int which = target - GL_VERTICES_SUBMITTED;
150b8e80941Smrg   assert(which < MAX_PIPELINE_STATISTICS);
151b8e80941Smrg
152b8e80941Smrg   if (!_mesa_has_ARB_pipeline_statistics_query(ctx))
153b8e80941Smrg      return NULL;
154b8e80941Smrg
155b8e80941Smrg   return &ctx->Query.pipeline_stats[which];
156b8e80941Smrg}
157848b8605Smrg
158848b8605Smrg/**
159848b8605Smrg * Return pointer to the query object binding point for the given target and
160848b8605Smrg * index.
161848b8605Smrg * \return NULL if invalid target, else the address of binding point
162848b8605Smrg */
163848b8605Smrgstatic struct gl_query_object **
164848b8605Smrgget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
165848b8605Smrg{
166848b8605Smrg   switch (target) {
167b8e80941Smrg   case GL_SAMPLES_PASSED:
168b8e80941Smrg      if (_mesa_has_ARB_occlusion_query(ctx) ||
169b8e80941Smrg          _mesa_has_ARB_occlusion_query2(ctx))
170848b8605Smrg         return &ctx->Query.CurrentOcclusionObject;
171848b8605Smrg      else
172848b8605Smrg         return NULL;
173848b8605Smrg   case GL_ANY_SAMPLES_PASSED:
174b8e80941Smrg      if (_mesa_has_ARB_occlusion_query2(ctx) ||
175b8e80941Smrg          _mesa_has_EXT_occlusion_query_boolean(ctx))
176848b8605Smrg         return &ctx->Query.CurrentOcclusionObject;
177848b8605Smrg      else
178848b8605Smrg         return NULL;
179848b8605Smrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
180b8e80941Smrg      if (_mesa_has_ARB_ES3_compatibility(ctx) ||
181b8e80941Smrg          _mesa_has_EXT_occlusion_query_boolean(ctx))
182848b8605Smrg         return &ctx->Query.CurrentOcclusionObject;
183848b8605Smrg      else
184848b8605Smrg         return NULL;
185b8e80941Smrg   case GL_TIME_ELAPSED:
186b8e80941Smrg      if (_mesa_has_EXT_timer_query(ctx) ||
187b8e80941Smrg          _mesa_has_EXT_disjoint_timer_query(ctx))
188848b8605Smrg         return &ctx->Query.CurrentTimerObject;
189848b8605Smrg      else
190848b8605Smrg         return NULL;
191848b8605Smrg   case GL_PRIMITIVES_GENERATED:
192b8e80941Smrg      if (_mesa_has_EXT_transform_feedback(ctx) ||
193b8e80941Smrg          _mesa_has_EXT_tessellation_shader(ctx) ||
194b8e80941Smrg          _mesa_has_OES_geometry_shader(ctx))
195848b8605Smrg         return &ctx->Query.PrimitivesGenerated[index];
196848b8605Smrg      else
197848b8605Smrg         return NULL;
198848b8605Smrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
199b8e80941Smrg      if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx))
200848b8605Smrg         return &ctx->Query.PrimitivesWritten[index];
201848b8605Smrg      else
202848b8605Smrg         return NULL;
203b8e80941Smrg   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
204b8e80941Smrg      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
205b8e80941Smrg         return &ctx->Query.TransformFeedbackOverflow[index];
206b8e80941Smrg      else
207b8e80941Smrg         return NULL;
208b8e80941Smrg   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
209b8e80941Smrg      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
210b8e80941Smrg         return &ctx->Query.TransformFeedbackOverflowAny;
211b8e80941Smrg      else
212b8e80941Smrg         return NULL;
213b8e80941Smrg
214b8e80941Smrg   case GL_VERTICES_SUBMITTED:
215b8e80941Smrg   case GL_PRIMITIVES_SUBMITTED:
216b8e80941Smrg   case GL_VERTEX_SHADER_INVOCATIONS:
217b8e80941Smrg   case GL_FRAGMENT_SHADER_INVOCATIONS:
218b8e80941Smrg   case GL_CLIPPING_INPUT_PRIMITIVES:
219b8e80941Smrg   case GL_CLIPPING_OUTPUT_PRIMITIVES:
220b8e80941Smrg         return get_pipe_stats_binding_point(ctx, target);
221b8e80941Smrg
222b8e80941Smrg   case GL_GEOMETRY_SHADER_INVOCATIONS:
223b8e80941Smrg      /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
224b8e80941Smrg      target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1;
225b8e80941Smrg      /* fallthrough */
226b8e80941Smrg   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
227b8e80941Smrg      if (_mesa_has_geometry_shaders(ctx))
228b8e80941Smrg         return get_pipe_stats_binding_point(ctx, target);
229b8e80941Smrg      else
230b8e80941Smrg         return NULL;
231b8e80941Smrg
232b8e80941Smrg   case GL_TESS_CONTROL_SHADER_PATCHES:
233b8e80941Smrg   case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
234b8e80941Smrg      if (_mesa_has_tessellation(ctx))
235b8e80941Smrg         return get_pipe_stats_binding_point(ctx, target);
236b8e80941Smrg      else
237b8e80941Smrg         return NULL;
238b8e80941Smrg
239b8e80941Smrg   case GL_COMPUTE_SHADER_INVOCATIONS:
240b8e80941Smrg      if (_mesa_has_compute_shaders(ctx))
241b8e80941Smrg         return get_pipe_stats_binding_point(ctx, target);
242b8e80941Smrg      else
243b8e80941Smrg         return NULL;
244b8e80941Smrg
245848b8605Smrg   default:
246848b8605Smrg      return NULL;
247848b8605Smrg   }
248848b8605Smrg}
249848b8605Smrg
250b8e80941Smrg/**
251b8e80941Smrg * Create $n query objects and store them in *ids. Make them of type $target
252b8e80941Smrg * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
253b8e80941Smrg */
254b8e80941Smrgstatic void
255b8e80941Smrgcreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
256b8e80941Smrg               bool dsa)
257848b8605Smrg{
258b8e80941Smrg   const char *func = dsa ? "glGenQueries" : "glCreateQueries";
259848b8605Smrg   GLuint first;
260848b8605Smrg
261848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
262b8e80941Smrg      _mesa_debug(ctx, "%s(%d)\n", func, n);
263848b8605Smrg
264848b8605Smrg   if (n < 0) {
265b8e80941Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
266848b8605Smrg      return;
267848b8605Smrg   }
268848b8605Smrg
269848b8605Smrg   first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
270848b8605Smrg   if (first) {
271848b8605Smrg      GLsizei i;
272848b8605Smrg      for (i = 0; i < n; i++) {
273848b8605Smrg         struct gl_query_object *q
274848b8605Smrg            = ctx->Driver.NewQueryObject(ctx, first + i);
275848b8605Smrg         if (!q) {
276b8e80941Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
277848b8605Smrg            return;
278b8e80941Smrg         } else if (dsa) {
279b8e80941Smrg            /* Do the equivalent of binding the buffer with a target */
280b8e80941Smrg            q->Target = target;
281b8e80941Smrg            q->EverBound = GL_TRUE;
282848b8605Smrg         }
283848b8605Smrg         ids[i] = first + i;
284b8e80941Smrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, first + i, q);
285848b8605Smrg      }
286848b8605Smrg   }
287848b8605Smrg}
288848b8605Smrg
289b8e80941Smrgvoid GLAPIENTRY
290b8e80941Smrg_mesa_GenQueries(GLsizei n, GLuint *ids)
291b8e80941Smrg{
292b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
293b8e80941Smrg   create_queries(ctx, 0, n, ids, false);
294b8e80941Smrg}
295b8e80941Smrg
296b8e80941Smrgvoid GLAPIENTRY
297b8e80941Smrg_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
298b8e80941Smrg{
299b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
300b8e80941Smrg
301b8e80941Smrg   switch (target) {
302b8e80941Smrg   case GL_SAMPLES_PASSED:
303b8e80941Smrg   case GL_ANY_SAMPLES_PASSED:
304b8e80941Smrg   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
305b8e80941Smrg   case GL_TIME_ELAPSED:
306b8e80941Smrg   case GL_TIMESTAMP:
307b8e80941Smrg   case GL_PRIMITIVES_GENERATED:
308b8e80941Smrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
309b8e80941Smrg   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
310b8e80941Smrg   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
311b8e80941Smrg      break;
312b8e80941Smrg   default:
313b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
314b8e80941Smrg                  _mesa_enum_to_string(target));
315b8e80941Smrg      return;
316b8e80941Smrg   }
317b8e80941Smrg
318b8e80941Smrg   create_queries(ctx, target, n, ids, true);
319b8e80941Smrg}
320b8e80941Smrg
321848b8605Smrg
322848b8605Smrgvoid GLAPIENTRY
323848b8605Smrg_mesa_DeleteQueries(GLsizei n, const GLuint *ids)
324848b8605Smrg{
325848b8605Smrg   GLint i;
326848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
327848b8605Smrg   FLUSH_VERTICES(ctx, 0);
328848b8605Smrg
329848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
330848b8605Smrg      _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
331848b8605Smrg
332848b8605Smrg   if (n < 0) {
333848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
334848b8605Smrg      return;
335848b8605Smrg   }
336848b8605Smrg
337848b8605Smrg   for (i = 0; i < n; i++) {
338848b8605Smrg      if (ids[i] > 0) {
339848b8605Smrg         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
340848b8605Smrg         if (q) {
341848b8605Smrg            if (q->Active) {
342848b8605Smrg               struct gl_query_object **bindpt;
343848b8605Smrg               bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
344848b8605Smrg               assert(bindpt); /* Should be non-null for active q. */
345848b8605Smrg               if (bindpt) {
346848b8605Smrg                  *bindpt = NULL;
347848b8605Smrg               }
348848b8605Smrg               q->Active = GL_FALSE;
349848b8605Smrg               ctx->Driver.EndQuery(ctx, q);
350848b8605Smrg            }
351b8e80941Smrg            _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]);
352848b8605Smrg            ctx->Driver.DeleteQuery(ctx, q);
353848b8605Smrg         }
354848b8605Smrg      }
355848b8605Smrg   }
356848b8605Smrg}
357848b8605Smrg
358848b8605Smrg
359848b8605SmrgGLboolean GLAPIENTRY
360848b8605Smrg_mesa_IsQuery(GLuint id)
361848b8605Smrg{
362848b8605Smrg   struct gl_query_object *q;
363848b8605Smrg
364848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
365848b8605Smrg   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
366848b8605Smrg
367848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
368848b8605Smrg      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
369848b8605Smrg
370848b8605Smrg   if (id == 0)
371848b8605Smrg      return GL_FALSE;
372848b8605Smrg
373848b8605Smrg   q = _mesa_lookup_query_object(ctx, id);
374848b8605Smrg   if (q == NULL)
375848b8605Smrg      return GL_FALSE;
376848b8605Smrg
377848b8605Smrg   return q->EverBound;
378848b8605Smrg}
379848b8605Smrg
380848b8605Smrgstatic GLboolean
381848b8605Smrgquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
382848b8605Smrg{
383848b8605Smrg   switch (target) {
384848b8605Smrg   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
385848b8605Smrg   case GL_PRIMITIVES_GENERATED:
386b8e80941Smrg   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
387848b8605Smrg      if (index >= ctx->Const.MaxVertexStreams) {
388848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE,
389848b8605Smrg                     "glBeginQueryIndexed(index>=MaxVertexStreams)");
390848b8605Smrg         return GL_FALSE;
391848b8605Smrg      }
392848b8605Smrg      break;
393848b8605Smrg   default:
394848b8605Smrg      if (index > 0) {
395848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
396848b8605Smrg         return GL_FALSE;
397848b8605Smrg      }
398848b8605Smrg   }
399848b8605Smrg   return GL_TRUE;
400848b8605Smrg}
401848b8605Smrg
402848b8605Smrgvoid GLAPIENTRY
403848b8605Smrg_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
404848b8605Smrg{
405848b8605Smrg   struct gl_query_object *q, **bindpt;
406848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
407848b8605Smrg
408848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
409848b8605Smrg      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
410b8e80941Smrg                  _mesa_enum_to_string(target), index, id);
411848b8605Smrg
412848b8605Smrg   if (!query_error_check_index(ctx, target, index))
413848b8605Smrg      return;
414848b8605Smrg
415848b8605Smrg   FLUSH_VERTICES(ctx, 0);
416848b8605Smrg
417848b8605Smrg   bindpt = get_query_binding_point(ctx, target, index);
418848b8605Smrg   if (!bindpt) {
419848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
420848b8605Smrg      return;
421848b8605Smrg   }
422848b8605Smrg
423848b8605Smrg   /* From the GL_ARB_occlusion_query spec:
424848b8605Smrg    *
425848b8605Smrg    *     "If BeginQueryARB is called while another query is already in
426848b8605Smrg    *      progress with the same target, an INVALID_OPERATION error is
427848b8605Smrg    *      generated."
428848b8605Smrg    */
429848b8605Smrg   if (*bindpt) {
430848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
431848b8605Smrg                  "glBeginQuery{Indexed}(target=%s is active)",
432b8e80941Smrg                  _mesa_enum_to_string(target));
433848b8605Smrg      return;
434848b8605Smrg   }
435848b8605Smrg
436848b8605Smrg   if (id == 0) {
437848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
438848b8605Smrg      return;
439848b8605Smrg   }
440848b8605Smrg
441848b8605Smrg   q = _mesa_lookup_query_object(ctx, id);
442848b8605Smrg   if (!q) {
443848b8605Smrg      if (ctx->API != API_OPENGL_COMPAT) {
444848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
445848b8605Smrg                     "glBeginQuery{Indexed}(non-gen name)");
446848b8605Smrg         return;
447848b8605Smrg      } else {
448848b8605Smrg         /* create new object */
449848b8605Smrg         q = ctx->Driver.NewQueryObject(ctx, id);
450848b8605Smrg         if (!q) {
451848b8605Smrg            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
452848b8605Smrg            return;
453848b8605Smrg         }
454b8e80941Smrg         _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q);
455848b8605Smrg      }
456848b8605Smrg   }
457848b8605Smrg   else {
458848b8605Smrg      /* pre-existing object */
459848b8605Smrg      if (q->Active) {
460848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
461848b8605Smrg                     "glBeginQuery{Indexed}(query already active)");
462848b8605Smrg         return;
463848b8605Smrg      }
464b8e80941Smrg
465b8e80941Smrg      /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
466b8e80941Smrg       * spec states:
467b8e80941Smrg       *
468b8e80941Smrg       *     "BeginQuery generates an INVALID_OPERATION error if any of the
469b8e80941Smrg       *      following conditions hold: [...] id is the name of an
470b8e80941Smrg       *      existing query object whose type does not match target; [...]
471b8e80941Smrg       *
472b8e80941Smrg       * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
473b8e80941Smrg       * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
474b8e80941Smrg       */
475b8e80941Smrg      if (q->EverBound && q->Target != target) {
476b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
477b8e80941Smrg                     "glBeginQuery{Indexed}(target mismatch)");
478b8e80941Smrg         return;
479b8e80941Smrg      }
480848b8605Smrg   }
481848b8605Smrg
482b8e80941Smrg   /* This possibly changes the target of a buffer allocated by
483b8e80941Smrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
484b8e80941Smrg    * the following:
485b8e80941Smrg    *
486b8e80941Smrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
487b8e80941Smrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
488b8e80941Smrg    * isn't a selector, so we decided not to change it."
489b8e80941Smrg    *
490b8e80941Smrg    * Updating the target of the query object should be acceptable, so let's
491b8e80941Smrg    * do that.
492b8e80941Smrg    */
493b8e80941Smrg
494848b8605Smrg   q->Target = target;
495848b8605Smrg   q->Active = GL_TRUE;
496848b8605Smrg   q->Result = 0;
497848b8605Smrg   q->Ready = GL_FALSE;
498848b8605Smrg   q->EverBound = GL_TRUE;
499848b8605Smrg   q->Stream = index;
500848b8605Smrg
501848b8605Smrg   /* XXX should probably refcount query objects */
502848b8605Smrg   *bindpt = q;
503848b8605Smrg
504848b8605Smrg   ctx->Driver.BeginQuery(ctx, q);
505848b8605Smrg}
506848b8605Smrg
507848b8605Smrg
508848b8605Smrgvoid GLAPIENTRY
509848b8605Smrg_mesa_EndQueryIndexed(GLenum target, GLuint index)
510848b8605Smrg{
511848b8605Smrg   struct gl_query_object *q, **bindpt;
512848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
513848b8605Smrg
514848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
515848b8605Smrg      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
516b8e80941Smrg                  _mesa_enum_to_string(target), index);
517848b8605Smrg
518848b8605Smrg   if (!query_error_check_index(ctx, target, index))
519848b8605Smrg      return;
520848b8605Smrg
521848b8605Smrg   FLUSH_VERTICES(ctx, 0);
522848b8605Smrg
523848b8605Smrg   bindpt = get_query_binding_point(ctx, target, index);
524848b8605Smrg   if (!bindpt) {
525848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
526848b8605Smrg      return;
527848b8605Smrg   }
528848b8605Smrg
529848b8605Smrg   /* XXX should probably refcount query objects */
530848b8605Smrg   q = *bindpt;
531848b8605Smrg
532848b8605Smrg   /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
533848b8605Smrg   if (q && q->Target != target) {
534848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
535848b8605Smrg                  "glEndQuery(target=%s with active query of target %s)",
536b8e80941Smrg                  _mesa_enum_to_string(target),
537b8e80941Smrg                  _mesa_enum_to_string(q->Target));
538848b8605Smrg      return;
539848b8605Smrg   }
540848b8605Smrg
541848b8605Smrg   *bindpt = NULL;
542848b8605Smrg
543848b8605Smrg   if (!q || !q->Active) {
544848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
545848b8605Smrg                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
546848b8605Smrg      return;
547848b8605Smrg   }
548848b8605Smrg
549848b8605Smrg   q->Active = GL_FALSE;
550848b8605Smrg   ctx->Driver.EndQuery(ctx, q);
551848b8605Smrg}
552848b8605Smrg
553848b8605Smrgvoid GLAPIENTRY
554848b8605Smrg_mesa_BeginQuery(GLenum target, GLuint id)
555848b8605Smrg{
556848b8605Smrg   _mesa_BeginQueryIndexed(target, 0, id);
557848b8605Smrg}
558848b8605Smrg
559848b8605Smrgvoid GLAPIENTRY
560848b8605Smrg_mesa_EndQuery(GLenum target)
561848b8605Smrg{
562848b8605Smrg   _mesa_EndQueryIndexed(target, 0);
563848b8605Smrg}
564848b8605Smrg
565848b8605Smrgvoid GLAPIENTRY
566848b8605Smrg_mesa_QueryCounter(GLuint id, GLenum target)
567848b8605Smrg{
568848b8605Smrg   struct gl_query_object *q;
569848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
570848b8605Smrg
571848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
572848b8605Smrg      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
573b8e80941Smrg                  _mesa_enum_to_string(target));
574848b8605Smrg
575848b8605Smrg   /* error checking */
576848b8605Smrg   if (target != GL_TIMESTAMP) {
577848b8605Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
578848b8605Smrg      return;
579848b8605Smrg   }
580848b8605Smrg
581848b8605Smrg   if (id == 0) {
582848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
583848b8605Smrg      return;
584848b8605Smrg   }
585848b8605Smrg
586848b8605Smrg   q = _mesa_lookup_query_object(ctx, id);
587848b8605Smrg   if (!q) {
588848b8605Smrg      /* XXX the Core profile should throw INVALID_OPERATION here */
589848b8605Smrg
590848b8605Smrg      /* create new object */
591848b8605Smrg      q = ctx->Driver.NewQueryObject(ctx, id);
592848b8605Smrg      if (!q) {
593848b8605Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
594848b8605Smrg         return;
595848b8605Smrg      }
596b8e80941Smrg      _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q);
597848b8605Smrg   }
598848b8605Smrg   else {
599848b8605Smrg      if (q->Target && q->Target != GL_TIMESTAMP) {
600848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
601848b8605Smrg                     "glQueryCounter(id has an invalid target)");
602848b8605Smrg         return;
603848b8605Smrg      }
604848b8605Smrg   }
605848b8605Smrg
606848b8605Smrg   if (q->Active) {
607848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
608848b8605Smrg      return;
609848b8605Smrg   }
610848b8605Smrg
611b8e80941Smrg   /* This possibly changes the target of a buffer allocated by
612b8e80941Smrg    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
613b8e80941Smrg    * the following:
614b8e80941Smrg    *
615b8e80941Smrg    * "CreateQueries adds a <target>, so strictly speaking the <target>
616b8e80941Smrg    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
617b8e80941Smrg    * isn't a selector, so we decided not to change it."
618b8e80941Smrg    *
619b8e80941Smrg    * Updating the target of the query object should be acceptable, so let's
620b8e80941Smrg    * do that.
621b8e80941Smrg    */
622b8e80941Smrg
623848b8605Smrg   q->Target = target;
624848b8605Smrg   q->Result = 0;
625848b8605Smrg   q->Ready = GL_FALSE;
626848b8605Smrg   q->EverBound = GL_TRUE;
627848b8605Smrg
628848b8605Smrg   if (ctx->Driver.QueryCounter) {
629848b8605Smrg      ctx->Driver.QueryCounter(ctx, q);
630848b8605Smrg   } else {
631848b8605Smrg      /* QueryCounter is implemented using EndQuery without BeginQuery
632848b8605Smrg       * in drivers. This is actually Direct3D and Gallium convention.
633848b8605Smrg       */
634848b8605Smrg      ctx->Driver.EndQuery(ctx, q);
635848b8605Smrg   }
636848b8605Smrg}
637848b8605Smrg
638848b8605Smrg
639848b8605Smrgvoid GLAPIENTRY
640848b8605Smrg_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
641848b8605Smrg                        GLint *params)
642848b8605Smrg{
643848b8605Smrg   struct gl_query_object *q = NULL, **bindpt = NULL;
644848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
645848b8605Smrg
646848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
647848b8605Smrg      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
648b8e80941Smrg                  _mesa_enum_to_string(target),
649848b8605Smrg                  index,
650b8e80941Smrg                  _mesa_enum_to_string(pname));
651848b8605Smrg
652848b8605Smrg   if (!query_error_check_index(ctx, target, index))
653848b8605Smrg      return;
654848b8605Smrg
655b8e80941Smrg   /* From the GL_EXT_occlusion_query_boolean spec:
656b8e80941Smrg    *
657b8e80941Smrg    * "The error INVALID_ENUM is generated if GetQueryivEXT is called where
658b8e80941Smrg    * <pname> is not CURRENT_QUERY_EXT."
659b8e80941Smrg    *
660b8e80941Smrg    * Same rule is present also in ES 3.2 spec.
661b8e80941Smrg    */
662b8e80941Smrg   if (_mesa_is_gles(ctx) && pname != GL_CURRENT_QUERY) {
663b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)",
664b8e80941Smrg                  _mesa_enum_to_string(pname));
665b8e80941Smrg      return;
666b8e80941Smrg   }
667b8e80941Smrg
668848b8605Smrg   if (target == GL_TIMESTAMP) {
669b8e80941Smrg      if (!_mesa_has_ARB_timer_query(ctx) &&
670b8e80941Smrg          !_mesa_has_EXT_disjoint_timer_query(ctx)) {
671848b8605Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
672848b8605Smrg         return;
673848b8605Smrg      }
674848b8605Smrg   }
675848b8605Smrg   else {
676848b8605Smrg      bindpt = get_query_binding_point(ctx, target, index);
677848b8605Smrg      if (!bindpt) {
678848b8605Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
679848b8605Smrg         return;
680848b8605Smrg      }
681848b8605Smrg
682848b8605Smrg      q = *bindpt;
683848b8605Smrg   }
684848b8605Smrg
685848b8605Smrg   switch (pname) {
686b8e80941Smrg      case GL_QUERY_COUNTER_BITS:
687848b8605Smrg         switch (target) {
688848b8605Smrg         case GL_SAMPLES_PASSED:
689848b8605Smrg            *params = ctx->Const.QueryCounterBits.SamplesPassed;
690848b8605Smrg            break;
691848b8605Smrg         case GL_ANY_SAMPLES_PASSED:
692b8e80941Smrg         case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
693848b8605Smrg            /* The minimum value of this is 1 if it's nonzero, and the value
694848b8605Smrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
695848b8605Smrg             * bits.
696848b8605Smrg             */
697848b8605Smrg            *params = 1;
698848b8605Smrg            break;
699848b8605Smrg         case GL_TIME_ELAPSED:
700848b8605Smrg            *params = ctx->Const.QueryCounterBits.TimeElapsed;
701848b8605Smrg            break;
702848b8605Smrg         case GL_TIMESTAMP:
703848b8605Smrg            *params = ctx->Const.QueryCounterBits.Timestamp;
704848b8605Smrg            break;
705848b8605Smrg         case GL_PRIMITIVES_GENERATED:
706848b8605Smrg            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
707848b8605Smrg            break;
708848b8605Smrg         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
709848b8605Smrg            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
710848b8605Smrg            break;
711b8e80941Smrg         case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
712b8e80941Smrg         case GL_TRANSFORM_FEEDBACK_OVERFLOW:
713b8e80941Smrg            /* The minimum value of this is 1 if it's nonzero, and the value
714b8e80941Smrg             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
715b8e80941Smrg             * bits.
716b8e80941Smrg             */
717b8e80941Smrg            *params = 1;
718b8e80941Smrg            break;
719b8e80941Smrg         case GL_VERTICES_SUBMITTED:
720b8e80941Smrg            *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
721b8e80941Smrg            break;
722b8e80941Smrg         case GL_PRIMITIVES_SUBMITTED:
723b8e80941Smrg            *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
724b8e80941Smrg            break;
725b8e80941Smrg         case GL_VERTEX_SHADER_INVOCATIONS:
726b8e80941Smrg            *params = ctx->Const.QueryCounterBits.VsInvocations;
727b8e80941Smrg            break;
728b8e80941Smrg         case GL_TESS_CONTROL_SHADER_PATCHES:
729b8e80941Smrg            *params = ctx->Const.QueryCounterBits.TessPatches;
730b8e80941Smrg            break;
731b8e80941Smrg         case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
732b8e80941Smrg            *params = ctx->Const.QueryCounterBits.TessInvocations;
733b8e80941Smrg            break;
734b8e80941Smrg         case GL_GEOMETRY_SHADER_INVOCATIONS:
735b8e80941Smrg            *params = ctx->Const.QueryCounterBits.GsInvocations;
736b8e80941Smrg            break;
737b8e80941Smrg         case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
738b8e80941Smrg            *params = ctx->Const.QueryCounterBits.GsPrimitives;
739b8e80941Smrg            break;
740b8e80941Smrg         case GL_FRAGMENT_SHADER_INVOCATIONS:
741b8e80941Smrg            *params = ctx->Const.QueryCounterBits.FsInvocations;
742b8e80941Smrg            break;
743b8e80941Smrg         case GL_COMPUTE_SHADER_INVOCATIONS:
744b8e80941Smrg            *params = ctx->Const.QueryCounterBits.ComputeInvocations;
745b8e80941Smrg            break;
746b8e80941Smrg         case GL_CLIPPING_INPUT_PRIMITIVES:
747b8e80941Smrg            *params = ctx->Const.QueryCounterBits.ClInPrimitives;
748b8e80941Smrg            break;
749b8e80941Smrg         case GL_CLIPPING_OUTPUT_PRIMITIVES:
750b8e80941Smrg            *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
751b8e80941Smrg            break;
752848b8605Smrg         default:
753848b8605Smrg            _mesa_problem(ctx,
754848b8605Smrg                          "Unknown target in glGetQueryIndexediv(target = %s)",
755b8e80941Smrg                          _mesa_enum_to_string(target));
756848b8605Smrg            *params = 0;
757848b8605Smrg            break;
758848b8605Smrg         }
759848b8605Smrg         break;
760b8e80941Smrg      case GL_CURRENT_QUERY:
761848b8605Smrg         *params = (q && q->Target == target) ? q->Id : 0;
762848b8605Smrg         break;
763848b8605Smrg      default:
764848b8605Smrg         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
765848b8605Smrg         return;
766848b8605Smrg   }
767848b8605Smrg}
768848b8605Smrg
769848b8605Smrgvoid GLAPIENTRY
770848b8605Smrg_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
771848b8605Smrg{
772848b8605Smrg   _mesa_GetQueryIndexediv(target, 0, pname, params);
773848b8605Smrg}
774848b8605Smrg
775b8e80941Smrgstatic void
776b8e80941Smrgget_query_object(struct gl_context *ctx, const char *func,
777b8e80941Smrg                 GLuint id, GLenum pname, GLenum ptype,
778b8e80941Smrg                 struct gl_buffer_object *buf, intptr_t offset)
779848b8605Smrg{
780848b8605Smrg   struct gl_query_object *q = NULL;
781b8e80941Smrg   uint64_t value;
782848b8605Smrg
783848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
784b8e80941Smrg      _mesa_debug(ctx, "%s(%u, %s)\n", func, id,
785b8e80941Smrg                  _mesa_enum_to_string(pname));
786848b8605Smrg
787848b8605Smrg   if (id)
788848b8605Smrg      q = _mesa_lookup_query_object(ctx, id);
789848b8605Smrg
790b8e80941Smrg   if (!q || q->Active || !q->EverBound) {
791848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
792b8e80941Smrg                  "%s(id=%d is invalid or active)", func, id);
793b8e80941Smrg      return;
794b8e80941Smrg   }
795b8e80941Smrg
796b8e80941Smrg   /* From GL_EXT_occlusion_query_boolean spec:
797b8e80941Smrg    *
798b8e80941Smrg    *    "Accepted by the <pname> parameter of GetQueryObjectivEXT and
799b8e80941Smrg    *    GetQueryObjectuivEXT:
800b8e80941Smrg    *
801b8e80941Smrg    *    QUERY_RESULT_EXT                               0x8866
802b8e80941Smrg    *    QUERY_RESULT_AVAILABLE_EXT                     0x8867"
803b8e80941Smrg    *
804b8e80941Smrg    * Same rule is present also in ES 3.2 spec.
805b8e80941Smrg    */
806b8e80941Smrg   if (_mesa_is_gles(ctx) &&
807b8e80941Smrg       (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) {
808b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func,
809b8e80941Smrg                  _mesa_enum_to_string(pname));
810848b8605Smrg      return;
811848b8605Smrg   }
812848b8605Smrg
813b8e80941Smrg   if (buf && buf != ctx->Shared->NullBufferObj) {
814b8e80941Smrg      bool is_64bit = ptype == GL_INT64_ARB ||
815b8e80941Smrg         ptype == GL_UNSIGNED_INT64_ARB;
816b8e80941Smrg      if (!_mesa_has_ARB_query_buffer_object(ctx)) {
817b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func);
818b8e80941Smrg         return;
819b8e80941Smrg      }
820b8e80941Smrg      if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) {
821b8e80941Smrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func);
822b8e80941Smrg         return;
823b8e80941Smrg      }
824b8e80941Smrg
825b8e80941Smrg      if (offset < 0) {
826b8e80941Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func);
827b8e80941Smrg         return;
828b8e80941Smrg      }
829b8e80941Smrg
830b8e80941Smrg      switch (pname) {
831b8e80941Smrg      case GL_QUERY_RESULT:
832b8e80941Smrg      case GL_QUERY_RESULT_NO_WAIT:
833b8e80941Smrg      case GL_QUERY_RESULT_AVAILABLE:
834b8e80941Smrg      case GL_QUERY_TARGET:
835b8e80941Smrg         ctx->Driver.StoreQueryResult(ctx, q, buf, offset, pname, ptype);
836b8e80941Smrg         return;
837b8e80941Smrg      }
838b8e80941Smrg
839b8e80941Smrg      /* fall through to get error below */
840b8e80941Smrg   }
841b8e80941Smrg
842848b8605Smrg   switch (pname) {
843b8e80941Smrg   case GL_QUERY_RESULT:
844b8e80941Smrg      if (!q->Ready)
845b8e80941Smrg         ctx->Driver.WaitQuery(ctx, q);
846b8e80941Smrg      value = q->Result;
847b8e80941Smrg      break;
848b8e80941Smrg   case GL_QUERY_RESULT_NO_WAIT:
849b8e80941Smrg      if (!_mesa_has_ARB_query_buffer_object(ctx))
850b8e80941Smrg         goto invalid_enum;
851b8e80941Smrg      ctx->Driver.CheckQuery(ctx, q);
852b8e80941Smrg      if (!q->Ready)
853848b8605Smrg         return;
854b8e80941Smrg      value = q->Result;
855b8e80941Smrg      break;
856b8e80941Smrg   case GL_QUERY_RESULT_AVAILABLE:
857b8e80941Smrg      if (!q->Ready)
858b8e80941Smrg         ctx->Driver.CheckQuery(ctx, q);
859b8e80941Smrg      value = q->Ready;
860b8e80941Smrg      break;
861b8e80941Smrg   case GL_QUERY_TARGET:
862b8e80941Smrg      value = q->Target;
863b8e80941Smrg      break;
864b8e80941Smrg   default:
865b8e80941Smrginvalid_enum:
866b8e80941Smrg      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)",
867b8e80941Smrg                  func, _mesa_enum_to_string(pname));
868b8e80941Smrg      return;
869848b8605Smrg   }
870b8e80941Smrg
871b8e80941Smrg   switch (ptype) {
872b8e80941Smrg   case GL_INT: {
873b8e80941Smrg      GLint *param = (GLint *)offset;
874b8e80941Smrg      if (value > 0x7fffffff)
875b8e80941Smrg         *param = 0x7fffffff;
876b8e80941Smrg      else
877b8e80941Smrg         *param = value;
878b8e80941Smrg      break;
879b8e80941Smrg   }
880b8e80941Smrg   case GL_UNSIGNED_INT: {
881b8e80941Smrg      GLuint *param = (GLuint *)offset;
882b8e80941Smrg      if (value > 0xffffffff)
883b8e80941Smrg         *param = 0xffffffff;
884b8e80941Smrg      else
885b8e80941Smrg         *param = value;
886b8e80941Smrg      break;
887b8e80941Smrg   }
888b8e80941Smrg   case GL_INT64_ARB:
889b8e80941Smrg   case GL_UNSIGNED_INT64_ARB: {
890b8e80941Smrg      GLuint64EXT *param = (GLuint64EXT *)offset;
891b8e80941Smrg      *param = value;
892b8e80941Smrg      break;
893b8e80941Smrg   }
894b8e80941Smrg   default:
895b8e80941Smrg      unreachable("unexpected ptype");
896b8e80941Smrg   }
897b8e80941Smrg}
898b8e80941Smrg
899b8e80941Smrgvoid GLAPIENTRY
900b8e80941Smrg_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
901b8e80941Smrg{
902b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
903b8e80941Smrg
904b8e80941Smrg   get_query_object(ctx, "glGetQueryObjectiv",
905b8e80941Smrg                    id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params);
906848b8605Smrg}
907848b8605Smrg
908848b8605Smrg
909848b8605Smrgvoid GLAPIENTRY
910848b8605Smrg_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
911848b8605Smrg{
912848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
913848b8605Smrg
914b8e80941Smrg   get_query_object(ctx, "glGetQueryObjectuiv",
915b8e80941Smrg                    id, pname, GL_UNSIGNED_INT,
916b8e80941Smrg                    ctx->QueryBuffer, (intptr_t)params);
917b8e80941Smrg}
918848b8605Smrg
919848b8605Smrg
920b8e80941Smrg/**
921b8e80941Smrg * New with GL_EXT_timer_query
922b8e80941Smrg */
923b8e80941Smrgvoid GLAPIENTRY
924b8e80941Smrg_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
925b8e80941Smrg{
926b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
927848b8605Smrg
928b8e80941Smrg   get_query_object(ctx, "glGetQueryObjecti64v",
929b8e80941Smrg                    id, pname, GL_INT64_ARB,
930b8e80941Smrg                    ctx->QueryBuffer, (intptr_t)params);
931848b8605Smrg}
932848b8605Smrg
933848b8605Smrg
934848b8605Smrg/**
935848b8605Smrg * New with GL_EXT_timer_query
936848b8605Smrg */
937848b8605Smrgvoid GLAPIENTRY
938b8e80941Smrg_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
939848b8605Smrg{
940848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
941848b8605Smrg
942b8e80941Smrg   get_query_object(ctx, "glGetQueryObjectui64v",
943b8e80941Smrg                    id, pname, GL_UNSIGNED_INT64_ARB,
944b8e80941Smrg                    ctx->QueryBuffer, (intptr_t)params);
945b8e80941Smrg}
946848b8605Smrg
947b8e80941Smrg/**
948b8e80941Smrg * New with GL_ARB_query_buffer_object
949b8e80941Smrg */
950b8e80941Smrgvoid GLAPIENTRY
951b8e80941Smrg_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
952b8e80941Smrg                             GLintptr offset)
953b8e80941Smrg{
954b8e80941Smrg   struct gl_buffer_object *buf;
955b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
956848b8605Smrg
957b8e80941Smrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv");
958b8e80941Smrg   if (!buf)
959848b8605Smrg      return;
960848b8605Smrg
961b8e80941Smrg   get_query_object(ctx, "glGetQueryBufferObjectiv",
962b8e80941Smrg                    id, pname, GL_INT, buf, offset);
963848b8605Smrg}
964848b8605Smrg
965848b8605Smrg
966848b8605Smrgvoid GLAPIENTRY
967b8e80941Smrg_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
968b8e80941Smrg                              GLintptr offset)
969848b8605Smrg{
970b8e80941Smrg   struct gl_buffer_object *buf;
971848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
972848b8605Smrg
973b8e80941Smrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv");
974b8e80941Smrg   if (!buf)
975b8e80941Smrg      return;
976848b8605Smrg
977b8e80941Smrg   get_query_object(ctx, "glGetQueryBufferObjectuiv",
978b8e80941Smrg                    id, pname, GL_UNSIGNED_INT, buf, offset);
979b8e80941Smrg}
980848b8605Smrg
981b8e80941Smrg
982b8e80941Smrgvoid GLAPIENTRY
983b8e80941Smrg_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
984b8e80941Smrg                               GLintptr offset)
985b8e80941Smrg{
986b8e80941Smrg   struct gl_buffer_object *buf;
987b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
988b8e80941Smrg
989b8e80941Smrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v");
990b8e80941Smrg   if (!buf)
991848b8605Smrg      return;
992848b8605Smrg
993b8e80941Smrg   get_query_object(ctx, "glGetQueryBufferObjecti64v",
994b8e80941Smrg                    id, pname, GL_INT64_ARB, buf, offset);
995848b8605Smrg}
996848b8605Smrg
997b8e80941Smrg
998b8e80941Smrgvoid GLAPIENTRY
999b8e80941Smrg_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
1000b8e80941Smrg                                GLintptr offset)
1001b8e80941Smrg{
1002b8e80941Smrg   struct gl_buffer_object *buf;
1003b8e80941Smrg   GET_CURRENT_CONTEXT(ctx);
1004b8e80941Smrg
1005b8e80941Smrg   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v");
1006b8e80941Smrg   if (!buf)
1007b8e80941Smrg      return;
1008b8e80941Smrg
1009b8e80941Smrg   get_query_object(ctx, "glGetQueryBufferObjectui64v",
1010b8e80941Smrg                    id, pname, GL_UNSIGNED_INT64_ARB, buf, offset);
1011b8e80941Smrg}
1012b8e80941Smrg
1013b8e80941Smrg
1014848b8605Smrg/**
1015848b8605Smrg * Allocate/init the context state related to query objects.
1016848b8605Smrg */
1017848b8605Smrgvoid
1018848b8605Smrg_mesa_init_queryobj(struct gl_context *ctx)
1019848b8605Smrg{
1020848b8605Smrg   ctx->Query.QueryObjects = _mesa_NewHashTable();
1021848b8605Smrg   ctx->Query.CurrentOcclusionObject = NULL;
1022848b8605Smrg
1023848b8605Smrg   ctx->Const.QueryCounterBits.SamplesPassed = 64;
1024848b8605Smrg   ctx->Const.QueryCounterBits.TimeElapsed = 64;
1025848b8605Smrg   ctx->Const.QueryCounterBits.Timestamp = 64;
1026848b8605Smrg   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
1027848b8605Smrg   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
1028b8e80941Smrg
1029b8e80941Smrg   ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
1030b8e80941Smrg   ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
1031b8e80941Smrg   ctx->Const.QueryCounterBits.VsInvocations = 64;
1032b8e80941Smrg   ctx->Const.QueryCounterBits.TessPatches = 64;
1033b8e80941Smrg   ctx->Const.QueryCounterBits.TessInvocations = 64;
1034b8e80941Smrg   ctx->Const.QueryCounterBits.GsInvocations = 64;
1035b8e80941Smrg   ctx->Const.QueryCounterBits.GsPrimitives = 64;
1036b8e80941Smrg   ctx->Const.QueryCounterBits.FsInvocations = 64;
1037b8e80941Smrg   ctx->Const.QueryCounterBits.ComputeInvocations = 64;
1038b8e80941Smrg   ctx->Const.QueryCounterBits.ClInPrimitives = 64;
1039b8e80941Smrg   ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
1040848b8605Smrg}
1041848b8605Smrg
1042848b8605Smrg
1043848b8605Smrg/**
1044848b8605Smrg * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
1045848b8605Smrg */
1046848b8605Smrgstatic void
1047848b8605Smrgdelete_queryobj_cb(GLuint id, void *data, void *userData)
1048848b8605Smrg{
1049848b8605Smrg   struct gl_query_object *q= (struct gl_query_object *) data;
1050848b8605Smrg   struct gl_context *ctx = (struct gl_context *)userData;
1051848b8605Smrg   ctx->Driver.DeleteQuery(ctx, q);
1052848b8605Smrg}
1053848b8605Smrg
1054848b8605Smrg
1055848b8605Smrg/**
1056848b8605Smrg * Free the context state related to query objects.
1057848b8605Smrg */
1058848b8605Smrgvoid
1059848b8605Smrg_mesa_free_queryobj_data(struct gl_context *ctx)
1060848b8605Smrg{
1061848b8605Smrg   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
1062848b8605Smrg   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
1063848b8605Smrg}
1064