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 a query object. Called via ctx->Driver.DeleteQuery().
94 * Not removed from hash table here.
97 _mesa_delete_query(GLcontext
*ctx
, struct gl_query_object
*q
)
103 static struct gl_query_object
*
104 lookup_query_object(GLcontext
*ctx
, GLuint id
)
106 return (struct gl_query_object
*)
107 _mesa_HashLookup(ctx
->Query
.QueryObjects
, id
);
113 _mesa_GenQueriesARB(GLsizei n
, GLuint
*ids
)
116 GET_CURRENT_CONTEXT(ctx
);
117 ASSERT_OUTSIDE_BEGIN_END(ctx
);
120 _mesa_error(ctx
, GL_INVALID_VALUE
, "glGenQueriesARB(n < 0)");
124 /* No query objects can be active at this time! */
125 if (ctx
->Query
.CurrentOcclusionObject
||
126 ctx
->Query
.CurrentTimerObject
) {
127 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glGenQueriesARB");
131 first
= _mesa_HashFindFreeKeyBlock(ctx
->Query
.QueryObjects
, n
);
134 for (i
= 0; i
< n
; i
++) {
135 struct gl_query_object
*q
136 = ctx
->Driver
.NewQueryObject(ctx
, first
+ i
);
138 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glGenQueriesARB");
142 _mesa_HashInsert(ctx
->Query
.QueryObjects
, first
+ i
, q
);
149 _mesa_DeleteQueriesARB(GLsizei n
, const GLuint
*ids
)
152 GET_CURRENT_CONTEXT(ctx
);
153 ASSERT_OUTSIDE_BEGIN_END(ctx
);
156 _mesa_error(ctx
, GL_INVALID_VALUE
, "glDeleteQueriesARB(n < 0)");
160 /* No query objects can be active at this time! */
161 if (ctx
->Query
.CurrentOcclusionObject
||
162 ctx
->Query
.CurrentTimerObject
) {
163 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glDeleteQueriesARB");
167 for (i
= 0; i
< n
; i
++) {
169 struct gl_query_object
*q
= lookup_query_object(ctx
, ids
[i
]);
171 ASSERT(!q
->Active
); /* should be caught earlier */
172 _mesa_HashRemove(ctx
->Query
.QueryObjects
, ids
[i
]);
173 ctx
->Driver
.DeleteQuery(ctx
, q
);
181 _mesa_IsQueryARB(GLuint id
)
183 GET_CURRENT_CONTEXT(ctx
);
184 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx
, GL_FALSE
);
186 if (id
&& lookup_query_object(ctx
, id
))
194 _mesa_BeginQueryARB(GLenum target
, GLuint id
)
196 struct gl_query_object
*q
;
197 GET_CURRENT_CONTEXT(ctx
);
198 ASSERT_OUTSIDE_BEGIN_END(ctx
);
200 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
203 case GL_SAMPLES_PASSED_ARB
:
204 if (!ctx
->Extensions
.ARB_occlusion_query
) {
205 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
208 if (ctx
->Query
.CurrentOcclusionObject
) {
209 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
213 #if FEATURE_EXT_timer_query
214 case GL_TIME_ELAPSED_EXT
:
215 if (!ctx
->Extensions
.EXT_timer_query
) {
216 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
219 if (ctx
->Query
.CurrentTimerObject
) {
220 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB");
226 _mesa_error(ctx
, GL_INVALID_ENUM
, "glBeginQueryARB(target)");
231 _mesa_error(ctx
, GL_INVALID_OPERATION
, "glBeginQueryARB(id==0)");
235 q
= lookup_query_object(ctx
, id
);
237 /* create new object */
238 q
= ctx
->Driver
.NewQueryObject(ctx
, id
);
240 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glBeginQueryARB");
243 _mesa_HashInsert(ctx
->Query
.QueryObjects
, id
, q
);
246 /* pre-existing object */
248 _mesa_error(ctx
, GL_INVALID_OPERATION
,
249 "glBeginQueryARB(query already active)");
259 if (target
== GL_SAMPLES_PASSED_ARB
) {
260 ctx
->Query
.CurrentOcclusionObject
= q
;
262 #if FEATURE_EXT_timer_query
263 else if (target
== GL_TIME_ELAPSED_EXT
) {
264 ctx
->Query
.CurrentTimerObject
= q
;
268 ctx
->Driver
.BeginQuery(ctx
, q
);
273 _mesa_EndQueryARB(GLenum target
)
275 struct gl_query_object
*q
;
276 GET_CURRENT_CONTEXT(ctx
);
277 ASSERT_OUTSIDE_BEGIN_END(ctx
);
279 FLUSH_VERTICES(ctx
, _NEW_DEPTH
);
282 case GL_SAMPLES_PASSED_ARB
:
283 if (!ctx
->Extensions
.ARB_occlusion_query
) {
284 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
287 q
= ctx
->Query
.CurrentOcclusionObject
;
288 ctx
->Query
.CurrentOcclusionObject
= NULL
;
290 #if FEATURE_EXT_timer_query
291 case GL_TIME_ELAPSED_EXT
:
292 if (!ctx
->Extensions
.EXT_timer_query
) {
293 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
296 q
= ctx
->Query
.CurrentTimerObject
;
297 ctx
->Query
.CurrentTimerObject
= NULL
;
301 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
305 if (!q
|| !q
->Active
) {
306 _mesa_error(ctx
, GL_INVALID_OPERATION
,
307 "glEndQueryARB(no matching glBeginQueryARB)");
311 q
->Active
= GL_FALSE
;
312 ctx
->Driver
.EndQuery(ctx
, q
);
317 _mesa_GetQueryivARB(GLenum target
, GLenum pname
, GLint
*params
)
319 struct gl_query_object
*q
;
320 GET_CURRENT_CONTEXT(ctx
);
321 ASSERT_OUTSIDE_BEGIN_END(ctx
);
324 case GL_SAMPLES_PASSED_ARB
:
325 if (!ctx
->Extensions
.ARB_occlusion_query
) {
326 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
329 q
= ctx
->Query
.CurrentOcclusionObject
;
331 #if FEATURE_EXT_timer_query
332 case GL_TIME_ELAPSED_EXT
:
333 if (!ctx
->Extensions
.EXT_timer_query
) {
334 _mesa_error(ctx
, GL_INVALID_ENUM
, "glEndQueryARB(target)");
337 q
= ctx
->Query
.CurrentTimerObject
;
341 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(target)");
346 case GL_QUERY_COUNTER_BITS_ARB
:
347 *params
= 8 * sizeof(q
->Result
);
349 case GL_CURRENT_QUERY_ARB
:
350 *params
= q
? q
->Id
: 0;
353 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryivARB(pname)");
360 _mesa_GetQueryObjectivARB(GLuint id
, GLenum pname
, GLint
*params
)
362 struct gl_query_object
*q
= NULL
;
363 GET_CURRENT_CONTEXT(ctx
);
364 ASSERT_OUTSIDE_BEGIN_END(ctx
);
367 q
= lookup_query_object(ctx
, id
);
369 if (!q
|| q
->Active
) {
370 _mesa_error(ctx
, GL_INVALID_OPERATION
,
371 "glGetQueryObjectivARB(id=%d is invalid or active)", id
);
376 case GL_QUERY_RESULT_ARB
:
378 ctx
->Driver
.WaitQuery(ctx
, q
);
379 /* if result is too large for returned type, clamp to max value */
380 if (q
->Result
> 0x7fffffff) {
381 *params
= 0x7fffffff;
384 *params
= (GLint
)q
->Result
;
387 case GL_QUERY_RESULT_AVAILABLE_ARB
:
389 ctx
->Driver
.CheckQuery( ctx
, q
);
393 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectivARB(pname)");
400 _mesa_GetQueryObjectuivARB(GLuint id
, GLenum pname
, GLuint
*params
)
402 struct gl_query_object
*q
= NULL
;
403 GET_CURRENT_CONTEXT(ctx
);
404 ASSERT_OUTSIDE_BEGIN_END(ctx
);
407 q
= lookup_query_object(ctx
, id
);
409 if (!q
|| q
->Active
) {
410 _mesa_error(ctx
, GL_INVALID_OPERATION
,
411 "glGetQueryObjectuivARB(id=%d is invalid or active)", id
);
416 case GL_QUERY_RESULT_ARB
:
418 ctx
->Driver
.WaitQuery(ctx
, q
);
419 /* if result is too large for returned type, clamp to max value */
420 if (q
->Result
> 0xffffffff) {
421 *params
= 0xffffffff;
424 *params
= (GLuint
)q
->Result
;
427 case GL_QUERY_RESULT_AVAILABLE_ARB
:
429 ctx
->Driver
.CheckQuery( ctx
, q
);
433 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectuivARB(pname)");
439 #if FEATURE_EXT_timer_query
442 * New with GL_EXT_timer_query
445 _mesa_GetQueryObjecti64vEXT(GLuint id
, GLenum pname
, GLint64EXT
*params
)
447 struct gl_query_object
*q
= NULL
;
448 GET_CURRENT_CONTEXT(ctx
);
449 ASSERT_OUTSIDE_BEGIN_END(ctx
);
452 q
= lookup_query_object(ctx
, id
);
454 if (!q
|| q
->Active
) {
455 _mesa_error(ctx
, GL_INVALID_OPERATION
,
456 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id
);
461 case GL_QUERY_RESULT_ARB
:
463 ctx
->Driver
.WaitQuery(ctx
, q
);
466 case GL_QUERY_RESULT_AVAILABLE_ARB
:
468 ctx
->Driver
.CheckQuery( ctx
, q
);
472 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjecti64vARB(pname)");
479 * New with GL_EXT_timer_query
482 _mesa_GetQueryObjectui64vEXT(GLuint id
, GLenum pname
, GLuint64EXT
*params
)
484 struct gl_query_object
*q
= NULL
;
485 GET_CURRENT_CONTEXT(ctx
);
486 ASSERT_OUTSIDE_BEGIN_END(ctx
);
489 q
= lookup_query_object(ctx
, id
);
491 if (!q
|| q
->Active
) {
492 _mesa_error(ctx
, GL_INVALID_OPERATION
,
493 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id
);
498 case GL_QUERY_RESULT_ARB
:
500 ctx
->Driver
.WaitQuery(ctx
, q
);
503 case GL_QUERY_RESULT_AVAILABLE_ARB
:
505 ctx
->Driver
.CheckQuery( ctx
, q
);
509 _mesa_error(ctx
, GL_INVALID_ENUM
, "glGetQueryObjectui64vARB(pname)");
514 #endif /* FEATURE_EXT_timer_query */
518 * Allocate/init the context state related to query objects.
521 _mesa_init_query(GLcontext
*ctx
)
523 #if FEATURE_ARB_occlusion_query
524 ctx
->Query
.QueryObjects
= _mesa_NewHashTable();
525 ctx
->Query
.CurrentOcclusionObject
= NULL
;
531 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
534 delete_queryobj_cb(GLuint id
, void *data
, void *userData
)
536 struct gl_query_object
*q
= (struct gl_query_object
*) data
;
537 GLcontext
*ctx
= (GLcontext
*)userData
;
538 ctx
->Driver
.DeleteQuery(ctx
, q
);
543 * Free the context state related to query objects.
546 _mesa_free_query_data(GLcontext
*ctx
)
548 _mesa_HashDeleteAll(ctx
->Query
.QueryObjects
, delete_queryobj_cb
, ctx
);
549 _mesa_DeleteHashTable(ctx
->Query
.QueryObjects
);