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