2 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
35 * Allocate a new query object. This is a fallback routine called via
36 * ctx->Driver.NewQueryObject().
37 * \param ctx - rendering context
38 * \param id - the new object's ID
39 * \return pointer to new query_object object or NULL if out of memory.
41 static struct gl_query_object
*
42 _mesa_new_query_object(GLcontext
*ctx
, GLuint id
)
44 struct gl_query_object
*q
= MALLOC_STRUCT(gl_query_object
);
50 q
->Ready
= GL_TRUE
; /* correct, see spec */
57 * Begin a query. Software driver fallback.
58 * Called via ctx->Driver.BeginQuery().
61 _mesa_begin_query(GLcontext
*ctx
, struct gl_query_object
*q
)
68 * End a query. Software driver fallback.
69 * Called via ctx->Driver.EndQuery().
72 _mesa_end_query(GLcontext
*ctx
, struct gl_query_object
*q
)
79 * Wait for query to complete. Software driver fallback.
80 * Called via ctx->Driver.WaitQuery().
83 _mesa_wait_query(GLcontext
*ctx
, struct gl_query_object
*q
)
85 /* For software drivers, _mesa_end_query() should have completed the query.
86 * For real hardware, implement a proper WaitQuery() driver function,
87 * which may require issuing a flush.
94 * Check if a query results are ready. Software driver fallback.
95 * Called via ctx->Driver.CheckQuery().
98 _mesa_check_query(GLcontext
*ctx
, struct gl_query_object
*q
)
100 /* No-op for sw rendering.
101 * HW drivers may need to flush at this time.
107 * Delete a query object. Called via ctx->Driver.DeleteQuery().
108 * Not removed from hash table here.
111 _mesa_delete_query(GLcontext
*ctx
, struct gl_query_object
*q
)
117 static struct gl_query_object
*
118 lookup_query_object(GLcontext
*ctx
, GLuint id
)
120 return (struct gl_query_object
*)
121 _mesa_HashLookup(ctx
->Query
.QueryObjects
, id
);
127 _mesa_init_query_object_functions(struct dd_function_table
*driver
)
129 driver
->NewQueryObject
= _mesa_new_query_object
;
130 driver
->DeleteQuery
= _mesa_delete_query
;
131 driver
->BeginQuery
= _mesa_begin_query
;
132 driver
->EndQuery
= _mesa_end_query
;
133 driver
->WaitQuery
= _mesa_wait_query
;
134 driver
->CheckQuery
= _mesa_check_query
;
139 _mesa_GenQueriesARB(GLsizei n
, GLuint
*ids
)
142 GET_CURRENT_CONTEXT(ctx
);
143 ASSERT_OUTSIDE_BEGIN_END(ctx
);
146 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenQueriesARB(n < 0)");
150 /* No query objects can be active at this time! */
151 if (ctx
->Query
.CurrentOcclusionObject
||
152 ctx
->Query
.CurrentTimerObject
) {
153 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGenQueriesARB");
157 first
= _mesa_HashFindFreeKeyBlock(ctx
->Query
.QueryObjects
, n
);
160 for (i
= 0; i
< n
; i
++) {
161 struct gl_query_object
*q
162 = ctx
->Driver
.NewQueryObject(ctx
, first
+ i
);
164 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenQueriesARB");
168 _mesa_HashInsert(ctx
->Query
.QueryObjects
, first
+ i
, q
);
175 _mesa_DeleteQueriesARB(GLsizei n
, const GLuint
*ids
)
178 GET_CURRENT_CONTEXT(ctx
);
179 ASSERT_OUTSIDE_BEGIN_END(ctx
);
182 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteQueriesARB(n < 0)");
186 /* No query objects can be active at this time! */
187 if (ctx
->Query
.CurrentOcclusionObject
||
188 ctx
->Query
.CurrentTimerObject
) {
189 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDeleteQueriesARB");
193 for (i
= 0; i
< n
; i
++) {
195 struct gl_query_object
*q
= lookup_query_object(ctx
, ids
[i
]);
197 ASSERT(!q
->Active
); /* should be caught earlier */
198 _mesa_HashRemove(ctx
->Query
.QueryObjects
, ids
[i
]);
199 ctx
->Driver
.DeleteQuery(ctx
, q
);
207 _mesa_IsQueryARB(GLuint id
)
209 GET_CURRENT_CONTEXT(ctx
);
210 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
212 if (id
&& lookup_query_object(ctx
, id
))
220 _mesa_BeginQueryARB(GLenum target
, GLuint id
)
222 struct gl_query_object
*q
;
223 GET_CURRENT_CONTEXT(ctx
);
224 ASSERT_OUTSIDE_BEGIN_END(ctx
);
226 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
229 case GL_SAMPLES_PASSED_ARB
:
230 if (!ctx
->Extensions
.ARB_occlusion_query
) {
231 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
234 if (ctx
->Query
.CurrentOcclusionObject
) {
235 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
239 #if FEATURE_EXT_timer_query
240 case GL_TIME_ELAPSED_EXT
:
241 if (!ctx
->Extensions
.EXT_timer_query
) {
242 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
245 if (ctx
->Query
.CurrentTimerObject
) {
246 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
252 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
257 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB(id==0)");
261 q
= lookup_query_object(ctx
, id
);
263 /* create new object */
264 q
= ctx
->Driver
.NewQueryObject(ctx
, id
);
266 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBeginQueryARB");
269 _mesa_HashInsert(ctx
->Query
.QueryObjects
, id
, q
);
272 /* pre-existing object */
274 _mesa_error(ctx
, GL_INVALID_OPERATION
,
275 "glBeginQueryARB(query already active)");
285 if (target
== GL_SAMPLES_PASSED_ARB
) {
286 ctx
->Query
.CurrentOcclusionObject
= q
;
288 #if FEATURE_EXT_timer_query
289 else if (target
== GL_TIME_ELAPSED_EXT
) {
290 ctx
->Query
.CurrentTimerObject
= q
;
294 ctx
->Driver
.BeginQuery(ctx
, q
);
299 _mesa_EndQueryARB(GLenum target
)
301 struct gl_query_object
*q
;
302 GET_CURRENT_CONTEXT(ctx
);
303 ASSERT_OUTSIDE_BEGIN_END(ctx
);
305 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
308 case GL_SAMPLES_PASSED_ARB
:
309 if (!ctx
->Extensions
.ARB_occlusion_query
) {
310 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
313 q
= ctx
->Query
.CurrentOcclusionObject
;
314 ctx
->Query
.CurrentOcclusionObject
= NULL
;
316 #if FEATURE_EXT_timer_query
317 case GL_TIME_ELAPSED_EXT
:
318 if (!ctx
->Extensions
.EXT_timer_query
) {
319 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
322 q
= ctx
->Query
.CurrentTimerObject
;
323 ctx
->Query
.CurrentTimerObject
= NULL
;
327 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
331 if (!q
|| !q
->Active
) {
332 _mesa_error(ctx
, GL_INVALID_OPERATION
,
333 "glEndQueryARB(no matching glBeginQueryARB)");
337 q
->Active
= GL_FALSE
;
338 ctx
->Driver
.EndQuery(ctx
, q
);
343 _mesa_GetQueryivARB(GLenum target
, GLenum pname
, GLint
*params
)
345 struct gl_query_object
*q
;
346 GET_CURRENT_CONTEXT(ctx
);
347 ASSERT_OUTSIDE_BEGIN_END(ctx
);
350 case GL_SAMPLES_PASSED_ARB
:
351 if (!ctx
->Extensions
.ARB_occlusion_query
) {
352 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
355 q
= ctx
->Query
.CurrentOcclusionObject
;
357 #if FEATURE_EXT_timer_query
358 case GL_TIME_ELAPSED_EXT
:
359 if (!ctx
->Extensions
.EXT_timer_query
) {
360 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
363 q
= ctx
->Query
.CurrentTimerObject
;
367 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(target)");
372 case GL_QUERY_COUNTER_BITS_ARB
:
373 *params
= 8 * sizeof(q
->Result
);
375 case GL_CURRENT_QUERY_ARB
:
376 *params
= q
? q
->Id
: 0;
379 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(pname)");
386 _mesa_GetQueryObjectivARB(GLuint id
, GLenum pname
, GLint
*params
)
388 struct gl_query_object
*q
= NULL
;
389 GET_CURRENT_CONTEXT(ctx
);
390 ASSERT_OUTSIDE_BEGIN_END(ctx
);
393 q
= lookup_query_object(ctx
, id
);
395 if (!q
|| q
->Active
) {
396 _mesa_error(ctx
, GL_INVALID_OPERATION
,
397 "glGetQueryObjectivARB(id=%d is invalid or active)", id
);
402 case GL_QUERY_RESULT_ARB
:
404 ctx
->Driver
.WaitQuery(ctx
, q
);
405 /* if result is too large for returned type, clamp to max value */
406 if (q
->Result
> 0x7fffffff) {
407 *params
= 0x7fffffff;
410 *params
= (GLint
)q
->Result
;
413 case GL_QUERY_RESULT_AVAILABLE_ARB
:
415 ctx
->Driver
.CheckQuery( ctx
, q
);
419 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectivARB(pname)");
426 _mesa_GetQueryObjectuivARB(GLuint id
, GLenum pname
, GLuint
*params
)
428 struct gl_query_object
*q
= NULL
;
429 GET_CURRENT_CONTEXT(ctx
);
430 ASSERT_OUTSIDE_BEGIN_END(ctx
);
433 q
= lookup_query_object(ctx
, id
);
435 if (!q
|| q
->Active
) {
436 _mesa_error(ctx
, GL_INVALID_OPERATION
,
437 "glGetQueryObjectuivARB(id=%d is invalid or active)", id
);
442 case GL_QUERY_RESULT_ARB
:
444 ctx
->Driver
.WaitQuery(ctx
, q
);
445 /* if result is too large for returned type, clamp to max value */
446 if (q
->Result
> 0xffffffff) {
447 *params
= 0xffffffff;
450 *params
= (GLuint
)q
->Result
;
453 case GL_QUERY_RESULT_AVAILABLE_ARB
:
455 ctx
->Driver
.CheckQuery( ctx
, q
);
459 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectuivARB(pname)");
465 #if FEATURE_EXT_timer_query
468 * New with GL_EXT_timer_query
471 _mesa_GetQueryObjecti64vEXT(GLuint id
, GLenum pname
, GLint64EXT
*params
)
473 struct gl_query_object
*q
= NULL
;
474 GET_CURRENT_CONTEXT(ctx
);
475 ASSERT_OUTSIDE_BEGIN_END(ctx
);
478 q
= lookup_query_object(ctx
, id
);
480 if (!q
|| q
->Active
) {
481 _mesa_error(ctx
, GL_INVALID_OPERATION
,
482 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id
);
487 case GL_QUERY_RESULT_ARB
:
489 ctx
->Driver
.WaitQuery(ctx
, q
);
492 case GL_QUERY_RESULT_AVAILABLE_ARB
:
494 ctx
->Driver
.CheckQuery( ctx
, q
);
498 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjecti64vARB(pname)");
505 * New with GL_EXT_timer_query
508 _mesa_GetQueryObjectui64vEXT(GLuint id
, GLenum pname
, GLuint64EXT
*params
)
510 struct gl_query_object
*q
= NULL
;
511 GET_CURRENT_CONTEXT(ctx
);
512 ASSERT_OUTSIDE_BEGIN_END(ctx
);
515 q
= lookup_query_object(ctx
, id
);
517 if (!q
|| q
->Active
) {
518 _mesa_error(ctx
, GL_INVALID_OPERATION
,
519 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id
);
524 case GL_QUERY_RESULT_ARB
:
526 ctx
->Driver
.WaitQuery(ctx
, q
);
529 case GL_QUERY_RESULT_AVAILABLE_ARB
:
531 ctx
->Driver
.CheckQuery( ctx
, q
);
535 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectui64vARB(pname)");
540 #endif /* FEATURE_EXT_timer_query */
544 * Allocate/init the context state related to query objects.
547 _mesa_init_query(GLcontext
*ctx
)
549 #if FEATURE_ARB_occlusion_query
550 ctx
->Query
.QueryObjects
= _mesa_NewHashTable();
551 ctx
->Query
.CurrentOcclusionObject
= NULL
;
557 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
560 delete_queryobj_cb(GLuint id
, void *data
, void *userData
)
562 struct gl_query_object
*q
= (struct gl_query_object
*) data
;
563 GLcontext
*ctx
= (GLcontext
*)userData
;
564 ctx
->Driver
.DeleteQuery(ctx
, q
);
569 * Free the context state related to query objects.
572 _mesa_free_query_data(GLcontext
*ctx
)
574 _mesa_HashDeleteAll(ctx
->Query
.QueryObjects
, delete_queryobj_cb
, ctx
);
575 _mesa_DeleteHashTable(ctx
->Query
.QueryObjects
);