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