remove ^M chars, disable shading language extensions
[mesa.git] / src / mesa / main / occlude.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.0.2
4 *
5 * Copyright (C) 1999-2004 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 /*
27 * Functions to implement the GL_ARB_occlusion_query extension.
28 */
29
30
31 #include "glheader.h"
32 #include "context.h"
33 #include "hash.h"
34 #include "imports.h"
35 #include "occlude.h"
36 #include "mtypes.h"
37
38
39 struct occlusion_query
40 {
41 GLenum Target;
42 GLuint Id;
43 GLuint PassedCounter;
44 GLboolean Active;
45 };
46
47
48 /**
49 * Allocate a new occlusion query object.
50 * \param target - must be GL_SAMPLES_PASSED_ARB at this time
51 * \param id - the object's ID
52 * \return pointer to new occlusion_query object or NULL if out of memory.
53 */
54 static struct occlusion_query *
55 new_query_object(GLenum target, GLuint id)
56 {
57 struct occlusion_query *q = MALLOC_STRUCT(occlusion_query);
58 if (q) {
59 q->Target = target;
60 q->Id = id;
61 q->PassedCounter = 0;
62 q->Active = GL_FALSE;
63 }
64 return q;
65 }
66
67
68 /**
69 * Delete an occlusion query object.
70 */
71 static void
72 delete_query_object(struct occlusion_query *q)
73 {
74 FREE(q);
75 }
76
77
78 void GLAPIENTRY
79 _mesa_GenQueriesARB(GLsizei n, GLuint *ids)
80 {
81 GET_CURRENT_CONTEXT(ctx);
82 GLuint first;
83 ASSERT_OUTSIDE_BEGIN_END(ctx);
84
85 if (n < 0) {
86 _mesa_error(ctx, GL_INVALID_VALUE, "glGenQueriesARB(n < 0)");
87 return;
88 }
89
90 if (ctx->Occlusion.Active) {
91 _mesa_error(ctx, GL_INVALID_OPERATION, "glGenQueriesARB");
92 return;
93 }
94
95 first = _mesa_HashFindFreeKeyBlock(ctx->Occlusion.QueryObjects, n);
96 if (first) {
97 GLsizei i;
98 for (i = 0; i < n; i++) {
99 struct occlusion_query *q = new_query_object(GL_SAMPLES_PASSED_ARB,
100 first + i);
101 if (!q) {
102 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenQueriesARB");
103 return;
104 }
105 ids[i] = first + i;
106 _mesa_HashInsert(ctx->Occlusion.QueryObjects, first + i, q);
107 }
108 }
109 }
110
111
112 void GLAPIENTRY
113 _mesa_DeleteQueriesARB(GLsizei n, const GLuint *ids)
114 {
115 GET_CURRENT_CONTEXT(ctx);
116 GLint i;
117 ASSERT_OUTSIDE_BEGIN_END(ctx);
118
119 if (n < 0) {
120 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteQueriesARB(n < 0)");
121 return;
122 }
123
124 if (ctx->Occlusion.Active) {
125 _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteQueriesARB");
126 return;
127 }
128
129 for (i = 0; i < n; i++) {
130 if (ids[i] > 0) {
131 struct occlusion_query *q = (struct occlusion_query *)
132 _mesa_HashLookup(ctx->Occlusion.QueryObjects, ids[i]);
133 if (q) {
134 _mesa_HashRemove(ctx->Occlusion.QueryObjects, ids[i]);
135 delete_query_object(q);
136 }
137 }
138 }
139 }
140
141
142 GLboolean GLAPIENTRY
143 _mesa_IsQueryARB(GLuint id)
144 {
145 GET_CURRENT_CONTEXT(ctx);
146 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
147
148 if (id && _mesa_HashLookup(ctx->Occlusion.QueryObjects, id))
149 return GL_TRUE;
150 else
151 return GL_FALSE;
152 }
153
154
155 void GLAPIENTRY
156 _mesa_BeginQueryARB(GLenum target, GLuint id)
157 {
158 GET_CURRENT_CONTEXT(ctx);
159 struct occlusion_query *q;
160 ASSERT_OUTSIDE_BEGIN_END(ctx);
161
162 FLUSH_VERTICES(ctx, _NEW_DEPTH);
163
164 if (target != GL_SAMPLES_PASSED_ARB) {
165 _mesa_error(ctx, GL_INVALID_ENUM, "glBeginQueryARB(target)");
166 return;
167 }
168
169 if (id == 0) {
170 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(id==0)");
171 return;
172 }
173
174 if (ctx->Occlusion.CurrentQueryObject) {
175 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB(target)");
176 return;
177 }
178
179 q = (struct occlusion_query *)
180 _mesa_HashLookup(ctx->Occlusion.QueryObjects, id);
181 if (q && q->Active) {
182 _mesa_error(ctx, GL_INVALID_OPERATION, "glBeginQueryARB");
183 return;
184 }
185 else if (!q) {
186 q = new_query_object(target, id);
187 if (!q) {
188 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBeginQueryARB");
189 return;
190 }
191 _mesa_HashInsert(ctx->Occlusion.QueryObjects, id, q);
192 }
193
194 q->Active = GL_TRUE;
195 q->PassedCounter = 0;
196 ctx->Occlusion.Active = GL_TRUE;
197 ctx->Occlusion.CurrentQueryObject = id;
198 ctx->Occlusion.PassedCounter = 0;
199 }
200
201
202 void GLAPIENTRY
203 _mesa_EndQueryARB(GLenum target)
204 {
205 GET_CURRENT_CONTEXT(ctx);
206 struct occlusion_query *q = NULL;
207 ASSERT_OUTSIDE_BEGIN_END(ctx);
208
209 FLUSH_VERTICES(ctx, _NEW_DEPTH);
210
211 if (target != GL_SAMPLES_PASSED_ARB) {
212 _mesa_error(ctx, GL_INVALID_ENUM, "glEndQueryARB(target)");
213 return;
214 }
215
216 if (ctx->Occlusion.CurrentQueryObject)
217 q = (struct occlusion_query *)
218 _mesa_HashLookup(ctx->Occlusion.QueryObjects,
219 ctx->Occlusion.CurrentQueryObject);
220 if (!q || !q->Active) {
221 _mesa_error(ctx, GL_INVALID_OPERATION, "glEndQuery with no glBeginQuery");
222 return;
223 }
224
225 q->PassedCounter = ctx->Occlusion.PassedCounter;
226 q->Active = GL_FALSE;
227 ctx->Occlusion.Active = GL_FALSE;
228 ctx->Occlusion.CurrentQueryObject = 0;
229 }
230
231
232 void GLAPIENTRY
233 _mesa_GetQueryivARB(GLenum target, GLenum pname, GLint *params)
234 {
235 GET_CURRENT_CONTEXT(ctx);
236 ASSERT_OUTSIDE_BEGIN_END(ctx);
237
238 if (target != GL_SAMPLES_PASSED_ARB) {
239 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(target)");
240 return;
241 }
242
243 switch (pname) {
244 case GL_QUERY_COUNTER_BITS_ARB:
245 *params = 8 * sizeof(GLuint);
246 break;
247 case GL_CURRENT_QUERY_ARB:
248 *params = ctx->Occlusion.CurrentQueryObject;
249 break;
250 default:
251 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryivARB(pname)");
252 return;
253 }
254 }
255
256
257 void GLAPIENTRY
258 _mesa_GetQueryObjectivARB(GLuint id, GLenum pname, GLint *params)
259 {
260 GET_CURRENT_CONTEXT(ctx);
261 struct occlusion_query *q = NULL;
262 ASSERT_OUTSIDE_BEGIN_END(ctx);
263
264 if (id)
265 q = (struct occlusion_query *)
266 _mesa_HashLookup(ctx->Occlusion.QueryObjects, id);
267
268 if (!q || q->Active) {
269 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryObjectivARB(id=%d)", id);
270 return;
271 }
272
273 switch (pname) {
274 case GL_QUERY_RESULT_ARB:
275 *params = q->PassedCounter;
276 break;
277 case GL_QUERY_RESULT_AVAILABLE_ARB:
278 /* XXX revisit when we have a hardware implementation! */
279 *params = GL_TRUE;
280 break;
281 default:
282 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)");
283 return;
284 }
285 }
286
287
288 void GLAPIENTRY
289 _mesa_GetQueryObjectuivARB(GLuint id, GLenum pname, GLuint *params)
290 {
291 GET_CURRENT_CONTEXT(ctx);
292 struct occlusion_query *q = NULL;
293 ASSERT_OUTSIDE_BEGIN_END(ctx);
294
295 if (id)
296 q = (struct occlusion_query *)
297 _mesa_HashLookup(ctx->Occlusion.QueryObjects, id);
298 if (!q || q->Active) {
299 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetQueryObjectuivARB(id=%d", id);
300 return;
301 }
302
303 switch (pname) {
304 case GL_QUERY_RESULT_ARB:
305 *params = q->PassedCounter;
306 break;
307 case GL_QUERY_RESULT_AVAILABLE_ARB:
308 /* XXX revisit when we have a hardware implementation! */
309 *params = GL_TRUE;
310 break;
311 default:
312 _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)");
313 return;
314 }
315 }
316
317
318
319 /**
320 * Allocate/init the context state related to occlusion query objects.
321 */
322 void
323 _mesa_init_occlude(GLcontext *ctx)
324 {
325 #if FEATURE_ARB_occlusion_query
326 ctx->Occlusion.QueryObjects = _mesa_NewHashTable();
327 #endif
328 ctx->OcclusionResult = GL_FALSE;
329 ctx->OcclusionResultSaved = GL_FALSE;
330 }
331
332
333 /**
334 * Free the context state related to occlusion query objects.
335 */
336 void
337 _mesa_free_occlude_data(GLcontext *ctx)
338 {
339 while (1) {
340 GLuint query = _mesa_HashFirstEntry(ctx->Occlusion.QueryObjects);
341 if (query) {
342 struct occlusion_query *q = (struct occlusion_query *)
343 _mesa_HashLookup(ctx->Occlusion.QueryObjects, query);
344 ASSERT(q);
345 delete_query_object(q);
346 _mesa_HashRemove(ctx->Occlusion.QueryObjects, query);
347 }
348 else {
349 break;
350 }
351 }
352 _mesa_DeleteHashTable(ctx->Occlusion.QueryObjects);
353 }