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