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 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_GenQueriesARB(GLsizei n
, GLuint
*ids
)
130 GET_CURRENT_CONTEXT(ctx
);
131 ASSERT_OUTSIDE_BEGIN_END(ctx
);
134 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenQueriesARB(n < 0)");
138 /* No query objects can be active at this time! */
139 if (ctx
->Query
.CurrentOcclusionObject
||
140 ctx
->Query
.CurrentTimerObject
) {
141 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGenQueriesARB");
145 first
= _mesa_HashFindFreeKeyBlock(ctx
->Query
.QueryObjects
, n
);
148 for (i
= 0; i
< n
; i
++) {
149 struct gl_query_object
*q
150 = ctx
->Driver
.NewQueryObject(ctx
, first
+ i
);
152 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenQueriesARB");
156 _mesa_HashInsert(ctx
->Query
.QueryObjects
, first
+ i
, q
);
163 _mesa_DeleteQueriesARB(GLsizei n
, const GLuint
*ids
)
166 GET_CURRENT_CONTEXT(ctx
);
167 ASSERT_OUTSIDE_BEGIN_END(ctx
);
170 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteQueriesARB(n < 0)");
174 /* No query objects can be active at this time! */
175 if (ctx
->Query
.CurrentOcclusionObject
||
176 ctx
->Query
.CurrentTimerObject
) {
177 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDeleteQueriesARB");
181 for (i
= 0; i
< n
; i
++) {
183 struct gl_query_object
*q
= lookup_query_object(ctx
, ids
[i
]);
185 ASSERT(!q
->Active
); /* should be caught earlier */
186 _mesa_HashRemove(ctx
->Query
.QueryObjects
, ids
[i
]);
187 ctx
->Driver
.DeleteQuery(ctx
, q
);
195 _mesa_IsQueryARB(GLuint id
)
197 GET_CURRENT_CONTEXT(ctx
);
198 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
200 if (id
&& lookup_query_object(ctx
, id
))
208 _mesa_BeginQueryARB(GLenum target
, GLuint id
)
210 struct gl_query_object
*q
;
211 GET_CURRENT_CONTEXT(ctx
);
212 ASSERT_OUTSIDE_BEGIN_END(ctx
);
214 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
217 case GL_SAMPLES_PASSED_ARB
:
218 if (!ctx
->Extensions
.ARB_occlusion_query
) {
219 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
222 if (ctx
->Query
.CurrentOcclusionObject
) {
223 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
227 #if FEATURE_EXT_timer_query
228 case GL_TIME_ELAPSED_EXT
:
229 if (!ctx
->Extensions
.EXT_timer_query
) {
230 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
233 if (ctx
->Query
.CurrentTimerObject
) {
234 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
240 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
245 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB(id==0)");
249 q
= lookup_query_object(ctx
, id
);
251 /* create new object */
252 q
= ctx
->Driver
.NewQueryObject(ctx
, id
);
254 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBeginQueryARB");
257 _mesa_HashInsert(ctx
->Query
.QueryObjects
, id
, q
);
260 /* pre-existing object */
262 _mesa_error(ctx
, GL_INVALID_OPERATION
,
263 "glBeginQueryARB(query already active)");
273 if (target
== GL_SAMPLES_PASSED_ARB
) {
274 ctx
->Query
.CurrentOcclusionObject
= q
;
276 #if FEATURE_EXT_timer_query
277 else if (target
== GL_TIME_ELAPSED_EXT
) {
278 ctx
->Query
.CurrentTimerObject
= q
;
282 ctx
->Driver
.BeginQuery(ctx
, q
);
287 _mesa_EndQueryARB(GLenum target
)
289 struct gl_query_object
*q
;
290 GET_CURRENT_CONTEXT(ctx
);
291 ASSERT_OUTSIDE_BEGIN_END(ctx
);
293 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
296 case GL_SAMPLES_PASSED_ARB
:
297 if (!ctx
->Extensions
.ARB_occlusion_query
) {
298 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
301 q
= ctx
->Query
.CurrentOcclusionObject
;
302 ctx
->Query
.CurrentOcclusionObject
= NULL
;
304 #if FEATURE_EXT_timer_query
305 case GL_TIME_ELAPSED_EXT
:
306 if (!ctx
->Extensions
.EXT_timer_query
) {
307 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
310 q
= ctx
->Query
.CurrentTimerObject
;
311 ctx
->Query
.CurrentTimerObject
= NULL
;
315 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
319 if (!q
|| !q
->Active
) {
320 _mesa_error(ctx
, GL_INVALID_OPERATION
,
321 "glEndQueryARB(no matching glBeginQueryARB)");
325 q
->Active
= GL_FALSE
;
326 ctx
->Driver
.EndQuery(ctx
, q
);
331 _mesa_GetQueryivARB(GLenum target
, GLenum pname
, GLint
*params
)
333 struct gl_query_object
*q
;
334 GET_CURRENT_CONTEXT(ctx
);
335 ASSERT_OUTSIDE_BEGIN_END(ctx
);
338 case GL_SAMPLES_PASSED_ARB
:
339 if (!ctx
->Extensions
.ARB_occlusion_query
) {
340 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
343 q
= ctx
->Query
.CurrentOcclusionObject
;
345 #if FEATURE_EXT_timer_query
346 case GL_TIME_ELAPSED_EXT
:
347 if (!ctx
->Extensions
.EXT_timer_query
) {
348 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
351 q
= ctx
->Query
.CurrentTimerObject
;
355 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(target)");
360 case GL_QUERY_COUNTER_BITS_ARB
:
361 *params
= 8 * sizeof(q
->Result
);
363 case GL_CURRENT_QUERY_ARB
:
364 *params
= q
? q
->Id
: 0;
367 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(pname)");
374 _mesa_GetQueryObjectivARB(GLuint id
, GLenum pname
, GLint
*params
)
376 struct gl_query_object
*q
= NULL
;
377 GET_CURRENT_CONTEXT(ctx
);
378 ASSERT_OUTSIDE_BEGIN_END(ctx
);
381 q
= lookup_query_object(ctx
, id
);
383 if (!q
|| q
->Active
) {
384 _mesa_error(ctx
, GL_INVALID_OPERATION
,
385 "glGetQueryObjectivARB(id=%d is invalid or active)", id
);
390 case GL_QUERY_RESULT_ARB
:
392 ctx
->Driver
.WaitQuery(ctx
, q
);
393 /* if result is too large for returned type, clamp to max value */
394 if (q
->Result
> 0x7fffffff) {
395 *params
= 0x7fffffff;
398 *params
= (GLint
)q
->Result
;
401 case GL_QUERY_RESULT_AVAILABLE_ARB
:
403 ctx
->Driver
.CheckQuery( ctx
, q
);
407 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectivARB(pname)");
414 _mesa_GetQueryObjectuivARB(GLuint id
, GLenum pname
, GLuint
*params
)
416 struct gl_query_object
*q
= NULL
;
417 GET_CURRENT_CONTEXT(ctx
);
418 ASSERT_OUTSIDE_BEGIN_END(ctx
);
421 q
= lookup_query_object(ctx
, id
);
423 if (!q
|| q
->Active
) {
424 _mesa_error(ctx
, GL_INVALID_OPERATION
,
425 "glGetQueryObjectuivARB(id=%d is invalid or active)", id
);
430 case GL_QUERY_RESULT_ARB
:
432 ctx
->Driver
.WaitQuery(ctx
, q
);
433 /* if result is too large for returned type, clamp to max value */
434 if (q
->Result
> 0xffffffff) {
435 *params
= 0xffffffff;
438 *params
= (GLuint
)q
->Result
;
441 case GL_QUERY_RESULT_AVAILABLE_ARB
:
443 ctx
->Driver
.CheckQuery( ctx
, q
);
447 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectuivARB(pname)");
453 #if FEATURE_EXT_timer_query
456 * New with GL_EXT_timer_query
459 _mesa_GetQueryObjecti64vEXT(GLuint id
, GLenum pname
, GLint64EXT
*params
)
461 struct gl_query_object
*q
= NULL
;
462 GET_CURRENT_CONTEXT(ctx
);
463 ASSERT_OUTSIDE_BEGIN_END(ctx
);
466 q
= lookup_query_object(ctx
, id
);
468 if (!q
|| q
->Active
) {
469 _mesa_error(ctx
, GL_INVALID_OPERATION
,
470 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id
);
475 case GL_QUERY_RESULT_ARB
:
477 ctx
->Driver
.WaitQuery(ctx
, q
);
480 case GL_QUERY_RESULT_AVAILABLE_ARB
:
482 ctx
->Driver
.CheckQuery( ctx
, q
);
486 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjecti64vARB(pname)");
493 * New with GL_EXT_timer_query
496 _mesa_GetQueryObjectui64vEXT(GLuint id
, GLenum pname
, GLuint64EXT
*params
)
498 struct gl_query_object
*q
= NULL
;
499 GET_CURRENT_CONTEXT(ctx
);
500 ASSERT_OUTSIDE_BEGIN_END(ctx
);
503 q
= lookup_query_object(ctx
, id
);
505 if (!q
|| q
->Active
) {
506 _mesa_error(ctx
, GL_INVALID_OPERATION
,
507 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id
);
512 case GL_QUERY_RESULT_ARB
:
514 ctx
->Driver
.WaitQuery(ctx
, q
);
517 case GL_QUERY_RESULT_AVAILABLE_ARB
:
519 ctx
->Driver
.CheckQuery( ctx
, q
);
523 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectui64vARB(pname)");
528 #endif /* FEATURE_EXT_timer_query */
532 * Allocate/init the context state related to query objects.
535 _mesa_init_query(GLcontext
*ctx
)
537 #if FEATURE_ARB_occlusion_query
538 ctx
->Query
.QueryObjects
= _mesa_NewHashTable();
539 ctx
->Query
.CurrentOcclusionObject
= NULL
;
545 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
548 delete_queryobj_cb(GLuint id
, void *data
, void *userData
)
550 struct gl_query_object
*q
= (struct gl_query_object
*) data
;
551 GLcontext
*ctx
= (GLcontext
*)userData
;
552 ctx
->Driver
.DeleteQuery(ctx
, q
);
557 * Free the context state related to query objects.
560 _mesa_free_query_data(GLcontext
*ctx
)
562 _mesa_HashDeleteAll(ctx
->Query
.QueryObjects
, delete_queryobj_cb
, ctx
);
563 _mesa_DeleteHashTable(ctx
->Query
.QueryObjects
);