Follow suggestion by Aapo Tahkola to fix giant memory leak from forgetting to free...
[mesa.git] / src / mesa / tnl / t_save_loopback.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
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 /* Author:
26 * Keith Whitwell <keith@tungstengraphics.com>
27 */
28
29 #include "glheader.h"
30 #include "context.h"
31 #include "enums.h"
32 #include "glapi.h"
33 #include "imports.h"
34 #include "macros.h"
35 #include "mtypes.h"
36 #include "t_context.h"
37 #include "t_save_api.h"
38 #include "dispatch.h"
39
40 /* If someone compiles a display list like:
41 * glBegin(Triangles)
42 * glVertex()
43 * ... lots of vertices ...
44 * glEnd()
45 *
46 * or:
47 * glDrawArrays(...)
48 *
49 * and then tries to execute it like this:
50 *
51 * glBegin(Lines)
52 * glCallList()
53 * glEnd()
54 *
55 * it will wind up in here, as the vertex copying used when wrapping
56 * buffers in list compilation (Triangles) won't be right for how the
57 * list is being executed (as Lines).
58 *
59 * This could be avoided by not compiling as vertex_lists until after
60 * the first glEnd() has been seen. However, that would miss an
61 * important category of display lists, for the sake of a degenerate
62 * usage.
63 *
64 * Further, replaying degenerately-called lists in this fashion is
65 * probably still faster than the replay using opcodes.
66 */
67
68 typedef void (*attr_func)( GLcontext *ctx, GLint target, const GLfloat * );
69
70
71 /* Wrapper functions in case glVertexAttrib*fvNV doesn't exist */
72 static void VertexAttrib1fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
73 {
74 CALL_VertexAttrib1fvNV(ctx->Exec, (target, v));
75 }
76
77 static void VertexAttrib2fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
78 {
79 CALL_VertexAttrib2fvNV(ctx->Exec, (target, v));
80 }
81
82 static void VertexAttrib3fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
83 {
84 CALL_VertexAttrib3fvNV(ctx->Exec, (target, v));
85 }
86
87 static void VertexAttrib4fvNV(GLcontext *ctx, GLint target, const GLfloat *v)
88 {
89 CALL_VertexAttrib4fvNV(ctx->Exec, (target, v));
90 }
91
92 static attr_func vert_attrfunc[4] = {
93 VertexAttrib1fvNV,
94 VertexAttrib2fvNV,
95 VertexAttrib3fvNV,
96 VertexAttrib4fvNV
97 };
98
99
100 static void VertexAttrib1fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
101 {
102 CALL_VertexAttrib1fvARB(ctx->Exec, (target, v));
103 }
104
105 static void VertexAttrib2fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
106 {
107 CALL_VertexAttrib2fvARB(ctx->Exec, (target, v));
108 }
109
110 static void VertexAttrib3fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
111 {
112 CALL_VertexAttrib3fvARB(ctx->Exec, (target, v));
113 }
114
115 static void VertexAttrib4fvARB(GLcontext *ctx, GLint target, const GLfloat *v)
116 {
117 CALL_VertexAttrib4fvARB(ctx->Exec, (target, v));
118 }
119
120 static attr_func vert_attrfunc_arb[4] = {
121 VertexAttrib1fvARB,
122 VertexAttrib2fvARB,
123 VertexAttrib3fvARB,
124 VertexAttrib4fvARB
125 };
126
127
128
129
130
131
132
133 static void mat_attr1fv( GLcontext *ctx, GLint target, const GLfloat *v )
134 {
135 switch (target) {
136 case _TNL_ATTRIB_MAT_FRONT_SHININESS:
137 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SHININESS, v ));
138 break;
139 case _TNL_ATTRIB_MAT_BACK_SHININESS:
140 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SHININESS, v ));
141 break;
142 }
143 }
144
145
146 static void mat_attr3fv( GLcontext *ctx, GLint target, const GLfloat *v )
147 {
148 switch (target) {
149 case _TNL_ATTRIB_MAT_FRONT_INDEXES:
150 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_COLOR_INDEXES, v ));
151 break;
152 case _TNL_ATTRIB_MAT_BACK_INDEXES:
153 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_COLOR_INDEXES, v ));
154 break;
155 }
156 }
157
158
159 static void mat_attr4fv( GLcontext *ctx, GLint target, const GLfloat *v )
160 {
161 switch (target) {
162 case _TNL_ATTRIB_MAT_FRONT_EMISSION:
163 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_EMISSION, v ));
164 break;
165 case _TNL_ATTRIB_MAT_BACK_EMISSION:
166 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_EMISSION, v ));
167 break;
168 case _TNL_ATTRIB_MAT_FRONT_AMBIENT:
169 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_AMBIENT, v ));
170 break;
171 case _TNL_ATTRIB_MAT_BACK_AMBIENT:
172 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_AMBIENT, v ));
173 break;
174 case _TNL_ATTRIB_MAT_FRONT_DIFFUSE:
175 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_DIFFUSE, v ));
176 break;
177 case _TNL_ATTRIB_MAT_BACK_DIFFUSE:
178 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_DIFFUSE, v ));
179 break;
180 case _TNL_ATTRIB_MAT_FRONT_SPECULAR:
181 CALL_Materialfv(ctx->Exec, ( GL_FRONT, GL_SPECULAR, v ));
182 break;
183 case _TNL_ATTRIB_MAT_BACK_SPECULAR:
184 CALL_Materialfv(ctx->Exec, ( GL_BACK, GL_SPECULAR, v ));
185 break;
186 }
187 }
188
189
190 static attr_func mat_attrfunc[4] = {
191 mat_attr1fv,
192 NULL,
193 mat_attr3fv,
194 mat_attr4fv
195 };
196
197
198 static void index_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
199 {
200 (void) target;
201 CALL_Indexf(ctx->Exec, (v[0]));
202 }
203
204 static void edgeflag_attr1fv(GLcontext *ctx, GLint target, const GLfloat *v)
205 {
206 (void) target;
207 CALL_EdgeFlag(ctx->Exec, ((GLboolean)(v[0] == 1.0)));
208 }
209
210 struct loopback_attr {
211 GLint target;
212 GLint sz;
213 attr_func func;
214 };
215
216 /* Don't emit ends and begins on wrapped primitives. Don't replay
217 * wrapped vertices. If we get here, it's probably because the the
218 * precalculated wrapping is wrong.
219 */
220 static void loopback_prim( GLcontext *ctx,
221 const struct tnl_vertex_list *list, GLuint i,
222 const struct loopback_attr *la, GLuint nr )
223 {
224 struct tnl_prim *prim = &list->prim[i];
225 GLint begin = prim->start;
226 GLint end = begin + prim->count;
227 GLfloat *data;
228 GLint j;
229 GLuint k;
230
231 if (prim->mode & PRIM_BEGIN) {
232 CALL_Begin(GET_DISPATCH(), ( prim->mode & PRIM_MODE_MASK ));
233 }
234 else {
235 assert(i == 0);
236 assert(begin == 0);
237 begin += list->wrap_count;
238 }
239
240 data = list->buffer + begin * list->vertex_size;
241
242 for (j = begin ; j < end ; j++) {
243 GLfloat *tmp = data + la[0].sz;
244
245 for (k = 1 ; k < nr ; k++) {
246 la[k].func( ctx, la[k].target, tmp );
247 tmp += la[k].sz;
248 }
249
250 /* Fire the vertex
251 */
252 la[0].func( ctx, VERT_ATTRIB_POS, data );
253 data = tmp;
254 }
255
256 if (prim->mode & PRIM_END) {
257 CALL_End(GET_DISPATCH(), ());
258 }
259 else {
260 assert (i == list->prim_count-1);
261 }
262 }
263
264 /* Primitives generated by DrawArrays/DrawElements/Rectf may be
265 * caught here. If there is no primitive in progress, execute them
266 * normally, otherwise need to track and discard the generated
267 * primitives.
268 */
269 static void loopback_weak_prim( GLcontext *ctx,
270 const struct tnl_vertex_list *list, GLuint i,
271 const struct loopback_attr *la, GLuint nr )
272 {
273 if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END)
274 loopback_prim( ctx, list, i, la, nr );
275 else {
276 struct tnl_prim *prim = &list->prim[i];
277
278 /* Use the prim_weak flag to ensure that if this primitive
279 * wraps, we don't mistake future vertex_lists for part of the
280 * surrounding primitive.
281 *
282 * While this flag is set, we are simply disposing of data
283 * generated by an operation now known to be a noop.
284 */
285 if (prim->mode & PRIM_BEGIN)
286 ctx->Driver.CurrentExecPrimitive |= PRIM_WEAK;
287 if (prim->mode & PRIM_END)
288 ctx->Driver.CurrentExecPrimitive &= ~PRIM_WEAK;
289 }
290 }
291
292
293
294 void _tnl_loopback_vertex_list( GLcontext *ctx,
295 const struct tnl_vertex_list *list )
296 {
297 struct loopback_attr la[_TNL_ATTRIB_MAX];
298 GLuint i, nr = 0;
299
300 for (i = 0 ; i <= _TNL_ATTRIB_TEX7 ; i++) {
301 if (list->attrsz[i]) {
302 la[nr].target = i;
303 la[nr].sz = list->attrsz[i];
304 la[nr].func = vert_attrfunc[list->attrsz[i]-1];
305 nr++;
306 }
307 }
308
309 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT ;
310 i <= _TNL_ATTRIB_MAT_BACK_INDEXES ;
311 i++) {
312 if (list->attrsz[i]) {
313 la[nr].target = i;
314 la[nr].sz = list->attrsz[i];
315 la[nr].func = mat_attrfunc[list->attrsz[i]-1];
316 nr++;
317 }
318 }
319
320 if (list->attrsz[_TNL_ATTRIB_EDGEFLAG]) {
321 la[nr].target = _TNL_ATTRIB_EDGEFLAG;
322 la[nr].sz = list->attrsz[_TNL_ATTRIB_EDGEFLAG];
323 la[nr].func = edgeflag_attr1fv;
324 nr++;
325 }
326
327 if (list->attrsz[_TNL_ATTRIB_INDEX]) {
328 la[nr].target = _TNL_ATTRIB_INDEX;
329 la[nr].sz = list->attrsz[_TNL_ATTRIB_INDEX];
330 la[nr].func = index_attr1fv;
331 nr++;
332 }
333
334 /* XXX ARB vertex attribs */
335
336 for (i = 0 ; i < list->prim_count ; i++) {
337 if (list->prim[i].mode & PRIM_WEAK)
338 loopback_weak_prim( ctx, list, i, la, nr );
339 else
340 loopback_prim( ctx, list, i, la, nr );
341 }
342 }