Remove unused texunit parameter to ctx->Driver.GenerateMipmap()
[mesa.git] / src / mesa / main / queryobj.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.1
4 *
5 * Copyright (C) 1999-2006 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 "hash.h"
29 #include "imports.h"
30 #include "queryobj.h"
31 #include "mtypes.h"
32
33
34 /**
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.
40 */
41 struct gl_query_object *
42 _mesa_new_query_object(GLcontext *ctx, GLuint id)
43 {
44 struct gl_query_object *q = MALLOC_STRUCT(gl_query_object);
45 (void) ctx;
46 if (q) {
47 q->Id = id;
48 q->Result = 0;
49 q->Active = GL_FALSE;
50 q->Ready = GL_TRUE; /* correct, see spec */
51 }
52 return q;
53 }
54
55
56 /**
57 * Delete an occlusion query object.
58 * Not removed from hash table here.
59 * XXX maybe add Delete() method to gl_query_object class and call that instead
60 */
61 static void
62 delete_query_object(struct gl_query_object *q)
63 {
64 FREE(q);
65 }
66
67
68 static struct gl_query_object *
69 lookup_query_object(GLcontext *ctx, GLuint id)
70 {
71 return (struct gl_query_object *)
72 _mesa_HashLookup(ctx->Query.QueryObjects, id);
73 }
74
75
76
77 void GLAPIENTRY
78 _mesa_GenQueriesARB(GLsizei n, GLuint *ids)
79 {
80 GLuint first;
81 GET_CURRENT_CONTEXT(ctx);
82 ASSERT_OUTSIDE_BEGIN_END(ctx);
83
84 if (n < 0) {
85 _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
86 return;
87 }
88
89 /* No query objects can be active at this time! */
90 if (ctx->Query.CurrentOcclusionObject ||
91 ctx->Query.CurrentTimerObject) {
92 _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
93 return;
94 }
95
96 first = _mesa_HashFindFreeKeyBlock(ctx->Query.QueryObjects, n);
97 if (first) {
98 GLsizei i;
99 for (i = 0; i < n; i++) {
100 struct gl_query_object *q
101 = ctx->Driver.NewQueryObject(ctx, first + i);
102 if (!q) {
103 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
104 return;
105 }
106 ids[i] = first + i;
107 _mesa_HashInsert(ctx->Query.QueryObjects, first + i, q);
108 }
109 }
110 }
111
112
113 void GLAPIENTRY
114 _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
115 {
116 GLint i;
117 GET_CURRENT_CONTEXT(ctx);
118 ASSERT_OUTSIDE_BEGIN_END(ctx);
119
120 if (n < 0) {
121 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
122 return;
123 }
124
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, "glDeleteQueriesARB");
129 return;
130 }
131
132 for (i = 0; i < n; i++) {
133 if (ids[i] > 0) {
134 struct gl_query_object *q = lookup_query_object(ctx, ids[i]);
135 if (q) {
136 ASSERT(!q->Active); /* should be caught earlier */
137 _mesa_HashRemove(ctx->Query.QueryObjects, ids[i]);
138 delete_query_object(q);
139 }
140 }
141 }
142 }
143
144
145 GLboolean GLAPIENTRY
146 _mesa_IsQueryARB(GLuint id)
147 {
148 GET_CURRENT_CONTEXT(ctx);
149 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
150
151 if (id && lookup_query_object(ctx, id))
152 return GL_TRUE;
153 else
154 return GL_FALSE;
155 }
156
157
158 void GLAPIENTRY
159 _mesa_BeginQueryARB(GLenum target, GLuint id)
160 {
161 struct gl_query_object *q;
162 GET_CURRENT_CONTEXT(ctx);
163 ASSERT_OUTSIDE_BEGIN_END(ctx);
164
165 FLUSH_VERTICES(ctx, _NEW_DEPTH);
166
167 switch (target) {
168 case GL_SAMPLES_PASSED_ARB:
169 if (!ctx->Extensions.ARB_occlusion_query) {
170 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
171 return;
172 }
173 if (ctx->Query.CurrentOcclusionObject) {
174 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
175 return;
176 }
177 break;
178 #if FEATURE_EXT_timer_query
179 case GL_TIME_ELAPSED_EXT:
180 if (!ctx->Extensions.EXT_timer_query) {
181 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
182 return;
183 }
184 if (ctx->Query.CurrentTimerObject) {
185 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
186 return;
187 }
188 break;
189 #endif
190 default:
191 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
192 return;
193 }
194
195 if (id == 0) {
196 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
197 return;
198 }
199
200 q = lookup_query_object(ctx, id);
201 if (!q) {
202 /* create new object */
203 q = ctx->Driver.NewQueryObject(ctx, id);
204 if (!q) {
205 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
206 return;
207 }
208 _mesa_HashInsert(ctx->Query.QueryObjects, id, q);
209 }
210 else {
211 /* pre-existing object */
212 if (q->Active) {
213 _mesa_error(ctx, GL_INVALID_OPERATION,
214 "glBeginQueryARB(query already active)");
215 return;
216 }
217 }
218
219 q->Active = GL_TRUE;
220 q->Result = 0;
221 q->Ready = GL_FALSE;
222
223 if (target == GL_SAMPLES_PASSED_ARB) {
224 ctx->Query.CurrentOcclusionObject = q;
225 }
226 #if FEATURE_EXT_timer_query
227 else if (target == GL_TIME_ELAPSED_EXT) {
228 ctx->Query.CurrentTimerObject = q;
229 }
230 #endif
231
232 if (ctx->Driver.BeginQuery) {
233 ctx->Driver.BeginQuery(ctx, target, q);
234 }
235 }
236
237
238 void GLAPIENTRY
239 _mesa_EndQueryARB(GLenum target)
240 {
241 struct gl_query_object *q;
242 GET_CURRENT_CONTEXT(ctx);
243 ASSERT_OUTSIDE_BEGIN_END(ctx);
244
245 FLUSH_VERTICES(ctx, _NEW_DEPTH);
246
247 switch (target) {
248 case GL_SAMPLES_PASSED_ARB:
249 if (!ctx->Extensions.ARB_occlusion_query) {
250 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
251 return;
252 }
253 q = ctx->Query.CurrentOcclusionObject;
254 ctx->Query.CurrentOcclusionObject = NULL;
255 break;
256 #if FEATURE_EXT_timer_query
257 case GL_TIME_ELAPSED_EXT:
258 if (!ctx->Extensions.EXT_timer_query) {
259 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
260 return;
261 }
262 q = ctx->Query.CurrentTimerObject;
263 ctx->Query.CurrentTimerObject = NULL;
264 break;
265 #endif
266 default:
267 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
268 return;
269 }
270
271 if (!q || !q->Active) {
272 _mesa_error(ctx, GL_INVALID_OPERATION,
273 "glEndQueryARB(no matching glBeginQueryARB)");
274 return;
275 }
276
277 q->Active = GL_FALSE;
278 if (ctx->Driver.EndQuery) {
279 ctx->Driver.EndQuery(ctx, target, q);
280 }
281 else {
282 /* if we're using software rendering/querying */
283 q->Ready = GL_TRUE;
284 }
285 }
286
287
288 void GLAPIENTRY
289 _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
290 {
291 struct gl_query_object *q;
292 GET_CURRENT_CONTEXT(ctx);
293 ASSERT_OUTSIDE_BEGIN_END(ctx);
294
295 switch (target) {
296 case GL_SAMPLES_PASSED_ARB:
297 if (!ctx->Extensions.ARB_occlusion_query) {
298 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
299 return;
300 }
301 q = ctx->Query.CurrentOcclusionObject;
302 break;
303 #if FEATURE_EXT_timer_query
304 case GL_TIME_ELAPSED_EXT:
305 if (!ctx->Extensions.EXT_timer_query) {
306 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
307 return;
308 }
309 q = ctx->Query.CurrentTimerObject;
310 break;
311 #endif
312 default:
313 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(target)");
314 return;
315 }
316
317 switch (pname) {
318 case GL_QUERY_COUNTER_BITS_ARB:
319 *params = 8 * sizeof(q->Result);
320 break;
321 case GL_CURRENT_QUERY_ARB:
322 *params = q ? q->Id : 0;
323 break;
324 default:
325 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
326 return;
327 }
328 }
329
330
331 void GLAPIENTRY
332 _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
333 {
334 struct gl_query_object *q = NULL;
335 GET_CURRENT_CONTEXT(ctx);
336 ASSERT_OUTSIDE_BEGIN_END(ctx);
337
338 if (id)
339 q = lookup_query_object(ctx, id);
340
341 if (!q || q->Active) {
342 _mesa_error(ctx, GL_INVALID_OPERATION,
343 "glGetQueryObjectivARB(id=%d is invalid or active)", id);
344 return;
345 }
346
347 switch (pname) {
348 case GL_QUERY_RESULT_ARB:
349 while (!q->Ready) {
350 /* Wait for the query to finish! */
351 /* If using software rendering, the result will always be ready
352 * by time we get here. Otherwise, we must be using hardware!
353 */
354 ASSERT(ctx->Driver.EndQuery);
355 }
356 /* if result is too large for returned type, clamp to max value */
357 if (q->Result > 0x7fffffff) {
358 *params = 0x7fffffff;
359 }
360 else {
361 *params = q->Result;
362 }
363 break;
364 case GL_QUERY_RESULT_AVAILABLE_ARB:
365 /* XXX revisit when we have a hardware implementation! */
366 *params = q->Ready;
367 break;
368 default:
369 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
370 return;
371 }
372 }
373
374
375 void GLAPIENTRY
376 _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
377 {
378 struct gl_query_object *q = NULL;
379 GET_CURRENT_CONTEXT(ctx);
380 ASSERT_OUTSIDE_BEGIN_END(ctx);
381
382 if (id)
383 q = lookup_query_object(ctx, id);
384
385 if (!q || q->Active) {
386 _mesa_error(ctx, GL_INVALID_OPERATION,
387 "glGetQueryObjectuivARB(id=%d is invalid or active)", id);
388 return;
389 }
390
391 switch (pname) {
392 case GL_QUERY_RESULT_ARB:
393 while (!q->Ready) {
394 /* Wait for the query to finish! */
395 /* If using software rendering, the result will always be ready
396 * by time we get here. Otherwise, we must be using hardware!
397 */
398 ASSERT(ctx->Driver.EndQuery);
399 }
400 /* if result is too large for returned type, clamp to max value */
401 if (q->Result > 0xffffffff) {
402 *params = 0xffffffff;
403 }
404 else {
405 *params = q->Result;
406 }
407 break;
408 case GL_QUERY_RESULT_AVAILABLE_ARB:
409 /* XXX revisit when we have a hardware implementation! */
410 *params = q->Ready;
411 break;
412 default:
413 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
414 return;
415 }
416 }
417
418
419 #if FEATURE_EXT_timer_query
420
421 /**
422 * New with GL_EXT_timer_query
423 */
424 void GLAPIENTRY
425 _mesa_GetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params)
426 {
427 struct gl_query_object *q = NULL;
428 GET_CURRENT_CONTEXT(ctx);
429 ASSERT_OUTSIDE_BEGIN_END(ctx);
430
431 if (id)
432 q = lookup_query_object(ctx, id);
433
434 if (!q || q->Active) {
435 _mesa_error(ctx, GL_INVALID_OPERATION,
436 "glGetQueryObjectui64vARB(id=%d is invalid or active)", id);
437 return;
438 }
439
440 switch (pname) {
441 case GL_QUERY_RESULT_ARB:
442 while (!q->Ready) {
443 /* Wait for the query to finish! */
444 /* If using software rendering, the result will always be ready
445 * by time we get here. Otherwise, we must be using hardware!
446 */
447 ASSERT(ctx->Driver.EndQuery);
448 }
449 *params = q->Result;
450 break;
451 case GL_QUERY_RESULT_AVAILABLE_ARB:
452 /* XXX revisit when we have a hardware implementation! */
453 *params = q->Ready;
454 break;
455 default:
456 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)");
457 return;
458 }
459 }
460
461
462 /**
463 * New with GL_EXT_timer_query
464 */
465 void GLAPIENTRY
466 _mesa_GetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params)
467 {
468 struct gl_query_object *q = NULL;
469 GET_CURRENT_CONTEXT(ctx);
470 ASSERT_OUTSIDE_BEGIN_END(ctx);
471
472 if (id)
473 q = lookup_query_object(ctx, id);
474
475 if (!q || q->Active) {
476 _mesa_error(ctx, GL_INVALID_OPERATION,
477 "glGetQueryObjectuui64vARB(id=%d is invalid or active)", id);
478 return;
479 }
480
481 switch (pname) {
482 case GL_QUERY_RESULT_ARB:
483 while (!q->Ready) {
484 /* Wait for the query to finish! */
485 /* If using software rendering, the result will always be ready
486 * by time we get here. Otherwise, we must be using hardware!
487 */
488 ASSERT(ctx->Driver.EndQuery);
489 }
490 *params = q->Result;
491 break;
492 case GL_QUERY_RESULT_AVAILABLE_ARB:
493 /* XXX revisit when we have a hardware implementation! */
494 *params = q->Ready;
495 break;
496 default:
497 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)");
498 return;
499 }
500 }
501
502 #endif /* FEATURE_EXT_timer_query */
503
504
505 /**
506 * Allocate/init the context state related to query objects.
507 */
508 void
509 _mesa_init_query(GLcontext *ctx)
510 {
511 #if FEATURE_ARB_occlusion_query
512 ctx->Query.QueryObjects = _mesa_NewHashTable();
513 ctx->Query.CurrentOcclusionObject = NULL;
514 #endif
515 }
516
517
518 /**
519 * Callback for deleting a query object. Called by _mesa_HashDeleteAll().
520 */
521 static void
522 delete_queryobj_cb(GLuint id, void *data, void *userData)
523 {
524 struct gl_query_object *q= (struct gl_query_object *) data;
525 (void) userData;
526 delete_query_object(q);
527 }
528
529
530 /**
531 * Free the context state related to query objects.
532 */
533 void
534 _mesa_free_query_data(GLcontext *ctx)
535 {
536 _mesa_HashDeleteAll(ctx->Query.QueryObjects, delete_queryobj_cb, NULL);
537 _mesa_DeleteHashTable(ctx->Query.QueryObjects);
538 }