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.
93 * Delete an occlusion query object.
94 * Not removed from hash table here.
95 * XXX maybe add Delete() method to gl_query_object class and call that instead
98 _mesa_delete_query(GLcontext
*ctx
, struct gl_query_object
*q
)
104 static struct gl_query_object
*
105 lookup_query_object(GLcontext
*ctx
, GLuint id
)
107 return (struct gl_query_object
*)
108 _mesa_HashLookup(ctx
->Query
.QueryObjects
, id
);
114 _mesa_GenQueriesARB(GLsizei n
, GLuint
*ids
)
117 GET_CURRENT_CONTEXT(ctx
);
118 ASSERT_OUTSIDE_BEGIN_END(ctx
);
121 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenQueriesARB(n < 0)");
125 /* No query objects can be active at this time! */
126 if (ctx
->Query
.CurrentOcclusionObject
||
127 ctx
->Query
.CurrentTimerObject
) {
128 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGenQueriesARB");
132 first
= _mesa_HashFindFreeKeyBlock(ctx
->Query
.QueryObjects
, n
);
135 for (i
= 0; i
< n
; i
++) {
136 struct gl_query_object
*q
137 = ctx
->Driver
.NewQueryObject(ctx
, first
+ i
);
139 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenQueriesARB");
143 _mesa_HashInsert(ctx
->Query
.QueryObjects
, first
+ i
, q
);
150 _mesa_DeleteQueriesARB(GLsizei n
, const GLuint
*ids
)
153 GET_CURRENT_CONTEXT(ctx
);
154 ASSERT_OUTSIDE_BEGIN_END(ctx
);
157 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteQueriesARB(n < 0)");
161 /* No query objects can be active at this time! */
162 if (ctx
->Query
.CurrentOcclusionObject
||
163 ctx
->Query
.CurrentTimerObject
) {
164 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDeleteQueriesARB");
168 for (i
= 0; i
< n
; i
++) {
170 struct gl_query_object
*q
= lookup_query_object(ctx
, ids
[i
]);
172 ASSERT(!q
->Active
); /* should be caught earlier */
173 _mesa_HashRemove(ctx
->Query
.QueryObjects
, ids
[i
]);
174 ctx
->Driver
.DeleteQuery(ctx
, q
);
182 _mesa_IsQueryARB(GLuint id
)
184 GET_CURRENT_CONTEXT(ctx
);
185 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
187 if (id
&& lookup_query_object(ctx
, id
))
195 _mesa_BeginQueryARB(GLenum target
, GLuint id
)
197 struct gl_query_object
*q
;
198 GET_CURRENT_CONTEXT(ctx
);
199 ASSERT_OUTSIDE_BEGIN_END(ctx
);
201 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
204 case GL_SAMPLES_PASSED_ARB
:
205 if (!ctx
->Extensions
.ARB_occlusion_query
) {
206 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
209 if (ctx
->Query
.CurrentOcclusionObject
) {
210 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
214 #if FEATURE_EXT_timer_query
215 case GL_TIME_ELAPSED_EXT
:
216 if (!ctx
->Extensions
.EXT_timer_query
) {
217 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
220 if (ctx
->Query
.CurrentTimerObject
) {
221 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
227 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
232 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB(id==0)");
236 q
= lookup_query_object(ctx
, id
);
238 /* create new object */
239 q
= ctx
->Driver
.NewQueryObject(ctx
, id
);
241 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBeginQueryARB");
244 _mesa_HashInsert(ctx
->Query
.QueryObjects
, id
, q
);
247 /* pre-existing object */
249 _mesa_error(ctx
, GL_INVALID_OPERATION
,
250 "glBeginQueryARB(query already active)");
260 if (target
== GL_SAMPLES_PASSED_ARB
) {
261 ctx
->Query
.CurrentOcclusionObject
= q
;
263 #if FEATURE_EXT_timer_query
264 else if (target
== GL_TIME_ELAPSED_EXT
) {
265 ctx
->Query
.CurrentTimerObject
= q
;
269 ctx
->Driver
.BeginQuery(ctx
, q
);
274 _mesa_EndQueryARB(GLenum target
)
276 struct gl_query_object
*q
;
277 GET_CURRENT_CONTEXT(ctx
);
278 ASSERT_OUTSIDE_BEGIN_END(ctx
);
280 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
283 case GL_SAMPLES_PASSED_ARB
:
284 if (!ctx
->Extensions
.ARB_occlusion_query
) {
285 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
288 q
= ctx
->Query
.CurrentOcclusionObject
;
289 ctx
->Query
.CurrentOcclusionObject
= NULL
;
291 #if FEATURE_EXT_timer_query
292 case GL_TIME_ELAPSED_EXT
:
293 if (!ctx
->Extensions
.EXT_timer_query
) {
294 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
297 q
= ctx
->Query
.CurrentTimerObject
;
298 ctx
->Query
.CurrentTimerObject
= NULL
;
302 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
306 if (!q
|| !q
->Active
) {
307 _mesa_error(ctx
, GL_INVALID_OPERATION
,
308 "glEndQueryARB(no matching glBeginQueryARB)");
312 q
->Active
= GL_FALSE
;
313 ctx
->Driver
.EndQuery(ctx
, q
);
318 _mesa_GetQueryivARB(GLenum target
, GLenum pname
, GLint
*params
)
320 struct gl_query_object
*q
;
321 GET_CURRENT_CONTEXT(ctx
);
322 ASSERT_OUTSIDE_BEGIN_END(ctx
);
325 case GL_SAMPLES_PASSED_ARB
:
326 if (!ctx
->Extensions
.ARB_occlusion_query
) {
327 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
330 q
= ctx
->Query
.CurrentOcclusionObject
;
332 #if FEATURE_EXT_timer_query
333 case GL_TIME_ELAPSED_EXT
:
334 if (!ctx
->Extensions
.EXT_timer_query
) {
335 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
338 q
= ctx
->Query
.CurrentTimerObject
;
342 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(target)");
347 case GL_QUERY_COUNTER_BITS_ARB
:
348 *params
= 8 * sizeof(q
->Result
);
350 case GL_CURRENT_QUERY_ARB
:
351 *params
= q
? q
->Id
: 0;
354 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(pname)");
361 _mesa_GetQueryObjectivARB(GLuint id
, GLenum pname
, GLint
*params
)
363 struct gl_query_object
*q
= NULL
;
364 GET_CURRENT_CONTEXT(ctx
);
365 ASSERT_OUTSIDE_BEGIN_END(ctx
);
368 q
= lookup_query_object(ctx
, id
);
370 if (!q
|| q
->Active
) {
371 _mesa_error(ctx
, GL_INVALID_OPERATION
,
372 "glGetQueryObjectivARB(id=%d is invalid or active)", id
);
377 case GL_QUERY_RESULT_ARB
:
379 ctx
->Driver
.WaitQuery(ctx
, q
);
380 /* if result is too large for returned type, clamp to max value */
381 if (q
->Result
> 0x7fffffff) {
382 *params
= 0x7fffffff;
385 *params
= (GLint
)q
->Result
;
388 case GL_QUERY_RESULT_AVAILABLE_ARB
:
390 ctx
->Driver
.CheckQuery( ctx
, q
);
394 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectivARB(pname)");
401 _mesa_GetQueryObjectuivARB(GLuint id
, GLenum pname
, GLuint
*params
)
403 struct gl_query_object
*q
= NULL
;
404 GET_CURRENT_CONTEXT(ctx
);
405 ASSERT_OUTSIDE_BEGIN_END(ctx
);
408 q
= lookup_query_object(ctx
, id
);
410 if (!q
|| q
->Active
) {
411 _mesa_error(ctx
, GL_INVALID_OPERATION
,
412 "glGetQueryObjectuivARB(id=%d is invalid or active)", id
);
417 case GL_QUERY_RESULT_ARB
:
419 ctx
->Driver
.WaitQuery(ctx
, q
);
420 /* if result is too large for returned type, clamp to max value */
421 if (q
->Result
> 0xffffffff) {
422 *params
= 0xffffffff;
425 *params
= (GLuint
)q
->Result
;
428 case GL_QUERY_RESULT_AVAILABLE_ARB
:
430 ctx
->Driver
.CheckQuery( ctx
, q
);
434 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectuivARB(pname)");
440 #if FEATURE_EXT_timer_query
443 * New with GL_EXT_timer_query
446 _mesa_GetQueryObjecti64vEXT(GLuint id
, GLenum pname
, GLint64EXT
*params
)
448 struct gl_query_object
*q
= NULL
;
449 GET_CURRENT_CONTEXT(ctx
);
450 ASSERT_OUTSIDE_BEGIN_END(ctx
);
453 q
= lookup_query_object(ctx
, id
);
455 if (!q
|| q
->Active
) {
456 _mesa_error(ctx
, GL_INVALID_OPERATION
,
457 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id
);
462 case GL_QUERY_RESULT_ARB
:
464 ctx
->Driver
.WaitQuery(ctx
, q
);
467 case GL_QUERY_RESULT_AVAILABLE_ARB
:
469 ctx
->Driver
.CheckQuery( ctx
, q
);
473 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjecti64vARB(pname)");
480 * New with GL_EXT_timer_query
483 _mesa_GetQueryObjectui64vEXT(GLuint id
, GLenum pname
, GLuint64EXT
*params
)
485 struct gl_query_object
*q
= NULL
;
486 GET_CURRENT_CONTEXT(ctx
);
487 ASSERT_OUTSIDE_BEGIN_END(ctx
);
490 q
= lookup_query_object(ctx
, id
);
492 if (!q
|| q
->Active
) {
493 _mesa_error(ctx
, GL_INVALID_OPERATION
,
494 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id
);
499 case GL_QUERY_RESULT_ARB
:
501 ctx
->Driver
.WaitQuery(ctx
, q
);
504 case GL_QUERY_RESULT_AVAILABLE_ARB
:
506 ctx
->Driver
.CheckQuery( ctx
, q
);
510 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectui64vARB(pname)");
515 #endif /* FEATURE_EXT_timer_query */
519 * Allocate/init the context state related to query objects.
522 _mesa_init_query(GLcontext
*ctx
)
524 #if FEATURE_ARB_occlusion_query
525 ctx
->Query
.QueryObjects
= _mesa_NewHashTable();
526 ctx
->Query
.CurrentOcclusionObject
= NULL
;
532 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
535 delete_queryobj_cb(GLuint id
, void *data
, void *userData
)
537 struct gl_query_object
*q
= (struct gl_query_object
*) data
;
538 GLcontext
*ctx
= (GLcontext
*)userData
;
539 ctx
->Driver
.DeleteQuery(ctx
, q
);
544 * Free the context state related to query objects.
547 _mesa_free_query_data(GLcontext
*ctx
)
549 _mesa_HashDeleteAll(ctx
->Query
.QueryObjects
, delete_queryobj_cb
, NULL
);
550 _mesa_DeleteHashTable(ctx
->Query
.QueryObjects
);