xref: /third_party/mesa3d/src/mesa/main/queryobj.c (revision bf215546)
1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "bufferobj.h"
27bf215546Sopenharmony_ci#include "glheader.h"
28bf215546Sopenharmony_ci#include "context.h"
29bf215546Sopenharmony_ci#include "enums.h"
30bf215546Sopenharmony_ci#include "hash.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "queryobj.h"
33bf215546Sopenharmony_ci#include "mtypes.h"
34bf215546Sopenharmony_ci#include "pipe/p_context.h"
35bf215546Sopenharmony_ci#include "pipe/p_screen.h"
36bf215546Sopenharmony_ci#include "util/u_memory.h"
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include "api_exec_decl.h"
39bf215546Sopenharmony_ci#include "pipe/p_context.h"
40bf215546Sopenharmony_ci#include "pipe/p_screen.h"
41bf215546Sopenharmony_ci#include "state_tracker/st_context.h"
42bf215546Sopenharmony_ci#include "state_tracker/st_cb_bitmap.h"
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_cistatic struct gl_query_object *
46bf215546Sopenharmony_cinew_query_object(struct gl_context *ctx, GLuint id)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci   struct gl_query_object *q = CALLOC_STRUCT(gl_query_object);
49bf215546Sopenharmony_ci   if (q) {
50bf215546Sopenharmony_ci      q->Id = id;
51bf215546Sopenharmony_ci      q->Ready = GL_TRUE;
52bf215546Sopenharmony_ci      q->pq = NULL;
53bf215546Sopenharmony_ci      q->type = PIPE_QUERY_TYPES; /* an invalid value */
54bf215546Sopenharmony_ci      return q;
55bf215546Sopenharmony_ci   }
56bf215546Sopenharmony_ci   return NULL;
57bf215546Sopenharmony_ci}
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic void
61bf215546Sopenharmony_cifree_queries(struct pipe_context *pipe, struct gl_query_object *q)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   if (q->pq) {
64bf215546Sopenharmony_ci      pipe->destroy_query(pipe, q->pq);
65bf215546Sopenharmony_ci      q->pq = NULL;
66bf215546Sopenharmony_ci   }
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   if (q->pq_begin) {
69bf215546Sopenharmony_ci      pipe->destroy_query(pipe, q->pq_begin);
70bf215546Sopenharmony_ci      q->pq_begin = NULL;
71bf215546Sopenharmony_ci   }
72bf215546Sopenharmony_ci}
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_cistatic void
76bf215546Sopenharmony_cidelete_query(struct gl_context *ctx, struct gl_query_object *q)
77bf215546Sopenharmony_ci{
78bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   free_queries(pipe, q);
81bf215546Sopenharmony_ci   free(q->Label);
82bf215546Sopenharmony_ci   FREE(q);
83bf215546Sopenharmony_ci}
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_cistatic int
86bf215546Sopenharmony_citarget_to_index(const struct gl_query_object *q)
87bf215546Sopenharmony_ci{
88bf215546Sopenharmony_ci   if (q->Target == GL_PRIMITIVES_GENERATED ||
89bf215546Sopenharmony_ci       q->Target == GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN ||
90bf215546Sopenharmony_ci       q->Target == GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB)
91bf215546Sopenharmony_ci      return q->Stream;
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   /* Drivers with PIPE_CAP_QUERY_PIPELINE_STATISTICS_SINGLE = 0 ignore the
94bf215546Sopenharmony_ci    * index param so it should be useless; but radeonsi needs it in some cases,
95bf215546Sopenharmony_ci    * so pass the correct value.
96bf215546Sopenharmony_ci    */
97bf215546Sopenharmony_ci   switch (q->Target) {
98bf215546Sopenharmony_ci      case GL_VERTICES_SUBMITTED_ARB:
99bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_IA_VERTICES;
100bf215546Sopenharmony_ci      case GL_PRIMITIVES_SUBMITTED_ARB:
101bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_IA_PRIMITIVES;
102bf215546Sopenharmony_ci      case GL_VERTEX_SHADER_INVOCATIONS_ARB:
103bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_VS_INVOCATIONS;
104bf215546Sopenharmony_ci      case GL_GEOMETRY_SHADER_INVOCATIONS:
105bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_GS_INVOCATIONS;
106bf215546Sopenharmony_ci      case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
107bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_GS_PRIMITIVES;
108bf215546Sopenharmony_ci      case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
109bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_C_INVOCATIONS;
110bf215546Sopenharmony_ci      case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
111bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_C_PRIMITIVES;
112bf215546Sopenharmony_ci      case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
113bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_PS_INVOCATIONS;
114bf215546Sopenharmony_ci      case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
115bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_HS_INVOCATIONS;
116bf215546Sopenharmony_ci      case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
117bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_DS_INVOCATIONS;
118bf215546Sopenharmony_ci      case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
119bf215546Sopenharmony_ci         return PIPE_STAT_QUERY_CS_INVOCATIONS;
120bf215546Sopenharmony_ci      default:
121bf215546Sopenharmony_ci         break;
122bf215546Sopenharmony_ci   }
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci   return 0;
125bf215546Sopenharmony_ci}
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_cistatic void
128bf215546Sopenharmony_cibegin_query(struct gl_context *ctx, struct gl_query_object *q)
129bf215546Sopenharmony_ci{
130bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
131bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
132bf215546Sopenharmony_ci   unsigned type;
133bf215546Sopenharmony_ci   bool ret = false;
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   st_flush_bitmap_cache(st_context(ctx));
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   /* convert GL query type to Gallium query type */
138bf215546Sopenharmony_ci   switch (q->Target) {
139bf215546Sopenharmony_ci   case GL_ANY_SAMPLES_PASSED:
140bf215546Sopenharmony_ci      type = PIPE_QUERY_OCCLUSION_PREDICATE;
141bf215546Sopenharmony_ci      break;
142bf215546Sopenharmony_ci   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
143bf215546Sopenharmony_ci      type = PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE;
144bf215546Sopenharmony_ci      break;
145bf215546Sopenharmony_ci   case GL_SAMPLES_PASSED_ARB:
146bf215546Sopenharmony_ci      type = PIPE_QUERY_OCCLUSION_COUNTER;
147bf215546Sopenharmony_ci      break;
148bf215546Sopenharmony_ci   case GL_PRIMITIVES_GENERATED:
149bf215546Sopenharmony_ci      type = PIPE_QUERY_PRIMITIVES_GENERATED;
150bf215546Sopenharmony_ci      break;
151bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
152bf215546Sopenharmony_ci      type = PIPE_QUERY_PRIMITIVES_EMITTED;
153bf215546Sopenharmony_ci      break;
154bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW_ARB:
155bf215546Sopenharmony_ci      type = PIPE_QUERY_SO_OVERFLOW_PREDICATE;
156bf215546Sopenharmony_ci      break;
157bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_OVERFLOW_ARB:
158bf215546Sopenharmony_ci      type = PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE;
159bf215546Sopenharmony_ci      break;
160bf215546Sopenharmony_ci   case GL_TIME_ELAPSED:
161bf215546Sopenharmony_ci      if (st->has_time_elapsed)
162bf215546Sopenharmony_ci         type = PIPE_QUERY_TIME_ELAPSED;
163bf215546Sopenharmony_ci      else
164bf215546Sopenharmony_ci         type = PIPE_QUERY_TIMESTAMP;
165bf215546Sopenharmony_ci      break;
166bf215546Sopenharmony_ci   case GL_VERTICES_SUBMITTED_ARB:
167bf215546Sopenharmony_ci   case GL_PRIMITIVES_SUBMITTED_ARB:
168bf215546Sopenharmony_ci   case GL_VERTEX_SHADER_INVOCATIONS_ARB:
169bf215546Sopenharmony_ci   case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
170bf215546Sopenharmony_ci   case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
171bf215546Sopenharmony_ci   case GL_GEOMETRY_SHADER_INVOCATIONS:
172bf215546Sopenharmony_ci   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
173bf215546Sopenharmony_ci   case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
174bf215546Sopenharmony_ci   case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
175bf215546Sopenharmony_ci   case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
176bf215546Sopenharmony_ci   case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
177bf215546Sopenharmony_ci      type = st->has_single_pipe_stat ? PIPE_QUERY_PIPELINE_STATISTICS_SINGLE
178bf215546Sopenharmony_ci                                      : PIPE_QUERY_PIPELINE_STATISTICS;
179bf215546Sopenharmony_ci      break;
180bf215546Sopenharmony_ci   default:
181bf215546Sopenharmony_ci      assert(0 && "unexpected query target in st_BeginQuery()");
182bf215546Sopenharmony_ci      return;
183bf215546Sopenharmony_ci   }
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   if (q->type != type) {
186bf215546Sopenharmony_ci      /* free old query of different type */
187bf215546Sopenharmony_ci      free_queries(pipe, q);
188bf215546Sopenharmony_ci      q->type = PIPE_QUERY_TYPES; /* an invalid value */
189bf215546Sopenharmony_ci   }
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci   if (q->Target == GL_TIME_ELAPSED &&
192bf215546Sopenharmony_ci       type == PIPE_QUERY_TIMESTAMP) {
193bf215546Sopenharmony_ci      /* Determine time elapsed by emitting two timestamp queries. */
194bf215546Sopenharmony_ci      if (!q->pq_begin) {
195bf215546Sopenharmony_ci         q->pq_begin = pipe->create_query(pipe, type, 0);
196bf215546Sopenharmony_ci         q->type = type;
197bf215546Sopenharmony_ci      }
198bf215546Sopenharmony_ci      if (q->pq_begin)
199bf215546Sopenharmony_ci         ret = pipe->end_query(pipe, q->pq_begin);
200bf215546Sopenharmony_ci   } else {
201bf215546Sopenharmony_ci      if (!q->pq) {
202bf215546Sopenharmony_ci         q->pq = pipe->create_query(pipe, type, target_to_index(q));
203bf215546Sopenharmony_ci         q->type = type;
204bf215546Sopenharmony_ci      }
205bf215546Sopenharmony_ci      if (q->pq)
206bf215546Sopenharmony_ci         ret = pipe->begin_query(pipe, q->pq);
207bf215546Sopenharmony_ci   }
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci   if (!ret) {
210bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery");
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci      free_queries(pipe, q);
213bf215546Sopenharmony_ci      q->Active = GL_FALSE;
214bf215546Sopenharmony_ci      return;
215bf215546Sopenharmony_ci   }
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   if (q->type != PIPE_QUERY_TIMESTAMP)
218bf215546Sopenharmony_ci      st->active_queries++;
219bf215546Sopenharmony_ci
220bf215546Sopenharmony_ci   assert(q->type == type);
221bf215546Sopenharmony_ci}
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_cistatic void
225bf215546Sopenharmony_ciend_query(struct gl_context *ctx, struct gl_query_object *q)
226bf215546Sopenharmony_ci{
227bf215546Sopenharmony_ci   struct st_context *st = st_context(ctx);
228bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
229bf215546Sopenharmony_ci   bool ret = false;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   st_flush_bitmap_cache(st_context(ctx));
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   if ((q->Target == GL_TIMESTAMP ||
234bf215546Sopenharmony_ci        q->Target == GL_TIME_ELAPSED) &&
235bf215546Sopenharmony_ci       !q->pq) {
236bf215546Sopenharmony_ci      q->pq = pipe->create_query(pipe, PIPE_QUERY_TIMESTAMP, 0);
237bf215546Sopenharmony_ci      q->type = PIPE_QUERY_TIMESTAMP;
238bf215546Sopenharmony_ci   }
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   if (q->pq)
241bf215546Sopenharmony_ci      ret = pipe->end_query(pipe, q->pq);
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   if (!ret) {
244bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glEndQuery");
245bf215546Sopenharmony_ci      return;
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   if (q->type != PIPE_QUERY_TIMESTAMP)
249bf215546Sopenharmony_ci      st->active_queries--;
250bf215546Sopenharmony_ci}
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_cistatic boolean
254bf215546Sopenharmony_ciget_query_result(struct pipe_context *pipe,
255bf215546Sopenharmony_ci                 struct gl_query_object *q,
256bf215546Sopenharmony_ci                 boolean wait)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   union pipe_query_result data;
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   if (!q->pq) {
261bf215546Sopenharmony_ci      /* Only needed in case we failed to allocate the gallium query earlier.
262bf215546Sopenharmony_ci       * Return TRUE so we don't spin on this forever.
263bf215546Sopenharmony_ci       */
264bf215546Sopenharmony_ci      return TRUE;
265bf215546Sopenharmony_ci   }
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   if (!pipe->get_query_result(pipe, q->pq, wait, &data))
268bf215546Sopenharmony_ci      return FALSE;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   switch (q->type) {
271bf215546Sopenharmony_ci   case PIPE_QUERY_PIPELINE_STATISTICS:
272bf215546Sopenharmony_ci      switch (q->Target) {
273bf215546Sopenharmony_ci      case GL_VERTICES_SUBMITTED_ARB:
274bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.ia_vertices;
275bf215546Sopenharmony_ci         break;
276bf215546Sopenharmony_ci      case GL_PRIMITIVES_SUBMITTED_ARB:
277bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.ia_primitives;
278bf215546Sopenharmony_ci         break;
279bf215546Sopenharmony_ci      case GL_VERTEX_SHADER_INVOCATIONS_ARB:
280bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.vs_invocations;
281bf215546Sopenharmony_ci         break;
282bf215546Sopenharmony_ci      case GL_TESS_CONTROL_SHADER_PATCHES_ARB:
283bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.hs_invocations;
284bf215546Sopenharmony_ci         break;
285bf215546Sopenharmony_ci      case GL_TESS_EVALUATION_SHADER_INVOCATIONS_ARB:
286bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.ds_invocations;
287bf215546Sopenharmony_ci         break;
288bf215546Sopenharmony_ci      case GL_GEOMETRY_SHADER_INVOCATIONS:
289bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.gs_invocations;
290bf215546Sopenharmony_ci         break;
291bf215546Sopenharmony_ci      case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED_ARB:
292bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.gs_primitives;
293bf215546Sopenharmony_ci         break;
294bf215546Sopenharmony_ci      case GL_FRAGMENT_SHADER_INVOCATIONS_ARB:
295bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.ps_invocations;
296bf215546Sopenharmony_ci         break;
297bf215546Sopenharmony_ci      case GL_COMPUTE_SHADER_INVOCATIONS_ARB:
298bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.cs_invocations;
299bf215546Sopenharmony_ci         break;
300bf215546Sopenharmony_ci      case GL_CLIPPING_INPUT_PRIMITIVES_ARB:
301bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.c_invocations;
302bf215546Sopenharmony_ci         break;
303bf215546Sopenharmony_ci      case GL_CLIPPING_OUTPUT_PRIMITIVES_ARB:
304bf215546Sopenharmony_ci         q->Result = data.pipeline_statistics.c_primitives;
305bf215546Sopenharmony_ci         break;
306bf215546Sopenharmony_ci      default:
307bf215546Sopenharmony_ci         unreachable("invalid pipeline statistics counter");
308bf215546Sopenharmony_ci      }
309bf215546Sopenharmony_ci      break;
310bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE:
311bf215546Sopenharmony_ci   case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE:
312bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_PREDICATE:
313bf215546Sopenharmony_ci   case PIPE_QUERY_SO_OVERFLOW_ANY_PREDICATE:
314bf215546Sopenharmony_ci      q->Result = !!data.b;
315bf215546Sopenharmony_ci      break;
316bf215546Sopenharmony_ci   default:
317bf215546Sopenharmony_ci      q->Result = data.u64;
318bf215546Sopenharmony_ci      break;
319bf215546Sopenharmony_ci   }
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   if (q->Target == GL_TIME_ELAPSED &&
322bf215546Sopenharmony_ci       q->type == PIPE_QUERY_TIMESTAMP) {
323bf215546Sopenharmony_ci      /* Calculate the elapsed time from the two timestamp queries */
324bf215546Sopenharmony_ci      GLuint64EXT Result0 = 0;
325bf215546Sopenharmony_ci      assert(q->pq_begin);
326bf215546Sopenharmony_ci      pipe->get_query_result(pipe, q->pq_begin, TRUE, (void *)&Result0);
327bf215546Sopenharmony_ci      q->Result -= Result0;
328bf215546Sopenharmony_ci   } else {
329bf215546Sopenharmony_ci      assert(!q->pq_begin);
330bf215546Sopenharmony_ci   }
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   return TRUE;
333bf215546Sopenharmony_ci}
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_civoid
337bf215546Sopenharmony_ci_mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
338bf215546Sopenharmony_ci{
339bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   /* this function should only be called if we don't have a ready result */
342bf215546Sopenharmony_ci   assert(!q->Ready);
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   while (!q->Ready &&
345bf215546Sopenharmony_ci          !get_query_result(pipe, q, TRUE))
346bf215546Sopenharmony_ci   {
347bf215546Sopenharmony_ci      /* nothing */
348bf215546Sopenharmony_ci   }
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   q->Ready = GL_TRUE;
351bf215546Sopenharmony_ci}
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_civoid
355bf215546Sopenharmony_ci_mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
356bf215546Sopenharmony_ci{
357bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
358bf215546Sopenharmony_ci   assert(!q->Ready);   /* we should not get called if Ready is TRUE */
359bf215546Sopenharmony_ci   q->Ready = get_query_result(pipe, q, FALSE);
360bf215546Sopenharmony_ci}
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ciuint64_t
364bf215546Sopenharmony_ci_mesa_get_timestamp(struct gl_context *ctx)
365bf215546Sopenharmony_ci{
366bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
367bf215546Sopenharmony_ci   struct pipe_screen *screen = pipe->screen;
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   /* Prefer the per-screen function */
370bf215546Sopenharmony_ci   if (screen->get_timestamp) {
371bf215546Sopenharmony_ci      return screen->get_timestamp(screen);
372bf215546Sopenharmony_ci   }
373bf215546Sopenharmony_ci   else {
374bf215546Sopenharmony_ci      /* Fall back to the per-context function */
375bf215546Sopenharmony_ci      assert(pipe->get_timestamp);
376bf215546Sopenharmony_ci      return pipe->get_timestamp(pipe);
377bf215546Sopenharmony_ci   }
378bf215546Sopenharmony_ci}
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_cistatic void
381bf215546Sopenharmony_cistore_query_result(struct gl_context *ctx, struct gl_query_object *q,
382bf215546Sopenharmony_ci                   struct gl_buffer_object *buf, intptr_t offset,
383bf215546Sopenharmony_ci                   GLenum pname, GLenum ptype)
384bf215546Sopenharmony_ci{
385bf215546Sopenharmony_ci   struct pipe_context *pipe = ctx->pipe;
386bf215546Sopenharmony_ci   enum pipe_query_flags flags = 0;
387bf215546Sopenharmony_ci   enum pipe_query_value_type result_type;
388bf215546Sopenharmony_ci   int index;
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci   if (pname == GL_QUERY_RESULT)
391bf215546Sopenharmony_ci      flags |= PIPE_QUERY_WAIT;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   /* GL_QUERY_TARGET is a bit of an extension since it has nothing to
394bf215546Sopenharmony_ci    * do with the GPU end of the query. Write it in "by hand".
395bf215546Sopenharmony_ci    */
396bf215546Sopenharmony_ci   if (pname == GL_QUERY_TARGET) {
397bf215546Sopenharmony_ci      /* Assume that the data must be LE. The endianness situation wrt CPU and
398bf215546Sopenharmony_ci       * GPU is incredibly confusing, but the vast majority of GPUs are
399bf215546Sopenharmony_ci       * LE. When a BE one comes along, this needs some form of resolution.
400bf215546Sopenharmony_ci       */
401bf215546Sopenharmony_ci      unsigned data[2] = { CPU_TO_LE32(q->Target), 0 };
402bf215546Sopenharmony_ci      pipe_buffer_write(pipe, buf->buffer, offset,
403bf215546Sopenharmony_ci                        (ptype == GL_INT64_ARB ||
404bf215546Sopenharmony_ci                         ptype == GL_UNSIGNED_INT64_ARB) ? 8 : 4,
405bf215546Sopenharmony_ci                        data);
406bf215546Sopenharmony_ci      return;
407bf215546Sopenharmony_ci   }
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci   switch (ptype) {
410bf215546Sopenharmony_ci   case GL_INT:
411bf215546Sopenharmony_ci      result_type = PIPE_QUERY_TYPE_I32;
412bf215546Sopenharmony_ci      break;
413bf215546Sopenharmony_ci   case GL_UNSIGNED_INT:
414bf215546Sopenharmony_ci      result_type = PIPE_QUERY_TYPE_U32;
415bf215546Sopenharmony_ci      break;
416bf215546Sopenharmony_ci   case GL_INT64_ARB:
417bf215546Sopenharmony_ci      result_type = PIPE_QUERY_TYPE_I64;
418bf215546Sopenharmony_ci      break;
419bf215546Sopenharmony_ci   case GL_UNSIGNED_INT64_ARB:
420bf215546Sopenharmony_ci      result_type = PIPE_QUERY_TYPE_U64;
421bf215546Sopenharmony_ci      break;
422bf215546Sopenharmony_ci   default:
423bf215546Sopenharmony_ci      unreachable("Unexpected result type");
424bf215546Sopenharmony_ci   }
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci   if (pname == GL_QUERY_RESULT_AVAILABLE) {
427bf215546Sopenharmony_ci      index = -1;
428bf215546Sopenharmony_ci   } else if (q->type == PIPE_QUERY_PIPELINE_STATISTICS) {
429bf215546Sopenharmony_ci      index = target_to_index(q);
430bf215546Sopenharmony_ci   } else {
431bf215546Sopenharmony_ci      index = 0;
432bf215546Sopenharmony_ci   }
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci   pipe->get_query_result_resource(pipe, q->pq, flags, result_type, index,
435bf215546Sopenharmony_ci                                   buf->buffer, offset);
436bf215546Sopenharmony_ci}
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_cistatic struct gl_query_object **
439bf215546Sopenharmony_ciget_pipe_stats_binding_point(struct gl_context *ctx,
440bf215546Sopenharmony_ci                             GLenum target)
441bf215546Sopenharmony_ci{
442bf215546Sopenharmony_ci   const int which = target - GL_VERTICES_SUBMITTED;
443bf215546Sopenharmony_ci   assert(which < MAX_PIPELINE_STATISTICS);
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   if (!_mesa_has_ARB_pipeline_statistics_query(ctx))
446bf215546Sopenharmony_ci      return NULL;
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci   return &ctx->Query.pipeline_stats[which];
449bf215546Sopenharmony_ci}
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci/**
452bf215546Sopenharmony_ci * Return pointer to the query object binding point for the given target and
453bf215546Sopenharmony_ci * index.
454bf215546Sopenharmony_ci * \return NULL if invalid target, else the address of binding point
455bf215546Sopenharmony_ci */
456bf215546Sopenharmony_cistatic struct gl_query_object **
457bf215546Sopenharmony_ciget_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index)
458bf215546Sopenharmony_ci{
459bf215546Sopenharmony_ci   switch (target) {
460bf215546Sopenharmony_ci   case GL_SAMPLES_PASSED:
461bf215546Sopenharmony_ci      if (_mesa_has_ARB_occlusion_query(ctx) ||
462bf215546Sopenharmony_ci          _mesa_has_ARB_occlusion_query2(ctx))
463bf215546Sopenharmony_ci         return &ctx->Query.CurrentOcclusionObject;
464bf215546Sopenharmony_ci      else
465bf215546Sopenharmony_ci         return NULL;
466bf215546Sopenharmony_ci   case GL_ANY_SAMPLES_PASSED:
467bf215546Sopenharmony_ci      if (_mesa_has_ARB_occlusion_query2(ctx) ||
468bf215546Sopenharmony_ci          _mesa_has_EXT_occlusion_query_boolean(ctx))
469bf215546Sopenharmony_ci         return &ctx->Query.CurrentOcclusionObject;
470bf215546Sopenharmony_ci      else
471bf215546Sopenharmony_ci         return NULL;
472bf215546Sopenharmony_ci   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
473bf215546Sopenharmony_ci      if (_mesa_has_ARB_ES3_compatibility(ctx) ||
474bf215546Sopenharmony_ci          _mesa_has_EXT_occlusion_query_boolean(ctx))
475bf215546Sopenharmony_ci         return &ctx->Query.CurrentOcclusionObject;
476bf215546Sopenharmony_ci      else
477bf215546Sopenharmony_ci         return NULL;
478bf215546Sopenharmony_ci   case GL_TIME_ELAPSED:
479bf215546Sopenharmony_ci      if (_mesa_has_EXT_timer_query(ctx) ||
480bf215546Sopenharmony_ci          _mesa_has_EXT_disjoint_timer_query(ctx))
481bf215546Sopenharmony_ci         return &ctx->Query.CurrentTimerObject;
482bf215546Sopenharmony_ci      else
483bf215546Sopenharmony_ci         return NULL;
484bf215546Sopenharmony_ci   case GL_PRIMITIVES_GENERATED:
485bf215546Sopenharmony_ci      if (_mesa_has_EXT_transform_feedback(ctx) ||
486bf215546Sopenharmony_ci          _mesa_has_EXT_tessellation_shader(ctx) ||
487bf215546Sopenharmony_ci          _mesa_has_OES_geometry_shader(ctx))
488bf215546Sopenharmony_ci         return &ctx->Query.PrimitivesGenerated[index];
489bf215546Sopenharmony_ci      else
490bf215546Sopenharmony_ci         return NULL;
491bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
492bf215546Sopenharmony_ci      if (_mesa_has_EXT_transform_feedback(ctx) || _mesa_is_gles3(ctx))
493bf215546Sopenharmony_ci         return &ctx->Query.PrimitivesWritten[index];
494bf215546Sopenharmony_ci      else
495bf215546Sopenharmony_ci         return NULL;
496bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
497bf215546Sopenharmony_ci      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
498bf215546Sopenharmony_ci         return &ctx->Query.TransformFeedbackOverflow[index];
499bf215546Sopenharmony_ci      else
500bf215546Sopenharmony_ci         return NULL;
501bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
502bf215546Sopenharmony_ci      if (_mesa_has_ARB_transform_feedback_overflow_query(ctx))
503bf215546Sopenharmony_ci         return &ctx->Query.TransformFeedbackOverflowAny;
504bf215546Sopenharmony_ci      else
505bf215546Sopenharmony_ci         return NULL;
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci   case GL_VERTICES_SUBMITTED:
508bf215546Sopenharmony_ci   case GL_PRIMITIVES_SUBMITTED:
509bf215546Sopenharmony_ci   case GL_VERTEX_SHADER_INVOCATIONS:
510bf215546Sopenharmony_ci   case GL_FRAGMENT_SHADER_INVOCATIONS:
511bf215546Sopenharmony_ci   case GL_CLIPPING_INPUT_PRIMITIVES:
512bf215546Sopenharmony_ci   case GL_CLIPPING_OUTPUT_PRIMITIVES:
513bf215546Sopenharmony_ci         return get_pipe_stats_binding_point(ctx, target);
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_ci   case GL_GEOMETRY_SHADER_INVOCATIONS:
516bf215546Sopenharmony_ci      /* GL_GEOMETRY_SHADER_INVOCATIONS is defined in a non-sequential order */
517bf215546Sopenharmony_ci      target = GL_VERTICES_SUBMITTED + MAX_PIPELINE_STATISTICS - 1;
518bf215546Sopenharmony_ci      FALLTHROUGH;
519bf215546Sopenharmony_ci   case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
520bf215546Sopenharmony_ci      if (_mesa_has_geometry_shaders(ctx))
521bf215546Sopenharmony_ci         return get_pipe_stats_binding_point(ctx, target);
522bf215546Sopenharmony_ci      else
523bf215546Sopenharmony_ci         return NULL;
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci   case GL_TESS_CONTROL_SHADER_PATCHES:
526bf215546Sopenharmony_ci   case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
527bf215546Sopenharmony_ci      if (_mesa_has_tessellation(ctx))
528bf215546Sopenharmony_ci         return get_pipe_stats_binding_point(ctx, target);
529bf215546Sopenharmony_ci      else
530bf215546Sopenharmony_ci         return NULL;
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci   case GL_COMPUTE_SHADER_INVOCATIONS:
533bf215546Sopenharmony_ci      if (_mesa_has_compute_shaders(ctx))
534bf215546Sopenharmony_ci         return get_pipe_stats_binding_point(ctx, target);
535bf215546Sopenharmony_ci      else
536bf215546Sopenharmony_ci         return NULL;
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci   default:
539bf215546Sopenharmony_ci      return NULL;
540bf215546Sopenharmony_ci   }
541bf215546Sopenharmony_ci}
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci/**
544bf215546Sopenharmony_ci * Create $n query objects and store them in *ids. Make them of type $target
545bf215546Sopenharmony_ci * if dsa is set. Called from _mesa_GenQueries() and _mesa_CreateQueries().
546bf215546Sopenharmony_ci */
547bf215546Sopenharmony_cistatic void
548bf215546Sopenharmony_cicreate_queries(struct gl_context *ctx, GLenum target, GLsizei n, GLuint *ids,
549bf215546Sopenharmony_ci               bool dsa)
550bf215546Sopenharmony_ci{
551bf215546Sopenharmony_ci   const char *func = dsa ? "glGenQueries" : "glCreateQueries";
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
554bf215546Sopenharmony_ci      _mesa_debug(ctx, "%s(%d)\n", func, n);
555bf215546Sopenharmony_ci
556bf215546Sopenharmony_ci   if (n < 0) {
557bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func);
558bf215546Sopenharmony_ci      return;
559bf215546Sopenharmony_ci   }
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci   if (_mesa_HashFindFreeKeys(ctx->Query.QueryObjects, ids, n)) {
562bf215546Sopenharmony_ci      GLsizei i;
563bf215546Sopenharmony_ci      for (i = 0; i < n; i++) {
564bf215546Sopenharmony_ci         struct gl_query_object *q
565bf215546Sopenharmony_ci            = new_query_object(ctx, ids[i]);
566bf215546Sopenharmony_ci         if (!q) {
567bf215546Sopenharmony_ci            _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
568bf215546Sopenharmony_ci            return;
569bf215546Sopenharmony_ci         } else if (dsa) {
570bf215546Sopenharmony_ci            /* Do the equivalent of binding the buffer with a target */
571bf215546Sopenharmony_ci            q->Target = target;
572bf215546Sopenharmony_ci            q->EverBound = GL_TRUE;
573bf215546Sopenharmony_ci         }
574bf215546Sopenharmony_ci         _mesa_HashInsertLocked(ctx->Query.QueryObjects, ids[i], q, true);
575bf215546Sopenharmony_ci      }
576bf215546Sopenharmony_ci   }
577bf215546Sopenharmony_ci}
578bf215546Sopenharmony_ci
579bf215546Sopenharmony_civoid GLAPIENTRY
580bf215546Sopenharmony_ci_mesa_GenQueries(GLsizei n, GLuint *ids)
581bf215546Sopenharmony_ci{
582bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
583bf215546Sopenharmony_ci   create_queries(ctx, 0, n, ids, false);
584bf215546Sopenharmony_ci}
585bf215546Sopenharmony_ci
586bf215546Sopenharmony_civoid GLAPIENTRY
587bf215546Sopenharmony_ci_mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids)
588bf215546Sopenharmony_ci{
589bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
590bf215546Sopenharmony_ci
591bf215546Sopenharmony_ci   switch (target) {
592bf215546Sopenharmony_ci   case GL_SAMPLES_PASSED:
593bf215546Sopenharmony_ci   case GL_ANY_SAMPLES_PASSED:
594bf215546Sopenharmony_ci   case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
595bf215546Sopenharmony_ci   case GL_TIME_ELAPSED:
596bf215546Sopenharmony_ci   case GL_TIMESTAMP:
597bf215546Sopenharmony_ci   case GL_PRIMITIVES_GENERATED:
598bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
599bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
600bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_OVERFLOW:
601bf215546Sopenharmony_ci      break;
602bf215546Sopenharmony_ci   default:
603bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glCreateQueries(invalid target = %s)",
604bf215546Sopenharmony_ci                  _mesa_enum_to_string(target));
605bf215546Sopenharmony_ci      return;
606bf215546Sopenharmony_ci   }
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci   create_queries(ctx, target, n, ids, true);
609bf215546Sopenharmony_ci}
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci
612bf215546Sopenharmony_civoid GLAPIENTRY
613bf215546Sopenharmony_ci_mesa_DeleteQueries(GLsizei n, const GLuint *ids)
614bf215546Sopenharmony_ci{
615bf215546Sopenharmony_ci   GLint i;
616bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
617bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
618bf215546Sopenharmony_ci
619bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
620bf215546Sopenharmony_ci      _mesa_debug(ctx, "glDeleteQueries(%d)\n", n);
621bf215546Sopenharmony_ci
622bf215546Sopenharmony_ci   if (n < 0) {
623bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
624bf215546Sopenharmony_ci      return;
625bf215546Sopenharmony_ci   }
626bf215546Sopenharmony_ci
627bf215546Sopenharmony_ci   for (i = 0; i < n; i++) {
628bf215546Sopenharmony_ci      if (ids[i] > 0) {
629bf215546Sopenharmony_ci         struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
630bf215546Sopenharmony_ci         if (q) {
631bf215546Sopenharmony_ci            if (q->Active) {
632bf215546Sopenharmony_ci               struct gl_query_object **bindpt;
633bf215546Sopenharmony_ci               bindpt = get_query_binding_point(ctx, q->Target, q->Stream);
634bf215546Sopenharmony_ci               assert(bindpt); /* Should be non-null for active q. */
635bf215546Sopenharmony_ci               if (bindpt) {
636bf215546Sopenharmony_ci                  *bindpt = NULL;
637bf215546Sopenharmony_ci               }
638bf215546Sopenharmony_ci               q->Active = GL_FALSE;
639bf215546Sopenharmony_ci               end_query(ctx, q);
640bf215546Sopenharmony_ci            }
641bf215546Sopenharmony_ci            _mesa_HashRemoveLocked(ctx->Query.QueryObjects, ids[i]);
642bf215546Sopenharmony_ci            delete_query(ctx, q);
643bf215546Sopenharmony_ci         }
644bf215546Sopenharmony_ci      }
645bf215546Sopenharmony_ci   }
646bf215546Sopenharmony_ci}
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci
649bf215546Sopenharmony_ciGLboolean GLAPIENTRY
650bf215546Sopenharmony_ci_mesa_IsQuery(GLuint id)
651bf215546Sopenharmony_ci{
652bf215546Sopenharmony_ci   struct gl_query_object *q;
653bf215546Sopenharmony_ci
654bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
655bf215546Sopenharmony_ci   ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
658bf215546Sopenharmony_ci      _mesa_debug(ctx, "glIsQuery(%u)\n", id);
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci   if (id == 0)
661bf215546Sopenharmony_ci      return GL_FALSE;
662bf215546Sopenharmony_ci
663bf215546Sopenharmony_ci   q = _mesa_lookup_query_object(ctx, id);
664bf215546Sopenharmony_ci   if (q == NULL)
665bf215546Sopenharmony_ci      return GL_FALSE;
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ci   return q->EverBound;
668bf215546Sopenharmony_ci}
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_cistatic GLboolean
671bf215546Sopenharmony_ciquery_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
672bf215546Sopenharmony_ci{
673bf215546Sopenharmony_ci   switch (target) {
674bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
675bf215546Sopenharmony_ci   case GL_PRIMITIVES_GENERATED:
676bf215546Sopenharmony_ci   case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
677bf215546Sopenharmony_ci      if (index >= ctx->Const.MaxVertexStreams) {
678bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE,
679bf215546Sopenharmony_ci                     "glBeginQueryIndexed(index>=MaxVertexStreams)");
680bf215546Sopenharmony_ci         return GL_FALSE;
681bf215546Sopenharmony_ci      }
682bf215546Sopenharmony_ci      break;
683bf215546Sopenharmony_ci   default:
684bf215546Sopenharmony_ci      if (index > 0) {
685bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
686bf215546Sopenharmony_ci         return GL_FALSE;
687bf215546Sopenharmony_ci      }
688bf215546Sopenharmony_ci   }
689bf215546Sopenharmony_ci   return GL_TRUE;
690bf215546Sopenharmony_ci}
691bf215546Sopenharmony_ci
692bf215546Sopenharmony_civoid GLAPIENTRY
693bf215546Sopenharmony_ci_mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
694bf215546Sopenharmony_ci{
695bf215546Sopenharmony_ci   struct gl_query_object *q, **bindpt;
696bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
697bf215546Sopenharmony_ci
698bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
699bf215546Sopenharmony_ci      _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
700bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), index, id);
701bf215546Sopenharmony_ci
702bf215546Sopenharmony_ci   if (!query_error_check_index(ctx, target, index))
703bf215546Sopenharmony_ci      return;
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
706bf215546Sopenharmony_ci
707bf215546Sopenharmony_ci   bindpt = get_query_binding_point(ctx, target, index);
708bf215546Sopenharmony_ci   if (!bindpt) {
709bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
710bf215546Sopenharmony_ci      return;
711bf215546Sopenharmony_ci   }
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci   /* From the GL_ARB_occlusion_query spec:
714bf215546Sopenharmony_ci    *
715bf215546Sopenharmony_ci    *     "If BeginQueryARB is called while another query is already in
716bf215546Sopenharmony_ci    *      progress with the same target, an INVALID_OPERATION error is
717bf215546Sopenharmony_ci    *      generated."
718bf215546Sopenharmony_ci    */
719bf215546Sopenharmony_ci   if (*bindpt) {
720bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
721bf215546Sopenharmony_ci                  "glBeginQuery{Indexed}(target=%s is active)",
722bf215546Sopenharmony_ci                  _mesa_enum_to_string(target));
723bf215546Sopenharmony_ci      return;
724bf215546Sopenharmony_ci   }
725bf215546Sopenharmony_ci
726bf215546Sopenharmony_ci   if (id == 0) {
727bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
728bf215546Sopenharmony_ci      return;
729bf215546Sopenharmony_ci   }
730bf215546Sopenharmony_ci
731bf215546Sopenharmony_ci   q = _mesa_lookup_query_object(ctx, id);
732bf215546Sopenharmony_ci   if (!q) {
733bf215546Sopenharmony_ci      if (ctx->API != API_OPENGL_COMPAT) {
734bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
735bf215546Sopenharmony_ci                     "glBeginQuery{Indexed}(non-gen name)");
736bf215546Sopenharmony_ci         return;
737bf215546Sopenharmony_ci      } else {
738bf215546Sopenharmony_ci         /* create new object */
739bf215546Sopenharmony_ci         q = new_query_object(ctx, id);
740bf215546Sopenharmony_ci         if (!q) {
741bf215546Sopenharmony_ci            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
742bf215546Sopenharmony_ci            return;
743bf215546Sopenharmony_ci         }
744bf215546Sopenharmony_ci         _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false);
745bf215546Sopenharmony_ci      }
746bf215546Sopenharmony_ci   }
747bf215546Sopenharmony_ci   else {
748bf215546Sopenharmony_ci      /* pre-existing object */
749bf215546Sopenharmony_ci      if (q->Active) {
750bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
751bf215546Sopenharmony_ci                     "glBeginQuery{Indexed}(query already active)");
752bf215546Sopenharmony_ci         return;
753bf215546Sopenharmony_ci      }
754bf215546Sopenharmony_ci
755bf215546Sopenharmony_ci      /* Section 2.14 Asynchronous Queries, page 84 of the OpenGL ES 3.0.4
756bf215546Sopenharmony_ci       * spec states:
757bf215546Sopenharmony_ci       *
758bf215546Sopenharmony_ci       *     "BeginQuery generates an INVALID_OPERATION error if any of the
759bf215546Sopenharmony_ci       *      following conditions hold: [...] id is the name of an
760bf215546Sopenharmony_ci       *      existing query object whose type does not match target; [...]
761bf215546Sopenharmony_ci       *
762bf215546Sopenharmony_ci       * Similar wording exists in the OpenGL 4.5 spec, section 4.2. QUERY
763bf215546Sopenharmony_ci       * OBJECTS AND ASYNCHRONOUS QUERIES, page 43.
764bf215546Sopenharmony_ci       */
765bf215546Sopenharmony_ci      if (q->EverBound && q->Target != target) {
766bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
767bf215546Sopenharmony_ci                     "glBeginQuery{Indexed}(target mismatch)");
768bf215546Sopenharmony_ci         return;
769bf215546Sopenharmony_ci      }
770bf215546Sopenharmony_ci   }
771bf215546Sopenharmony_ci
772bf215546Sopenharmony_ci   /* This possibly changes the target of a buffer allocated by
773bf215546Sopenharmony_ci    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
774bf215546Sopenharmony_ci    * the following:
775bf215546Sopenharmony_ci    *
776bf215546Sopenharmony_ci    * "CreateQueries adds a <target>, so strictly speaking the <target>
777bf215546Sopenharmony_ci    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
778bf215546Sopenharmony_ci    * isn't a selector, so we decided not to change it."
779bf215546Sopenharmony_ci    *
780bf215546Sopenharmony_ci    * Updating the target of the query object should be acceptable, so let's
781bf215546Sopenharmony_ci    * do that.
782bf215546Sopenharmony_ci    */
783bf215546Sopenharmony_ci
784bf215546Sopenharmony_ci   q->Target = target;
785bf215546Sopenharmony_ci   q->Active = GL_TRUE;
786bf215546Sopenharmony_ci   q->Result = 0;
787bf215546Sopenharmony_ci   q->Ready = GL_FALSE;
788bf215546Sopenharmony_ci   q->EverBound = GL_TRUE;
789bf215546Sopenharmony_ci   q->Stream = index;
790bf215546Sopenharmony_ci
791bf215546Sopenharmony_ci   /* XXX should probably refcount query objects */
792bf215546Sopenharmony_ci   *bindpt = q;
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci   begin_query(ctx, q);
795bf215546Sopenharmony_ci}
796bf215546Sopenharmony_ci
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_civoid GLAPIENTRY
799bf215546Sopenharmony_ci_mesa_EndQueryIndexed(GLenum target, GLuint index)
800bf215546Sopenharmony_ci{
801bf215546Sopenharmony_ci   struct gl_query_object *q, **bindpt;
802bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
803bf215546Sopenharmony_ci
804bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
805bf215546Sopenharmony_ci      _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
806bf215546Sopenharmony_ci                  _mesa_enum_to_string(target), index);
807bf215546Sopenharmony_ci
808bf215546Sopenharmony_ci   if (!query_error_check_index(ctx, target, index))
809bf215546Sopenharmony_ci      return;
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
812bf215546Sopenharmony_ci
813bf215546Sopenharmony_ci   bindpt = get_query_binding_point(ctx, target, index);
814bf215546Sopenharmony_ci   if (!bindpt) {
815bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
816bf215546Sopenharmony_ci      return;
817bf215546Sopenharmony_ci   }
818bf215546Sopenharmony_ci
819bf215546Sopenharmony_ci   /* XXX should probably refcount query objects */
820bf215546Sopenharmony_ci   q = *bindpt;
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci   /* Check for GL_ANY_SAMPLES_PASSED vs GL_SAMPLES_PASSED. */
823bf215546Sopenharmony_ci   if (q && q->Target != target) {
824bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
825bf215546Sopenharmony_ci                  "glEndQuery(target=%s with active query of target %s)",
826bf215546Sopenharmony_ci                  _mesa_enum_to_string(target),
827bf215546Sopenharmony_ci                  _mesa_enum_to_string(q->Target));
828bf215546Sopenharmony_ci      return;
829bf215546Sopenharmony_ci   }
830bf215546Sopenharmony_ci
831bf215546Sopenharmony_ci   *bindpt = NULL;
832bf215546Sopenharmony_ci
833bf215546Sopenharmony_ci   if (!q || !q->Active) {
834bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
835bf215546Sopenharmony_ci                  "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
836bf215546Sopenharmony_ci      return;
837bf215546Sopenharmony_ci   }
838bf215546Sopenharmony_ci
839bf215546Sopenharmony_ci   q->Active = GL_FALSE;
840bf215546Sopenharmony_ci   end_query(ctx, q);
841bf215546Sopenharmony_ci}
842bf215546Sopenharmony_ci
843bf215546Sopenharmony_civoid GLAPIENTRY
844bf215546Sopenharmony_ci_mesa_BeginQuery(GLenum target, GLuint id)
845bf215546Sopenharmony_ci{
846bf215546Sopenharmony_ci   _mesa_BeginQueryIndexed(target, 0, id);
847bf215546Sopenharmony_ci}
848bf215546Sopenharmony_ci
849bf215546Sopenharmony_civoid GLAPIENTRY
850bf215546Sopenharmony_ci_mesa_EndQuery(GLenum target)
851bf215546Sopenharmony_ci{
852bf215546Sopenharmony_ci   _mesa_EndQueryIndexed(target, 0);
853bf215546Sopenharmony_ci}
854bf215546Sopenharmony_ci
855bf215546Sopenharmony_civoid GLAPIENTRY
856bf215546Sopenharmony_ci_mesa_QueryCounter(GLuint id, GLenum target)
857bf215546Sopenharmony_ci{
858bf215546Sopenharmony_ci   struct gl_query_object *q;
859bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
860bf215546Sopenharmony_ci
861bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
862bf215546Sopenharmony_ci      _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
863bf215546Sopenharmony_ci                  _mesa_enum_to_string(target));
864bf215546Sopenharmony_ci
865bf215546Sopenharmony_ci   /* error checking */
866bf215546Sopenharmony_ci   if (target != GL_TIMESTAMP) {
867bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
868bf215546Sopenharmony_ci      return;
869bf215546Sopenharmony_ci   }
870bf215546Sopenharmony_ci
871bf215546Sopenharmony_ci   if (id == 0) {
872bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
873bf215546Sopenharmony_ci      return;
874bf215546Sopenharmony_ci   }
875bf215546Sopenharmony_ci
876bf215546Sopenharmony_ci   q = _mesa_lookup_query_object(ctx, id);
877bf215546Sopenharmony_ci   if (!q) {
878bf215546Sopenharmony_ci      /* XXX the Core profile should throw INVALID_OPERATION here */
879bf215546Sopenharmony_ci
880bf215546Sopenharmony_ci      /* create new object */
881bf215546Sopenharmony_ci      q = new_query_object(ctx, id);
882bf215546Sopenharmony_ci      if (!q) {
883bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
884bf215546Sopenharmony_ci         return;
885bf215546Sopenharmony_ci      }
886bf215546Sopenharmony_ci      _mesa_HashInsertLocked(ctx->Query.QueryObjects, id, q, false);
887bf215546Sopenharmony_ci   }
888bf215546Sopenharmony_ci   else {
889bf215546Sopenharmony_ci      if (q->Target && q->Target != GL_TIMESTAMP) {
890bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
891bf215546Sopenharmony_ci                     "glQueryCounter(id has an invalid target)");
892bf215546Sopenharmony_ci         return;
893bf215546Sopenharmony_ci      }
894bf215546Sopenharmony_ci   }
895bf215546Sopenharmony_ci
896bf215546Sopenharmony_ci   if (q->Active) {
897bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
898bf215546Sopenharmony_ci      return;
899bf215546Sopenharmony_ci   }
900bf215546Sopenharmony_ci
901bf215546Sopenharmony_ci   /* This possibly changes the target of a buffer allocated by
902bf215546Sopenharmony_ci    * CreateQueries. Issue 39) in the ARB_direct_state_access extension states
903bf215546Sopenharmony_ci    * the following:
904bf215546Sopenharmony_ci    *
905bf215546Sopenharmony_ci    * "CreateQueries adds a <target>, so strictly speaking the <target>
906bf215546Sopenharmony_ci    * command isn't needed for BeginQuery/EndQuery, but in the end, this also
907bf215546Sopenharmony_ci    * isn't a selector, so we decided not to change it."
908bf215546Sopenharmony_ci    *
909bf215546Sopenharmony_ci    * Updating the target of the query object should be acceptable, so let's
910bf215546Sopenharmony_ci    * do that.
911bf215546Sopenharmony_ci    */
912bf215546Sopenharmony_ci
913bf215546Sopenharmony_ci   q->Target = target;
914bf215546Sopenharmony_ci   q->Result = 0;
915bf215546Sopenharmony_ci   q->Ready = GL_FALSE;
916bf215546Sopenharmony_ci   q->EverBound = GL_TRUE;
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ci   /* QueryCounter is implemented using EndQuery without BeginQuery
919bf215546Sopenharmony_ci    * in drivers. This is actually Direct3D and Gallium convention.
920bf215546Sopenharmony_ci    */
921bf215546Sopenharmony_ci   end_query(ctx, q);
922bf215546Sopenharmony_ci}
923bf215546Sopenharmony_ci
924bf215546Sopenharmony_ci
925bf215546Sopenharmony_civoid GLAPIENTRY
926bf215546Sopenharmony_ci_mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
927bf215546Sopenharmony_ci                        GLint *params)
928bf215546Sopenharmony_ci{
929bf215546Sopenharmony_ci   struct gl_query_object *q = NULL, **bindpt = NULL;
930bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
931bf215546Sopenharmony_ci
932bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
933bf215546Sopenharmony_ci      _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
934bf215546Sopenharmony_ci                  _mesa_enum_to_string(target),
935bf215546Sopenharmony_ci                  index,
936bf215546Sopenharmony_ci                  _mesa_enum_to_string(pname));
937bf215546Sopenharmony_ci
938bf215546Sopenharmony_ci   if (!query_error_check_index(ctx, target, index))
939bf215546Sopenharmony_ci      return;
940bf215546Sopenharmony_ci
941bf215546Sopenharmony_ci   /* From the GL_EXT_occlusion_query_boolean spec:
942bf215546Sopenharmony_ci    *
943bf215546Sopenharmony_ci    * "The error INVALID_ENUM is generated if GetQueryivEXT is called where
944bf215546Sopenharmony_ci    * <pname> is not CURRENT_QUERY_EXT."
945bf215546Sopenharmony_ci    *
946bf215546Sopenharmony_ci    * Same rule is present also in ES 3.2 spec.
947bf215546Sopenharmony_ci    *
948bf215546Sopenharmony_ci    * EXT_disjoint_timer_query extends this with GL_QUERY_COUNTER_BITS.
949bf215546Sopenharmony_ci    */
950bf215546Sopenharmony_ci   if (_mesa_is_gles(ctx)) {
951bf215546Sopenharmony_ci      switch (pname) {
952bf215546Sopenharmony_ci      case GL_CURRENT_QUERY:
953bf215546Sopenharmony_ci         break;
954bf215546Sopenharmony_ci      case GL_QUERY_COUNTER_BITS:
955bf215546Sopenharmony_ci         if (_mesa_has_EXT_disjoint_timer_query(ctx))
956bf215546Sopenharmony_ci            break;
957bf215546Sopenharmony_ci         FALLTHROUGH;
958bf215546Sopenharmony_ci      default:
959bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivEXT(%s)",
960bf215546Sopenharmony_ci                     _mesa_enum_to_string(pname));
961bf215546Sopenharmony_ci      }
962bf215546Sopenharmony_ci   }
963bf215546Sopenharmony_ci
964bf215546Sopenharmony_ci   if (target == GL_TIMESTAMP) {
965bf215546Sopenharmony_ci      if (!_mesa_has_ARB_timer_query(ctx) &&
966bf215546Sopenharmony_ci          !_mesa_has_EXT_disjoint_timer_query(ctx)) {
967bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
968bf215546Sopenharmony_ci         return;
969bf215546Sopenharmony_ci      }
970bf215546Sopenharmony_ci   }
971bf215546Sopenharmony_ci   else {
972bf215546Sopenharmony_ci      bindpt = get_query_binding_point(ctx, target, index);
973bf215546Sopenharmony_ci      if (!bindpt) {
974bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
975bf215546Sopenharmony_ci         return;
976bf215546Sopenharmony_ci      }
977bf215546Sopenharmony_ci
978bf215546Sopenharmony_ci      q = *bindpt;
979bf215546Sopenharmony_ci   }
980bf215546Sopenharmony_ci
981bf215546Sopenharmony_ci   switch (pname) {
982bf215546Sopenharmony_ci      case GL_QUERY_COUNTER_BITS:
983bf215546Sopenharmony_ci         switch (target) {
984bf215546Sopenharmony_ci         case GL_SAMPLES_PASSED:
985bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.SamplesPassed;
986bf215546Sopenharmony_ci            break;
987bf215546Sopenharmony_ci         case GL_ANY_SAMPLES_PASSED:
988bf215546Sopenharmony_ci         case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
989bf215546Sopenharmony_ci            /* The minimum value of this is 1 if it's nonzero, and the value
990bf215546Sopenharmony_ci             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
991bf215546Sopenharmony_ci             * bits.
992bf215546Sopenharmony_ci             */
993bf215546Sopenharmony_ci            *params = 1;
994bf215546Sopenharmony_ci            break;
995bf215546Sopenharmony_ci         case GL_TIME_ELAPSED:
996bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.TimeElapsed;
997bf215546Sopenharmony_ci            break;
998bf215546Sopenharmony_ci         case GL_TIMESTAMP:
999bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.Timestamp;
1000bf215546Sopenharmony_ci            break;
1001bf215546Sopenharmony_ci         case GL_PRIMITIVES_GENERATED:
1002bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
1003bf215546Sopenharmony_ci            break;
1004bf215546Sopenharmony_ci         case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
1005bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
1006bf215546Sopenharmony_ci            break;
1007bf215546Sopenharmony_ci         case GL_TRANSFORM_FEEDBACK_STREAM_OVERFLOW:
1008bf215546Sopenharmony_ci         case GL_TRANSFORM_FEEDBACK_OVERFLOW:
1009bf215546Sopenharmony_ci            /* The minimum value of this is 1 if it's nonzero, and the value
1010bf215546Sopenharmony_ci             * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
1011bf215546Sopenharmony_ci             * bits.
1012bf215546Sopenharmony_ci             */
1013bf215546Sopenharmony_ci            *params = 1;
1014bf215546Sopenharmony_ci            break;
1015bf215546Sopenharmony_ci         case GL_VERTICES_SUBMITTED:
1016bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.VerticesSubmitted;
1017bf215546Sopenharmony_ci            break;
1018bf215546Sopenharmony_ci         case GL_PRIMITIVES_SUBMITTED:
1019bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.PrimitivesSubmitted;
1020bf215546Sopenharmony_ci            break;
1021bf215546Sopenharmony_ci         case GL_VERTEX_SHADER_INVOCATIONS:
1022bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.VsInvocations;
1023bf215546Sopenharmony_ci            break;
1024bf215546Sopenharmony_ci         case GL_TESS_CONTROL_SHADER_PATCHES:
1025bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.TessPatches;
1026bf215546Sopenharmony_ci            break;
1027bf215546Sopenharmony_ci         case GL_TESS_EVALUATION_SHADER_INVOCATIONS:
1028bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.TessInvocations;
1029bf215546Sopenharmony_ci            break;
1030bf215546Sopenharmony_ci         case GL_GEOMETRY_SHADER_INVOCATIONS:
1031bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.GsInvocations;
1032bf215546Sopenharmony_ci            break;
1033bf215546Sopenharmony_ci         case GL_GEOMETRY_SHADER_PRIMITIVES_EMITTED:
1034bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.GsPrimitives;
1035bf215546Sopenharmony_ci            break;
1036bf215546Sopenharmony_ci         case GL_FRAGMENT_SHADER_INVOCATIONS:
1037bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.FsInvocations;
1038bf215546Sopenharmony_ci            break;
1039bf215546Sopenharmony_ci         case GL_COMPUTE_SHADER_INVOCATIONS:
1040bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.ComputeInvocations;
1041bf215546Sopenharmony_ci            break;
1042bf215546Sopenharmony_ci         case GL_CLIPPING_INPUT_PRIMITIVES:
1043bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.ClInPrimitives;
1044bf215546Sopenharmony_ci            break;
1045bf215546Sopenharmony_ci         case GL_CLIPPING_OUTPUT_PRIMITIVES:
1046bf215546Sopenharmony_ci            *params = ctx->Const.QueryCounterBits.ClOutPrimitives;
1047bf215546Sopenharmony_ci            break;
1048bf215546Sopenharmony_ci         default:
1049bf215546Sopenharmony_ci            _mesa_problem(ctx,
1050bf215546Sopenharmony_ci                          "Unknown target in glGetQueryIndexediv(target = %s)",
1051bf215546Sopenharmony_ci                          _mesa_enum_to_string(target));
1052bf215546Sopenharmony_ci            *params = 0;
1053bf215546Sopenharmony_ci            break;
1054bf215546Sopenharmony_ci         }
1055bf215546Sopenharmony_ci         break;
1056bf215546Sopenharmony_ci      case GL_CURRENT_QUERY:
1057bf215546Sopenharmony_ci         *params = (q && q->Target == target) ? q->Id : 0;
1058bf215546Sopenharmony_ci         break;
1059bf215546Sopenharmony_ci      default:
1060bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
1061bf215546Sopenharmony_ci         return;
1062bf215546Sopenharmony_ci   }
1063bf215546Sopenharmony_ci}
1064bf215546Sopenharmony_ci
1065bf215546Sopenharmony_civoid GLAPIENTRY
1066bf215546Sopenharmony_ci_mesa_GetQueryiv(GLenum target, GLenum pname, GLint *params)
1067bf215546Sopenharmony_ci{
1068bf215546Sopenharmony_ci   _mesa_GetQueryIndexediv(target, 0, pname, params);
1069bf215546Sopenharmony_ci}
1070bf215546Sopenharmony_ci
1071bf215546Sopenharmony_cistatic void
1072bf215546Sopenharmony_ciget_query_object(struct gl_context *ctx, const char *func,
1073bf215546Sopenharmony_ci                 GLuint id, GLenum pname, GLenum ptype,
1074bf215546Sopenharmony_ci                 struct gl_buffer_object *buf, intptr_t offset)
1075bf215546Sopenharmony_ci{
1076bf215546Sopenharmony_ci   struct gl_query_object *q = NULL;
1077bf215546Sopenharmony_ci   uint64_t value;
1078bf215546Sopenharmony_ci
1079bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
1080bf215546Sopenharmony_ci      _mesa_debug(ctx, "%s(%u, %s)\n", func, id,
1081bf215546Sopenharmony_ci                  _mesa_enum_to_string(pname));
1082bf215546Sopenharmony_ci
1083bf215546Sopenharmony_ci   if (id)
1084bf215546Sopenharmony_ci      q = _mesa_lookup_query_object(ctx, id);
1085bf215546Sopenharmony_ci
1086bf215546Sopenharmony_ci   if (!q || q->Active || !q->EverBound) {
1087bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_OPERATION,
1088bf215546Sopenharmony_ci                  "%s(id=%d is invalid or active)", func, id);
1089bf215546Sopenharmony_ci      return;
1090bf215546Sopenharmony_ci   }
1091bf215546Sopenharmony_ci
1092bf215546Sopenharmony_ci   /* From GL_EXT_occlusion_query_boolean spec:
1093bf215546Sopenharmony_ci    *
1094bf215546Sopenharmony_ci    *    "Accepted by the <pname> parameter of GetQueryObjectivEXT and
1095bf215546Sopenharmony_ci    *    GetQueryObjectuivEXT:
1096bf215546Sopenharmony_ci    *
1097bf215546Sopenharmony_ci    *    QUERY_RESULT_EXT                               0x8866
1098bf215546Sopenharmony_ci    *    QUERY_RESULT_AVAILABLE_EXT                     0x8867"
1099bf215546Sopenharmony_ci    *
1100bf215546Sopenharmony_ci    * Same rule is present also in ES 3.2 spec.
1101bf215546Sopenharmony_ci    */
1102bf215546Sopenharmony_ci   if (_mesa_is_gles(ctx) &&
1103bf215546Sopenharmony_ci       (pname != GL_QUERY_RESULT && pname != GL_QUERY_RESULT_AVAILABLE)) {
1104bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s)", func,
1105bf215546Sopenharmony_ci                  _mesa_enum_to_string(pname));
1106bf215546Sopenharmony_ci      return;
1107bf215546Sopenharmony_ci   }
1108bf215546Sopenharmony_ci
1109bf215546Sopenharmony_ci   if (buf) {
1110bf215546Sopenharmony_ci      bool is_64bit = ptype == GL_INT64_ARB ||
1111bf215546Sopenharmony_ci         ptype == GL_UNSIGNED_INT64_ARB;
1112bf215546Sopenharmony_ci      if (!_mesa_has_ARB_query_buffer_object(ctx)) {
1113bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(not supported)", func);
1114bf215546Sopenharmony_ci         return;
1115bf215546Sopenharmony_ci      }
1116bf215546Sopenharmony_ci      if (buf->Size < offset + 4 * (is_64bit ? 2 : 1)) {
1117bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "%s(out of bounds)", func);
1118bf215546Sopenharmony_ci         return;
1119bf215546Sopenharmony_ci      }
1120bf215546Sopenharmony_ci
1121bf215546Sopenharmony_ci      if (offset < 0) {
1122bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_VALUE, "%s(offset is negative)", func);
1123bf215546Sopenharmony_ci         return;
1124bf215546Sopenharmony_ci      }
1125bf215546Sopenharmony_ci
1126bf215546Sopenharmony_ci      switch (pname) {
1127bf215546Sopenharmony_ci      case GL_QUERY_RESULT:
1128bf215546Sopenharmony_ci      case GL_QUERY_RESULT_NO_WAIT:
1129bf215546Sopenharmony_ci      case GL_QUERY_RESULT_AVAILABLE:
1130bf215546Sopenharmony_ci      case GL_QUERY_TARGET:
1131bf215546Sopenharmony_ci         store_query_result(ctx, q, buf, offset, pname, ptype);
1132bf215546Sopenharmony_ci         return;
1133bf215546Sopenharmony_ci      }
1134bf215546Sopenharmony_ci
1135bf215546Sopenharmony_ci      /* fall through to get error below */
1136bf215546Sopenharmony_ci   }
1137bf215546Sopenharmony_ci
1138bf215546Sopenharmony_ci   switch (pname) {
1139bf215546Sopenharmony_ci   case GL_QUERY_RESULT:
1140bf215546Sopenharmony_ci      if (!q->Ready)
1141bf215546Sopenharmony_ci         _mesa_wait_query(ctx, q);
1142bf215546Sopenharmony_ci      value = q->Result;
1143bf215546Sopenharmony_ci      break;
1144bf215546Sopenharmony_ci   case GL_QUERY_RESULT_NO_WAIT:
1145bf215546Sopenharmony_ci      if (!_mesa_has_ARB_query_buffer_object(ctx))
1146bf215546Sopenharmony_ci         goto invalid_enum;
1147bf215546Sopenharmony_ci      _mesa_check_query(ctx, q);
1148bf215546Sopenharmony_ci      if (!q->Ready)
1149bf215546Sopenharmony_ci         return;
1150bf215546Sopenharmony_ci      value = q->Result;
1151bf215546Sopenharmony_ci      break;
1152bf215546Sopenharmony_ci   case GL_QUERY_RESULT_AVAILABLE:
1153bf215546Sopenharmony_ci      if (!q->Ready)
1154bf215546Sopenharmony_ci         _mesa_check_query(ctx, q);
1155bf215546Sopenharmony_ci      value = q->Ready;
1156bf215546Sopenharmony_ci      break;
1157bf215546Sopenharmony_ci   case GL_QUERY_TARGET:
1158bf215546Sopenharmony_ci      value = q->Target;
1159bf215546Sopenharmony_ci      break;
1160bf215546Sopenharmony_ci   default:
1161bf215546Sopenharmony_ciinvalid_enum:
1162bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=%s)",
1163bf215546Sopenharmony_ci                  func, _mesa_enum_to_string(pname));
1164bf215546Sopenharmony_ci      return;
1165bf215546Sopenharmony_ci   }
1166bf215546Sopenharmony_ci
1167bf215546Sopenharmony_ci   switch (ptype) {
1168bf215546Sopenharmony_ci   case GL_INT: {
1169bf215546Sopenharmony_ci      GLint *param = (GLint *)offset;
1170bf215546Sopenharmony_ci      if (value > 0x7fffffff)
1171bf215546Sopenharmony_ci         *param = 0x7fffffff;
1172bf215546Sopenharmony_ci      else
1173bf215546Sopenharmony_ci         *param = value;
1174bf215546Sopenharmony_ci      break;
1175bf215546Sopenharmony_ci   }
1176bf215546Sopenharmony_ci   case GL_UNSIGNED_INT: {
1177bf215546Sopenharmony_ci      GLuint *param = (GLuint *)offset;
1178bf215546Sopenharmony_ci      if (value > 0xffffffff)
1179bf215546Sopenharmony_ci         *param = 0xffffffff;
1180bf215546Sopenharmony_ci      else
1181bf215546Sopenharmony_ci         *param = value;
1182bf215546Sopenharmony_ci      break;
1183bf215546Sopenharmony_ci   }
1184bf215546Sopenharmony_ci   case GL_INT64_ARB:
1185bf215546Sopenharmony_ci   case GL_UNSIGNED_INT64_ARB: {
1186bf215546Sopenharmony_ci      GLuint64EXT *param = (GLuint64EXT *)offset;
1187bf215546Sopenharmony_ci      *param = value;
1188bf215546Sopenharmony_ci      break;
1189bf215546Sopenharmony_ci   }
1190bf215546Sopenharmony_ci   default:
1191bf215546Sopenharmony_ci      unreachable("unexpected ptype");
1192bf215546Sopenharmony_ci   }
1193bf215546Sopenharmony_ci}
1194bf215546Sopenharmony_ci
1195bf215546Sopenharmony_civoid GLAPIENTRY
1196bf215546Sopenharmony_ci_mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params)
1197bf215546Sopenharmony_ci{
1198bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1199bf215546Sopenharmony_ci
1200bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryObjectiv",
1201bf215546Sopenharmony_ci                    id, pname, GL_INT, ctx->QueryBuffer, (intptr_t)params);
1202bf215546Sopenharmony_ci}
1203bf215546Sopenharmony_ci
1204bf215546Sopenharmony_ci
1205bf215546Sopenharmony_civoid GLAPIENTRY
1206bf215546Sopenharmony_ci_mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
1207bf215546Sopenharmony_ci{
1208bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1209bf215546Sopenharmony_ci
1210bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryObjectuiv",
1211bf215546Sopenharmony_ci                    id, pname, GL_UNSIGNED_INT,
1212bf215546Sopenharmony_ci                    ctx->QueryBuffer, (intptr_t)params);
1213bf215546Sopenharmony_ci}
1214bf215546Sopenharmony_ci
1215bf215546Sopenharmony_ci
1216bf215546Sopenharmony_ci/**
1217bf215546Sopenharmony_ci * New with GL_EXT_timer_query
1218bf215546Sopenharmony_ci */
1219bf215546Sopenharmony_civoid GLAPIENTRY
1220bf215546Sopenharmony_ci_mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params)
1221bf215546Sopenharmony_ci{
1222bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1223bf215546Sopenharmony_ci
1224bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryObjecti64v",
1225bf215546Sopenharmony_ci                    id, pname, GL_INT64_ARB,
1226bf215546Sopenharmony_ci                    ctx->QueryBuffer, (intptr_t)params);
1227bf215546Sopenharmony_ci}
1228bf215546Sopenharmony_ci
1229bf215546Sopenharmony_ci
1230bf215546Sopenharmony_ci/**
1231bf215546Sopenharmony_ci * New with GL_EXT_timer_query
1232bf215546Sopenharmony_ci */
1233bf215546Sopenharmony_civoid GLAPIENTRY
1234bf215546Sopenharmony_ci_mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params)
1235bf215546Sopenharmony_ci{
1236bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1237bf215546Sopenharmony_ci
1238bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryObjectui64v",
1239bf215546Sopenharmony_ci                    id, pname, GL_UNSIGNED_INT64_ARB,
1240bf215546Sopenharmony_ci                    ctx->QueryBuffer, (intptr_t)params);
1241bf215546Sopenharmony_ci}
1242bf215546Sopenharmony_ci
1243bf215546Sopenharmony_ci/**
1244bf215546Sopenharmony_ci * New with GL_ARB_query_buffer_object
1245bf215546Sopenharmony_ci */
1246bf215546Sopenharmony_civoid GLAPIENTRY
1247bf215546Sopenharmony_ci_mesa_GetQueryBufferObjectiv(GLuint id, GLuint buffer, GLenum pname,
1248bf215546Sopenharmony_ci                             GLintptr offset)
1249bf215546Sopenharmony_ci{
1250bf215546Sopenharmony_ci   struct gl_buffer_object *buf;
1251bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1252bf215546Sopenharmony_ci
1253bf215546Sopenharmony_ci   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectiv");
1254bf215546Sopenharmony_ci   if (!buf)
1255bf215546Sopenharmony_ci      return;
1256bf215546Sopenharmony_ci
1257bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryBufferObjectiv",
1258bf215546Sopenharmony_ci                    id, pname, GL_INT, buf, offset);
1259bf215546Sopenharmony_ci}
1260bf215546Sopenharmony_ci
1261bf215546Sopenharmony_ci
1262bf215546Sopenharmony_civoid GLAPIENTRY
1263bf215546Sopenharmony_ci_mesa_GetQueryBufferObjectuiv(GLuint id, GLuint buffer, GLenum pname,
1264bf215546Sopenharmony_ci                              GLintptr offset)
1265bf215546Sopenharmony_ci{
1266bf215546Sopenharmony_ci   struct gl_buffer_object *buf;
1267bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1268bf215546Sopenharmony_ci
1269bf215546Sopenharmony_ci   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectuiv");
1270bf215546Sopenharmony_ci   if (!buf)
1271bf215546Sopenharmony_ci      return;
1272bf215546Sopenharmony_ci
1273bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryBufferObjectuiv",
1274bf215546Sopenharmony_ci                    id, pname, GL_UNSIGNED_INT, buf, offset);
1275bf215546Sopenharmony_ci}
1276bf215546Sopenharmony_ci
1277bf215546Sopenharmony_ci
1278bf215546Sopenharmony_civoid GLAPIENTRY
1279bf215546Sopenharmony_ci_mesa_GetQueryBufferObjecti64v(GLuint id, GLuint buffer, GLenum pname,
1280bf215546Sopenharmony_ci                               GLintptr offset)
1281bf215546Sopenharmony_ci{
1282bf215546Sopenharmony_ci   struct gl_buffer_object *buf;
1283bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1284bf215546Sopenharmony_ci
1285bf215546Sopenharmony_ci   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjecti64v");
1286bf215546Sopenharmony_ci   if (!buf)
1287bf215546Sopenharmony_ci      return;
1288bf215546Sopenharmony_ci
1289bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryBufferObjecti64v",
1290bf215546Sopenharmony_ci                    id, pname, GL_INT64_ARB, buf, offset);
1291bf215546Sopenharmony_ci}
1292bf215546Sopenharmony_ci
1293bf215546Sopenharmony_ci
1294bf215546Sopenharmony_civoid GLAPIENTRY
1295bf215546Sopenharmony_ci_mesa_GetQueryBufferObjectui64v(GLuint id, GLuint buffer, GLenum pname,
1296bf215546Sopenharmony_ci                                GLintptr offset)
1297bf215546Sopenharmony_ci{
1298bf215546Sopenharmony_ci   struct gl_buffer_object *buf;
1299bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1300bf215546Sopenharmony_ci
1301bf215546Sopenharmony_ci   buf = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetQueryBufferObjectui64v");
1302bf215546Sopenharmony_ci   if (!buf)
1303bf215546Sopenharmony_ci      return;
1304bf215546Sopenharmony_ci
1305bf215546Sopenharmony_ci   get_query_object(ctx, "glGetQueryBufferObjectui64v",
1306bf215546Sopenharmony_ci                    id, pname, GL_UNSIGNED_INT64_ARB, buf, offset);
1307bf215546Sopenharmony_ci}
1308bf215546Sopenharmony_ci
1309bf215546Sopenharmony_ci
1310bf215546Sopenharmony_ci/**
1311bf215546Sopenharmony_ci * Allocate/init the context state related to query objects.
1312bf215546Sopenharmony_ci */
1313bf215546Sopenharmony_civoid
1314bf215546Sopenharmony_ci_mesa_init_queryobj(struct gl_context *ctx)
1315bf215546Sopenharmony_ci{
1316bf215546Sopenharmony_ci   struct pipe_screen *screen = ctx->pipe->screen;
1317bf215546Sopenharmony_ci
1318bf215546Sopenharmony_ci   ctx->Query.QueryObjects = _mesa_NewHashTable();
1319bf215546Sopenharmony_ci   ctx->Query.CurrentOcclusionObject = NULL;
1320bf215546Sopenharmony_ci
1321bf215546Sopenharmony_ci   if (screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY))
1322bf215546Sopenharmony_ci      ctx->Const.QueryCounterBits.SamplesPassed = 64;
1323bf215546Sopenharmony_ci   else
1324bf215546Sopenharmony_ci      ctx->Const.QueryCounterBits.SamplesPassed = 0;
1325bf215546Sopenharmony_ci
1326bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.TimeElapsed = 64;
1327bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.Timestamp = 64;
1328bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
1329bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
1330bf215546Sopenharmony_ci
1331bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.VerticesSubmitted = 64;
1332bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64;
1333bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.VsInvocations = 64;
1334bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.TessPatches = 64;
1335bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.TessInvocations = 64;
1336bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.GsInvocations = 64;
1337bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.GsPrimitives = 64;
1338bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.FsInvocations = 64;
1339bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.ComputeInvocations = 64;
1340bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.ClInPrimitives = 64;
1341bf215546Sopenharmony_ci   ctx->Const.QueryCounterBits.ClOutPrimitives = 64;
1342bf215546Sopenharmony_ci}
1343bf215546Sopenharmony_ci
1344bf215546Sopenharmony_ci
1345bf215546Sopenharmony_ci/**
1346bf215546Sopenharmony_ci * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
1347bf215546Sopenharmony_ci */
1348bf215546Sopenharmony_cistatic void
1349bf215546Sopenharmony_cidelete_queryobj_cb(void *data, void *userData)
1350bf215546Sopenharmony_ci{
1351bf215546Sopenharmony_ci   struct gl_query_object *q= (struct gl_query_object *) data;
1352bf215546Sopenharmony_ci   struct gl_context *ctx = (struct gl_context *)userData;
1353bf215546Sopenharmony_ci   delete_query(ctx, q);
1354bf215546Sopenharmony_ci}
1355bf215546Sopenharmony_ci
1356bf215546Sopenharmony_ci
1357bf215546Sopenharmony_ci/**
1358bf215546Sopenharmony_ci * Free the context state related to query objects.
1359bf215546Sopenharmony_ci */
1360bf215546Sopenharmony_civoid
1361bf215546Sopenharmony_ci_mesa_free_queryobj_data(struct gl_context *ctx)
1362bf215546Sopenharmony_ci{
1363bf215546Sopenharmony_ci   _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
1364bf215546Sopenharmony_ci   _mesa_DeleteHashTable(ctx->Query.QueryObjects);
1365bf215546Sopenharmony_ci}
1366