1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.1
4  *
5  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation
10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11  * and/or sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included
15  * in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 
26 #include "glheader.h"
27 #include "context.h"
28 #include "enums.h"
29 #include "hash.h"
30 #include "imports.h"
31 #include "queryobj.h"
32 #include "mfeatures.h"
33 #include "mtypes.h"
34 #include "main/dispatch.h"
35 
36 
37 #if FEATURE_queryobj
38 
39 
40 /**
41  * Allocate a new query object.  This is a fallback routine called via
42  * ctx->Driver.NewQueryObject().
43  * \param ctx - rendering context
44  * \param id - the new object's ID
45  * \return pointer to new query_object object or NULL if out of memory.
46  */
47 static struct gl_query_object *
_mesa_new_query_object(struct gl_context * ctx,GLuint id)48 _mesa_new_query_object(struct gl_context *ctx, GLuint id)
49 {
50    struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
51    (void) ctx;
52    if (q) {
53       q->Id = id;
54       q->Result = 0;
55       q->Active = GL_FALSE;
56       q->Ready = GL_TRUE;   /* correct, see spec */
57    }
58    return q;
59 }
60 
61 
62 /**
63  * Begin a query.  Software driver fallback.
64  * Called via ctx->Driver.BeginQuery().
65  */
66 static void
_mesa_begin_query(struct gl_context * ctx,struct gl_query_object * q)67 _mesa_begin_query(struct gl_context *ctx, struct gl_query_object *q)
68 {
69    /* no-op */
70 }
71 
72 
73 /**
74  * End a query.  Software driver fallback.
75  * Called via ctx->Driver.EndQuery().
76  */
77 static void
_mesa_end_query(struct gl_context * ctx,struct gl_query_object * q)78 _mesa_end_query(struct gl_context *ctx, struct gl_query_object *q)
79 {
80    q->Ready = GL_TRUE;
81 }
82 
83 
84 /**
85  * Wait for query to complete.  Software driver fallback.
86  * Called via ctx->Driver.WaitQuery().
87  */
88 static void
_mesa_wait_query(struct gl_context * ctx,struct gl_query_object * q)89 _mesa_wait_query(struct gl_context *ctx, struct gl_query_object *q)
90 {
91    /* For software drivers, _mesa_end_query() should have completed the query.
92     * For real hardware, implement a proper WaitQuery() driver function,
93     * which may require issuing a flush.
94     */
95    assert(q->Ready);
96 }
97 
98 
99 /**
100  * Check if a query results are ready.  Software driver fallback.
101  * Called via ctx->Driver.CheckQuery().
102  */
103 static void
_mesa_check_query(struct gl_context * ctx,struct gl_query_object * q)104 _mesa_check_query(struct gl_context *ctx, struct gl_query_object *q)
105 {
106    /* No-op for sw rendering.
107     * HW drivers may need to flush at this time.
108     */
109 }
110 
111 
112 /**
113  * Delete a query object.  Called via ctx->Driver.DeleteQuery().
114  * Not removed from hash table here.
115  */
116 static void
_mesa_delete_query(struct gl_context * ctx,struct gl_query_object * q)117 _mesa_delete_query(struct gl_context *ctx, struct gl_query_object *q)
118 {
119    free(q);
120 }
121 
122 
123 void
_mesa_init_query_object_functions(struct dd_function_table * driver)124 _mesa_init_query_object_functions(struct dd_function_table *driver)
125 {
126    driver->NewQueryObject = _mesa_new_query_object;
127    driver->DeleteQuery = _mesa_delete_query;
128    driver->BeginQuery = _mesa_begin_query;
129    driver->EndQuery = _mesa_end_query;
130    driver->WaitQuery = _mesa_wait_query;
131    driver->CheckQuery = _mesa_check_query;
132 }
133 
134 
135 /**
136  * Return pointer to the query object binding point for the given target.
137  * \return NULL if invalid target, else the address of binding point
138  */
139 static struct gl_query_object **
get_query_binding_point(struct gl_context * ctx,GLenum target)140 get_query_binding_point(struct gl_context *ctx, GLenum target)
141 {
142    switch (target) {
143    case GL_SAMPLES_PASSED_ARB:
144       if (ctx->Extensions.ARB_occlusion_query)
145          return &ctx->Query.CurrentOcclusionObject;
146       else
147          return NULL;
148    case GL_ANY_SAMPLES_PASSED:
149       if (ctx->Extensions.ARB_occlusion_query2)
150          return &ctx->Query.CurrentOcclusionObject;
151       else
152          return NULL;
153    case GL_TIME_ELAPSED_EXT:
154       if (ctx->Extensions.EXT_timer_query)
155          return &ctx->Query.CurrentTimerObject;
156       else
157          return NULL;
158 #if FEATURE_EXT_transform_feedback
159    case GL_PRIMITIVES_GENERATED:
160       if (ctx->Extensions.EXT_transform_feedback)
161          return &ctx->Query.PrimitivesGenerated;
162       else
163          return NULL;
164    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
165       if (ctx->Extensions.EXT_transform_feedback)
166          return &ctx->Query.PrimitivesWritten;
167       else
168          return NULL;
169 #endif
170    default:
171       return NULL;
172    }
173 }
174 
175 
176 static void GLAPIENTRY
_mesa_GenQueriesARB(GLsizei n,GLuint * ids)177 _mesa_GenQueriesARB(GLsizei n, GLuint *ids)
178 {
179    GLuint first;
180    GET_CURRENT_CONTEXT(ctx);
181    ASSERT_OUTSIDE_BEGIN_END(ctx);
182 
183    if (MESA_VERBOSE & VERBOSE_API)
184       _mesa_debug(ctx, "glGenQueries(%d)\n", n);
185 
186    if (n < 0) {
187       _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
188       return;
189    }
190 
191    /* No query objects can be active at this time! */
192    if (ctx->Query.CurrentOcclusionObject ||
193        ctx->Query.CurrentTimerObject) {
194       _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
195       return;
196    }
197 
198    first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
199    if (first) {
200       GLsizei i;
201       for (i = 0; i < n; i++) {
202          struct gl_query_object *q
203             = ctx->Driver.NewQueryObject(ctx, first + i);
204          if (!q) {
205             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
206             return;
207          }
208          ids[i] = first + i;
209          _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
210       }
211    }
212 }
213 
214 
215 static void GLAPIENTRY
_mesa_DeleteQueriesARB(GLsizei n,const GLuint * ids)216 _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
217 {
218    GLint i;
219    GET_CURRENT_CONTEXT(ctx);
220    ASSERT_OUTSIDE_BEGIN_END(ctx);
221    FLUSH_VERTICES(ctx, 0);
222 
223    if (MESA_VERBOSE & VERBOSE_API)
224       _mesa_debug(ctx, "glDeleeteQueries(%d)\n", n);
225 
226    if (n < 0) {
227       _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
228       return;
229    }
230 
231    /* No query objects can be active at this time! */
232    if (ctx->Query.CurrentOcclusionObject ||
233        ctx->Query.CurrentTimerObject) {
234       _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
235       return;
236    }
237 
238    for (i = 0; i < n; i++) {
239       if (ids[i] > 0) {
240          struct gl_query_object *q = _mesa_lookup_query_object(ctx, ids[i]);
241          if (q) {
242             ASSERT(!q->Active); /* should be caught earlier */
243             _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
244             ctx->Driver.DeleteQuery(ctx, q);
245          }
246       }
247    }
248 }
249 
250 
251 static GLboolean GLAPIENTRY
_mesa_IsQueryARB(GLuint id)252 _mesa_IsQueryARB(GLuint id)
253 {
254    GET_CURRENT_CONTEXT(ctx);
255    ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
256 
257    if (MESA_VERBOSE & VERBOSE_API)
258       _mesa_debug(ctx, "glIsQuery(%u)\n", id);
259 
260    if (id && _mesa_lookup_query_object(ctx, id))
261       return GL_TRUE;
262    else
263       return GL_FALSE;
264 }
265 
266 static GLboolean
query_error_check_index(struct gl_context * ctx,GLenum target,GLuint index)267 query_error_check_index(struct gl_context *ctx, GLenum target, GLuint index)
268 {
269    switch (target) {
270    case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
271    case GL_PRIMITIVES_GENERATED:
272       if (index >= ctx->Const.MaxVertexStreams) {
273          _mesa_error(ctx, GL_INVALID_VALUE,
274                      "glBeginQueryIndexed(index>=MaxVertexStreams)");
275          return GL_FALSE;
276       }
277       break;
278    default:
279       if (index > 0) {
280          _mesa_error(ctx, GL_INVALID_VALUE, "glBeginQueryIndexed(index>0)");
281          return GL_FALSE;
282       }
283    }
284    return GL_TRUE;
285 }
286 
287 static void GLAPIENTRY
_mesa_BeginQueryIndexed(GLenum target,GLuint index,GLuint id)288 _mesa_BeginQueryIndexed(GLenum target, GLuint index, GLuint id)
289 {
290    struct gl_query_object *q, **bindpt;
291    GET_CURRENT_CONTEXT(ctx);
292    ASSERT_OUTSIDE_BEGIN_END(ctx);
293 
294    if (MESA_VERBOSE & VERBOSE_API)
295       _mesa_debug(ctx, "glBeginQueryIndexed(%s, %u, %u)\n",
296                   _mesa_lookup_enum_by_nr(target), index, id);
297 
298    if (!query_error_check_index(ctx, target, index))
299       return;
300 
301    FLUSH_VERTICES(ctx, _NEW_DEPTH);
302 
303    bindpt = get_query_binding_point(ctx, target);
304    if (!bindpt) {
305       _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQuery{Indexed}(target)");
306       return;
307    }
308 
309    if (id == 0) {
310       _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQuery{Indexed}(id==0)");
311       return;
312    }
313 
314    q = _mesa_lookup_query_object(ctx, id);
315    if (!q) {
316       if (ctx->API == API_OPENGL_CORE) {
317          _mesa_error(ctx, GL_INVALID_OPERATION,
318                      "glBeginQuery{Indexed}(non-gen name)");
319          return;
320       } else {
321          /* create new object */
322          q = ctx->Driver.NewQueryObject(ctx, id);
323          if (!q) {
324             _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQuery{Indexed}");
325             return;
326          }
327          _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
328       }
329    }
330    else {
331       /* pre-existing object */
332       if (q->Active) {
333          _mesa_error(ctx, GL_INVALID_OPERATION,
334                      "glBeginQuery{Indexed}(query already active)");
335          return;
336       }
337    }
338 
339    q->Target = target;
340    q->Active = GL_TRUE;
341    q->Result = 0;
342    q->Ready = GL_FALSE;
343 
344    /* XXX should probably refcount query objects */
345    *bindpt = q;
346 
347    ctx->Driver.BeginQuery(ctx, q);
348 }
349 
350 
351 static void GLAPIENTRY
_mesa_EndQueryIndexed(GLenum target,GLuint index)352 _mesa_EndQueryIndexed(GLenum target, GLuint index)
353 {
354    struct gl_query_object *q, **bindpt;
355    GET_CURRENT_CONTEXT(ctx);
356    ASSERT_OUTSIDE_BEGIN_END(ctx);
357 
358    if (MESA_VERBOSE & VERBOSE_API)
359       _mesa_debug(ctx, "glEndQueryIndexed(%s, %u)\n",
360                   _mesa_lookup_enum_by_nr(target), index);
361 
362    if (!query_error_check_index(ctx, target, index))
363       return;
364 
365    FLUSH_VERTICES(ctx, _NEW_DEPTH);
366 
367    bindpt = get_query_binding_point(ctx, target);
368    if (!bindpt) {
369       _mesa_error(ctx, GL_INVALID_ENUM, "glEndQuery{Indexed}(target)");
370       return;
371    }
372 
373    /* XXX should probably refcount query objects */
374    q = *bindpt;
375    *bindpt = NULL;
376 
377    if (!q || !q->Active) {
378       _mesa_error(ctx, GL_INVALID_OPERATION,
379                   "glEndQuery{Indexed}(no matching glBeginQuery{Indexed})");
380       return;
381    }
382 
383    q->Active = GL_FALSE;
384    ctx->Driver.EndQuery(ctx, q);
385 }
386 
387 static void GLAPIENTRY
_mesa_BeginQueryARB(GLenum target,GLuint id)388 _mesa_BeginQueryARB(GLenum target, GLuint id)
389 {
390    _mesa_BeginQueryIndexed(target, 0, id);
391 }
392 
393 static void GLAPIENTRY
_mesa_EndQueryARB(GLenum target)394 _mesa_EndQueryARB(GLenum target)
395 {
396    _mesa_EndQueryIndexed(target, 0);
397 }
398 
399 static void GLAPIENTRY
_mesa_QueryCounter(GLuint id,GLenum target)400 _mesa_QueryCounter(GLuint id, GLenum target)
401 {
402    struct gl_query_object *q;
403    GET_CURRENT_CONTEXT(ctx);
404    ASSERT_OUTSIDE_BEGIN_END(ctx);
405 
406    if (MESA_VERBOSE & VERBOSE_API)
407       _mesa_debug(ctx, "glQueryCounter(%u, %s)\n", id,
408                   _mesa_lookup_enum_by_nr(target));
409 
410    /* error checking */
411    if (target != GL_TIMESTAMP) {
412       _mesa_error(ctx, GL_INVALID_ENUM, "glQueryCounter(target)");
413       return;
414    }
415 
416    if (id == 0) {
417       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id==0)");
418       return;
419    }
420 
421    q = _mesa_lookup_query_object(ctx, id);
422    if (!q) {
423       /* XXX the Core profile should throw INVALID_OPERATION here */
424 
425       /* create new object */
426       q = ctx->Driver.NewQueryObject(ctx, id);
427       if (!q) {
428          _mesa_error(ctx, GL_OUT_OF_MEMORY, "glQueryCounter");
429          return;
430       }
431       _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
432    }
433    else {
434       if (q->Target && q->Target != GL_TIMESTAMP) {
435          _mesa_error(ctx, GL_INVALID_OPERATION,
436                      "glQueryCounter(id has an invalid target)");
437          return;
438       }
439    }
440 
441    if (q->Active) {
442       _mesa_error(ctx, GL_INVALID_OPERATION, "glQueryCounter(id is active)");
443       return;
444    }
445 
446    q->Target = target;
447    q->Result = 0;
448    q->Ready = GL_FALSE;
449 
450    /* QueryCounter is implemented using EndQuery without BeginQuery
451     * in drivers. This is actually Direct3D and Gallium convention. */
452    ctx->Driver.EndQuery(ctx, q);
453 }
454 
455 
456 static void GLAPIENTRY
_mesa_GetQueryIndexediv(GLenum target,GLuint index,GLenum pname,GLint * params)457 _mesa_GetQueryIndexediv(GLenum target, GLuint index, GLenum pname,
458                         GLint *params)
459 {
460    struct gl_query_object *q = NULL, **bindpt = NULL;
461    GET_CURRENT_CONTEXT(ctx);
462    ASSERT_OUTSIDE_BEGIN_END(ctx);
463 
464    if (MESA_VERBOSE & VERBOSE_API)
465       _mesa_debug(ctx, "glGetQueryIndexediv(%s, %u, %s)\n",
466                   _mesa_lookup_enum_by_nr(target),
467                   index,
468                   _mesa_lookup_enum_by_nr(pname));
469 
470    if (!query_error_check_index(ctx, target, index))
471       return;
472 
473    if (target == GL_TIMESTAMP) {
474       if (!ctx->Extensions.ARB_timer_query) {
475          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryARB(target)");
476          return;
477       }
478    }
479    else {
480       bindpt = get_query_binding_point(ctx, target);
481       if (!bindpt) {
482          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(target)");
483          return;
484       }
485 
486       q = *bindpt;
487    }
488 
489    switch (pname) {
490       case GL_QUERY_COUNTER_BITS_ARB:
491          switch (target) {
492          case GL_SAMPLES_PASSED:
493             *params = ctx->Const.QueryCounterBits.SamplesPassed;
494             break;
495          case GL_ANY_SAMPLES_PASSED:
496             /* The minimum value of this is 1 if it's nonzero, and the value
497              * is only ever GL_TRUE or GL_FALSE, so no sense in reporting more
498              * bits.
499              */
500             *params = 1;
501             break;
502          case GL_TIME_ELAPSED:
503             *params = ctx->Const.QueryCounterBits.TimeElapsed;
504             break;
505          case GL_TIMESTAMP:
506             *params = ctx->Const.QueryCounterBits.Timestamp;
507             break;
508          case GL_PRIMITIVES_GENERATED:
509             *params = ctx->Const.QueryCounterBits.PrimitivesGenerated;
510             break;
511          case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
512             *params = ctx->Const.QueryCounterBits.PrimitivesWritten;
513             break;
514          default:
515             _mesa_problem(ctx,
516                           "Unknown target in glGetQueryIndexediv(target = %s)",
517                           _mesa_lookup_enum_by_nr(target));
518             *params = 0;
519             break;
520          }
521          break;
522       case GL_CURRENT_QUERY_ARB:
523          *params = q ? q->Id : 0;
524          break;
525       default:
526          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQuery{Indexed}iv(pname)");
527          return;
528    }
529 }
530 
531 static void GLAPIENTRY
_mesa_GetQueryivARB(GLenum target,GLenum pname,GLint * params)532 _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
533 {
534    _mesa_GetQueryIndexediv(target, 0, pname, params);
535 }
536 
537 static void GLAPIENTRY
_mesa_GetQueryObjectivARB(GLuint id,GLenum pname,GLint * params)538 _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
539 {
540    struct gl_query_object *q = NULL;
541    GET_CURRENT_CONTEXT(ctx);
542    ASSERT_OUTSIDE_BEGIN_END(ctx);
543 
544    if (MESA_VERBOSE & VERBOSE_API)
545       _mesa_debug(ctx, "glGetQueryObjectiv(%u, %s)\n", id,
546                   _mesa_lookup_enum_by_nr(pname));
547 
548    if (id)
549       q = _mesa_lookup_query_object(ctx, id);
550 
551    if (!q || q->Active) {
552       _mesa_error(ctx, GL_INVALID_OPERATION,
553                   "glGetQueryObjectivARB(id=%d is invalid or active)", id);
554       return;
555    }
556 
557    switch (pname) {
558       case GL_QUERY_RESULT_ARB:
559          if (!q->Ready)
560             ctx->Driver.WaitQuery(ctx, q);
561          /* if result is too large for returned type, clamp to max value */
562          if (q->Target == GL_ANY_SAMPLES_PASSED) {
563             if (q->Result)
564                *params = GL_TRUE;
565             else
566                *params = GL_FALSE;
567          } else {
568             if (q->Result > 0x7fffffff) {
569                *params = 0x7fffffff;
570             }
571             else {
572                *params = (GLint)q->Result;
573             }
574          }
575          break;
576       case GL_QUERY_RESULT_AVAILABLE_ARB:
577 	 if (!q->Ready)
578 	    ctx->Driver.CheckQuery( ctx, q );
579          *params = q->Ready;
580          break;
581       default:
582          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
583          return;
584    }
585 }
586 
587 
588 static void GLAPIENTRY
_mesa_GetQueryObjectuivARB(GLuint id,GLenum pname,GLuint * params)589 _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
590 {
591    struct gl_query_object *q = NULL;
592    GET_CURRENT_CONTEXT(ctx);
593    ASSERT_OUTSIDE_BEGIN_END(ctx);
594 
595    if (MESA_VERBOSE & VERBOSE_API)
596       _mesa_debug(ctx, "glGetQueryObjectuiv(%u, %s)\n", id,
597                   _mesa_lookup_enum_by_nr(pname));
598 
599    if (id)
600       q = _mesa_lookup_query_object(ctx, id);
601 
602    if (!q || q->Active) {
603       _mesa_error(ctx, GL_INVALID_OPERATION,
604                   "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
605       return;
606    }
607 
608    switch (pname) {
609       case GL_QUERY_RESULT_ARB:
610          if (!q->Ready)
611             ctx->Driver.WaitQuery(ctx, q);
612          /* if result is too large for returned type, clamp to max value */
613          if (q->Target == GL_ANY_SAMPLES_PASSED) {
614             if (q->Result)
615                *params = GL_TRUE;
616             else
617                *params = GL_FALSE;
618          } else {
619             if (q->Result > 0xffffffff) {
620                *params = 0xffffffff;
621             }
622             else {
623                *params = (GLuint)q->Result;
624             }
625          }
626          break;
627       case GL_QUERY_RESULT_AVAILABLE_ARB:
628 	 if (!q->Ready)
629 	    ctx->Driver.CheckQuery( ctx, q );
630          *params = q->Ready;
631          break;
632       default:
633          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
634          return;
635    }
636 }
637 
638 
639 /**
640  * New with GL_EXT_timer_query
641  */
642 static void GLAPIENTRY
_mesa_GetQueryObjecti64vEXT(GLuint id,GLenum pname,GLint64EXT * params)643 _mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
644 {
645    struct gl_query_object *q = NULL;
646    GET_CURRENT_CONTEXT(ctx);
647    ASSERT_OUTSIDE_BEGIN_END(ctx);
648 
649    if (MESA_VERBOSE & VERBOSE_API)
650       _mesa_debug(ctx, "glGetQueryObjecti64v(%u, %s)\n", id,
651                   _mesa_lookup_enum_by_nr(pname));
652 
653    if (id)
654       q = _mesa_lookup_query_object(ctx, id);
655 
656    if (!q || q->Active) {
657       _mesa_error(ctx, GL_INVALID_OPERATION,
658                   "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
659       return;
660    }
661 
662    switch (pname) {
663       case GL_QUERY_RESULT_ARB:
664          if (!q->Ready)
665             ctx->Driver.WaitQuery(ctx, q);
666          *params = q->Result;
667          break;
668       case GL_QUERY_RESULT_AVAILABLE_ARB:
669 	 if (!q->Ready)
670 	    ctx->Driver.CheckQuery( ctx, q );
671          *params = q->Ready;
672          break;
673       default:
674          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
675          return;
676    }
677 }
678 
679 
680 /**
681  * New with GL_EXT_timer_query
682  */
683 static void GLAPIENTRY
_mesa_GetQueryObjectui64vEXT(GLuint id,GLenum pname,GLuint64EXT * params)684 _mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
685 {
686    struct gl_query_object *q = NULL;
687    GET_CURRENT_CONTEXT(ctx);
688    ASSERT_OUTSIDE_BEGIN_END(ctx);
689 
690    if (MESA_VERBOSE & VERBOSE_API)
691       _mesa_debug(ctx, "glGetQueryObjectui64v(%u, %s)\n", id,
692                   _mesa_lookup_enum_by_nr(pname));
693 
694    if (id)
695       q = _mesa_lookup_query_object(ctx, id);
696 
697    if (!q || q->Active) {
698       _mesa_error(ctx, GL_INVALID_OPERATION,
699                   "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
700       return;
701    }
702 
703    switch (pname) {
704       case GL_QUERY_RESULT_ARB:
705          if (!q->Ready)
706             ctx->Driver.WaitQuery(ctx, q);
707          *params = q->Result;
708          break;
709       case GL_QUERY_RESULT_AVAILABLE_ARB:
710 	 if (!q->Ready)
711 	    ctx->Driver.CheckQuery( ctx, q );
712          *params = q->Ready;
713          break;
714       default:
715          _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
716          return;
717    }
718 }
719 
720 
721 void
_mesa_init_queryobj_dispatch(struct _glapi_table * disp)722 _mesa_init_queryobj_dispatch(struct _glapi_table *disp)
723 {
724    SET_GenQueriesARB(disp, _mesa_GenQueriesARB);
725    SET_DeleteQueriesARB(disp, _mesa_DeleteQueriesARB);
726    SET_IsQueryARB(disp, _mesa_IsQueryARB);
727    SET_BeginQueryARB(disp, _mesa_BeginQueryARB);
728    SET_EndQueryARB(disp, _mesa_EndQueryARB);
729    SET_GetQueryivARB(disp, _mesa_GetQueryivARB);
730    SET_GetQueryObjectivARB(disp, _mesa_GetQueryObjectivARB);
731    SET_GetQueryObjectuivARB(disp, _mesa_GetQueryObjectuivARB);
732    SET_QueryCounter(disp, _mesa_QueryCounter);
733 
734    SET_GetQueryObjecti64vEXT(disp, _mesa_GetQueryObjecti64vEXT);
735    SET_GetQueryObjectui64vEXT(disp, _mesa_GetQueryObjectui64vEXT);
736 
737    SET_BeginQueryIndexed(disp, _mesa_BeginQueryIndexed);
738    SET_EndQueryIndexed(disp, _mesa_EndQueryIndexed);
739    SET_GetQueryIndexediv(disp, _mesa_GetQueryIndexediv);
740 }
741 
742 
743 #endif /* FEATURE_queryobj */
744 
745 
746 /**
747  * Allocate/init the context state related to query objects.
748  */
749 void
_mesa_init_queryobj(struct gl_context * ctx)750 _mesa_init_queryobj(struct gl_context *ctx)
751 {
752    ctx->Query.QueryObjects = _mesa_NewHashTable();
753    ctx->Query.CurrentOcclusionObject = NULL;
754 
755    ctx->Const.QueryCounterBits.SamplesPassed = 64;
756    ctx->Const.QueryCounterBits.TimeElapsed = 64;
757    ctx->Const.QueryCounterBits.Timestamp = 64;
758    ctx->Const.QueryCounterBits.PrimitivesGenerated = 64;
759    ctx->Const.QueryCounterBits.PrimitivesWritten = 64;
760 }
761 
762 
763 /**
764  * Callback for deleting a query object.  Called by _mesa_HashDeleteAll().
765  */
766 static void
delete_queryobj_cb(GLuint id,void * data,void * userData)767 delete_queryobj_cb(GLuint id, void *data, void *userData)
768 {
769    struct gl_query_object *q= (struct gl_query_object *) data;
770    struct gl_context *ctx = (struct gl_context *)userData;
771    ctx->Driver.DeleteQuery(ctx, q);
772 }
773 
774 
775 /**
776  * Free the context state related to query objects.
777  */
778 void
_mesa_free_queryobj_data(struct gl_context * ctx)779 _mesa_free_queryobj_data(struct gl_context *ctx)
780 {
781    _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, ctx);
782    _mesa_DeleteHashTable(ctx->Query.QueryObjects);
783 }
784