If there is only one normal, don't transform it multiple times.
[mesa.git] / src / mesa / tnl / t_save_api.c
1 /* $XFree86$ */
2 /**************************************************************************
3
4 Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
5
6 All Rights Reserved.
7
8 Permission is hereby granted, free of charge, to any person obtaining a
9 copy of this software and associated documentation files (the "Software"),
10 to deal in the Software without restriction, including without limitation
11 on the rights to use, copy, modify, merge, publish, distribute, sub
12 license, and/or sell copies of the Software, and to permit persons to whom
13 the Software is furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice (including the next
16 paragraph) shall be included in all copies or substantial portions of the
17 Software.
18
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27 **************************************************************************/
28
29 /*
30 * Authors:
31 * Keith Whitwell <keith@tungstengraphics.com>
32 */
33
34
35
36 /* Display list compiler attempts to store lists of vertices with the
37 * same vertex layout. Additionally it attempts to minimize the need
38 * for execute-time fixup of these vertex lists, allowing them to be
39 * cached on hardware.
40 *
41 * There are still some circumstances where this can be thwarted, for
42 * example by building a list that consists of one very long primitive
43 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
44 * from inside a different begin/end object (Begin(Lines), CallList,
45 * End).
46 *
47 * In that case the code will have to replay the list as individual
48 * commands through the Exec dispatch table, or fix up the copied
49 * vertices at execute-time.
50 *
51 * The other case where fixup is required is when a vertex attribute
52 * is introduced in the middle of a primitive. Eg:
53 * Begin(Lines)
54 * TexCoord1f() Vertex2f()
55 * TexCoord1f() Color3f() Vertex2f()
56 * End()
57 *
58 * If the current value of Color isn't known at compile-time, this
59 * primitive will require fixup.
60 *
61 *
62 * The list compiler currently doesn't attempt to compile lists
63 * containing EvalCoord or EvalPoint commands. On encountering one of
64 * these, compilation falls back to opcodes.
65 *
66 * This could be improved to fallback only when a mix of EvalCoord and
67 * Vertex commands are issued within a single primitive.
68 */
69
70
71 #include "glheader.h"
72 #include "context.h"
73 #include "dlist.h"
74 #include "enums.h"
75 #include "macros.h"
76 #include "api_validate.h"
77 #include "api_arrayelt.h"
78 #include "vtxfmt.h"
79 #include "t_save_api.h"
80
81 /*
82 * NOTE: Old 'parity' issue is gone, but copying can still be
83 * wrong-footed on replay.
84 */
85 static GLuint _save_copy_vertices( GLcontext *ctx,
86 const struct tnl_vertex_list *node )
87 {
88 TNLcontext *tnl = TNL_CONTEXT( ctx );
89 const struct tnl_prim *prim = &node->prim[node->prim_count-1];
90 GLuint nr = prim->count;
91 GLuint sz = tnl->save.vertex_size;
92 const GLfloat *src = node->buffer + prim->start * sz;
93 GLfloat *dst = tnl->save.copied.buffer;
94 GLuint ovf, i;
95
96 if (prim->mode & PRIM_END)
97 return 0;
98
99 switch( prim->mode & PRIM_MODE_MASK )
100 {
101 case GL_POINTS:
102 return 0;
103 case GL_LINES:
104 ovf = nr&1;
105 for (i = 0 ; i < ovf ; i++)
106 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
107 return i;
108 case GL_TRIANGLES:
109 ovf = nr%3;
110 for (i = 0 ; i < ovf ; i++)
111 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
112 return i;
113 case GL_QUADS:
114 ovf = nr&3;
115 for (i = 0 ; i < ovf ; i++)
116 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
117 return i;
118 case GL_LINE_STRIP:
119 if (nr == 0)
120 return 0;
121 else {
122 _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
123 return 1;
124 }
125 case GL_LINE_LOOP:
126 case GL_TRIANGLE_FAN:
127 case GL_POLYGON:
128 if (nr == 0)
129 return 0;
130 else if (nr == 1) {
131 _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
132 return 1;
133 } else {
134 _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
135 _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
136 return 2;
137 }
138 case GL_TRIANGLE_STRIP:
139 case GL_QUAD_STRIP:
140 switch (nr) {
141 case 0: ovf = 0; break;
142 case 1: ovf = 1; break;
143 default: ovf = 2 + (nr&1); break;
144 }
145 for (i = 0 ; i < ovf ; i++)
146 _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
147 return i;
148 default:
149 assert(0);
150 return 0;
151 }
152 }
153
154
155 static void
156 build_normal_lengths( struct tnl_vertex_list *node )
157 {
158 GLuint i;
159 GLfloat *len;
160 GLfloat *n = node->buffer;
161 GLuint stride = node->vertex_size;
162 GLuint count = node->count;
163
164 len = node->normal_lengths = (GLfloat *) MALLOC( count * sizeof(GLfloat) );
165 if (!len)
166 return;
167
168 /* Find the normal of the first vertex:
169 */
170 for (i = 0 ; i < _TNL_ATTRIB_NORMAL ; i++)
171 n += node->attrsz[i];
172
173 for (i = 0 ; i < count ; i++, n += stride) {
174 len[i] = LEN_3FV( n );
175 if (len[i] > 0.0F) len[i] = 1.0F / len[i];
176 }
177 }
178
179 static struct tnl_vertex_store *alloc_vertex_store( GLcontext *ctx )
180 {
181 struct tnl_vertex_store *store = MALLOC_STRUCT(tnl_vertex_store);
182 (void) ctx;
183 store->used = 0;
184 store->refcount = 1;
185 return store;
186 }
187
188 static struct tnl_primitive_store *alloc_prim_store( GLcontext *ctx )
189 {
190 struct tnl_primitive_store *store = MALLOC_STRUCT(tnl_primitive_store);
191 (void) ctx;
192 store->used = 0;
193 store->refcount = 1;
194 return store;
195 }
196
197 static void _save_reset_counters( GLcontext *ctx )
198 {
199 TNLcontext *tnl = TNL_CONTEXT(ctx);
200
201 tnl->save.prim = tnl->save.prim_store->buffer + tnl->save.prim_store->used;
202 tnl->save.buffer = (tnl->save.vertex_store->buffer +
203 tnl->save.vertex_store->used);
204
205 if (tnl->save.vertex_size)
206 tnl->save.initial_counter = ((SAVE_BUFFER_SIZE -
207 tnl->save.vertex_store->used) /
208 tnl->save.vertex_size);
209 else
210 tnl->save.initial_counter = 0;
211
212 if (tnl->save.initial_counter > ctx->Const.MaxArrayLockSize )
213 tnl->save.initial_counter = ctx->Const.MaxArrayLockSize;
214
215 tnl->save.counter = tnl->save.initial_counter;
216 tnl->save.prim_count = 0;
217 tnl->save.prim_max = SAVE_PRIM_SIZE - tnl->save.prim_store->used;
218 tnl->save.copied.nr = 0;
219 tnl->save.dangling_attr_ref = 0;
220 }
221
222
223 /* Insert the active immediate struct onto the display list currently
224 * being built.
225 */
226 static void _save_compile_vertex_list( GLcontext *ctx )
227 {
228 TNLcontext *tnl = TNL_CONTEXT(ctx);
229 struct tnl_vertex_list *node;
230
231 /* Allocate space for this structure in the display list currently
232 * being compiled.
233 */
234 node = (struct tnl_vertex_list *)
235 _mesa_alloc_instruction(ctx, tnl->save.opcode_vertex_list, sizeof(*node));
236
237 if (!node)
238 return;
239
240 /* Duplicate our template, increment refcounts to the storage structs:
241 */
242 _mesa_memcpy(node->attrsz, tnl->save.attrsz, sizeof(node->attrsz));
243 node->vertex_size = tnl->save.vertex_size;
244 node->buffer = tnl->save.buffer;
245 node->wrap_count = tnl->save.copied.nr;
246 node->count = tnl->save.initial_counter - tnl->save.counter;
247 node->prim = tnl->save.prim;
248 node->prim_count = tnl->save.prim_count;
249 node->vertex_store = tnl->save.vertex_store;
250 node->prim_store = tnl->save.prim_store;
251 node->dangling_attr_ref = tnl->save.dangling_attr_ref;
252 node->normal_lengths = 0;
253
254 node->vertex_store->refcount++;
255 node->prim_store->refcount++;
256
257 assert(node->attrsz[_TNL_ATTRIB_POS] != 0 ||
258 node->count == 0);
259
260 /* Maybe calculate normal lengths:
261 */
262 if (tnl->CalcDListNormalLengths &&
263 node->attrsz[_TNL_ATTRIB_NORMAL] == 3 &&
264 !node->dangling_attr_ref)
265 build_normal_lengths( node );
266
267 tnl->save.vertex_store->used += tnl->save.vertex_size * node->count;
268 tnl->save.prim_store->used += node->prim_count;
269
270 /* Decide whether the storage structs are full, or can be used for
271 * the next vertex lists as well.
272 */
273 if (tnl->save.vertex_store->used >
274 SAVE_BUFFER_SIZE - 16 * (tnl->save.vertex_size + 4)) {
275
276 tnl->save.vertex_store->refcount--;
277 assert(tnl->save.vertex_store->refcount != 0);
278 tnl->save.vertex_store = alloc_vertex_store( ctx );
279 tnl->save.vbptr = tnl->save.vertex_store->buffer;
280 }
281
282 if (tnl->save.prim_store->used > SAVE_PRIM_SIZE - 6) {
283 tnl->save.prim_store->refcount--;
284 assert(tnl->save.prim_store->refcount != 0);
285 tnl->save.prim_store = alloc_prim_store( ctx );
286 }
287
288 /* Reset our structures for the next run of vertices:
289 */
290 _save_reset_counters( ctx );
291
292 /* Copy duplicated vertices
293 */
294 tnl->save.copied.nr = _save_copy_vertices( ctx, node );
295
296
297 /* Deal with GL_COMPILE_AND_EXECUTE:
298 */
299 if (ctx->ExecuteFlag) {
300 _tnl_playback_vertex_list( ctx, (void *) node );
301 }
302 }
303
304
305 /* TODO -- If no new vertices have been stored, don't bother saving
306 * it.
307 */
308 static void _save_wrap_buffers( GLcontext *ctx )
309 {
310 TNLcontext *tnl = TNL_CONTEXT(ctx);
311 GLint i = tnl->save.prim_count - 1;
312 GLenum mode;
313
314 assert(i < (GLint) tnl->save.prim_max);
315 assert(i >= 0);
316
317 /* Close off in-progress primitive.
318 */
319 tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
320 tnl->save.prim[i].start);
321 mode = tnl->save.prim[i].mode & ~(PRIM_BEGIN|PRIM_END);
322
323 /* store the copied vertices, and allocate a new list.
324 */
325 _save_compile_vertex_list( ctx );
326
327 /* Restart interrupted primitive
328 */
329 tnl->save.prim[0].mode = mode;
330 tnl->save.prim[0].start = 0;
331 tnl->save.prim[0].count = 0;
332 tnl->save.prim_count = 1;
333 }
334
335
336
337 /* Called only when buffers are wrapped as the result of filling the
338 * vertex_store struct.
339 */
340 static void _save_wrap_filled_vertex( GLcontext *ctx )
341 {
342 TNLcontext *tnl = TNL_CONTEXT(ctx);
343 GLfloat *data = tnl->save.copied.buffer;
344 GLuint i;
345
346 /* Emit a glEnd to close off the last vertex list.
347 */
348 _save_wrap_buffers( ctx );
349
350 /* Copy stored stored vertices to start of new list.
351 */
352 assert(tnl->save.counter > tnl->save.copied.nr);
353
354 for (i = 0 ; i < tnl->save.copied.nr ; i++) {
355 _mesa_memcpy( tnl->save.vbptr, data, tnl->save.vertex_size * sizeof(GLfloat));
356 data += tnl->save.vertex_size;
357 tnl->save.vbptr += tnl->save.vertex_size;
358 tnl->save.counter--;
359 }
360 }
361
362
363 static void _save_copy_to_current( GLcontext *ctx )
364 {
365 TNLcontext *tnl = TNL_CONTEXT(ctx);
366 GLuint i;
367
368 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++) {
369 if (tnl->save.attrsz[i]) {
370 tnl->save.currentsz[i][0] = tnl->save.attrsz[i];
371 ASSIGN_4V(tnl->save.current[i], 0, 0, 0, 1);
372 COPY_SZ_4V(tnl->save.current[i],
373 tnl->save.attrsz[i],
374 tnl->save.attrptr[i]);
375 }
376 }
377
378 /* Edgeflag requires special treatment:
379 */
380 if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
381 ctx->ListState.ActiveEdgeFlag = 1;
382 ctx->ListState.CurrentEdgeFlag =
383 (tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
384 }
385 }
386
387
388 static void _save_copy_from_current( GLcontext *ctx )
389 {
390 TNLcontext *tnl = TNL_CONTEXT(ctx);
391 GLint i;
392
393 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
394 switch (tnl->save.attrsz[i]) {
395 case 4: tnl->save.attrptr[i][3] = tnl->save.current[i][3];
396 case 3: tnl->save.attrptr[i][2] = tnl->save.current[i][2];
397 case 2: tnl->save.attrptr[i][1] = tnl->save.current[i][1];
398 case 1: tnl->save.attrptr[i][0] = tnl->save.current[i][0];
399 case 0: break;
400 }
401
402 /* Edgeflag requires special treatment:
403 */
404 if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG])
405 tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
406 (GLfloat)ctx->ListState.CurrentEdgeFlag;
407 }
408
409
410
411
412 /* Flush existing data, set new attrib size, replay copied vertices.
413 */
414 static void _save_upgrade_vertex( GLcontext *ctx,
415 GLuint attr,
416 GLuint newsz )
417 {
418 TNLcontext *tnl = TNL_CONTEXT(ctx);
419 GLuint oldsz;
420 GLuint i;
421 GLfloat *tmp;
422
423 /* Store the current run of vertices, and emit a GL_END. Emit a
424 * BEGIN in the new buffer.
425 */
426 if (tnl->save.initial_counter != tnl->save.counter)
427 _save_wrap_buffers( ctx );
428 else
429 assert( tnl->save.copied.nr == 0 );
430
431 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
432 * when the attribute already exists in the vertex and is having
433 * its size increased.
434 */
435 _save_copy_to_current( ctx );
436
437 /* Fix up sizes:
438 */
439 oldsz = tnl->save.attrsz[attr];
440 tnl->save.attrsz[attr] = newsz;
441
442 tnl->save.vertex_size += newsz - oldsz;
443 tnl->save.counter = ((SAVE_BUFFER_SIZE - tnl->save.vertex_store->used) /
444 tnl->save.vertex_size);
445 if (tnl->save.counter > ctx->Const.MaxArrayLockSize )
446 tnl->save.counter = ctx->Const.MaxArrayLockSize;
447 tnl->save.initial_counter = tnl->save.counter;
448
449 /* Recalculate all the attrptr[] values:
450 */
451 for (i = 0, tmp = tnl->save.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
452 if (tnl->save.attrsz[i]) {
453 tnl->save.attrptr[i] = tmp;
454 tmp += tnl->save.attrsz[i];
455 }
456 else
457 tnl->save.attrptr[i] = 0; /* will not be dereferenced. */
458 }
459
460 /* Copy from current to repopulate the vertex with correct values.
461 */
462 _save_copy_from_current( ctx );
463
464 /* Replay stored vertices to translate them to new format here.
465 *
466 * If there are copied vertices and the new (upgraded) attribute
467 * has not been defined before, this list is somewhat degenerate,
468 * and will need fixup at runtime.
469 */
470 if (tnl->save.copied.nr)
471 {
472 GLfloat *data = tnl->save.copied.buffer;
473 GLfloat *dest = tnl->save.buffer;
474 GLuint j;
475
476 /* Need to note this and fix up at runtime (or loopback):
477 */
478 if (tnl->save.currentsz[attr][0] == 0) {
479 assert(oldsz == 0);
480 tnl->save.dangling_attr_ref = GL_TRUE;
481 _mesa_debug(0, "_save_upgrade_vertex: dangling reference attr %d\n",
482 attr);
483
484 #if 0
485 /* The current strategy is to punt these degenerate cases
486 * through _tnl_loopback_vertex_list(), a lower-performance
487 * option. To minimize the impact of this, artificially
488 * reduce the size of this vertex_list.
489 */
490 if (t->save.counter > 10) {
491 t->save.initial_counter = 10;
492 t->save.counter = 10;
493 }
494 #endif
495 }
496
497 for (i = 0 ; i < tnl->save.copied.nr ; i++) {
498 for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
499 if (tnl->save.attrsz[j]) {
500 if (j == attr) {
501 if (oldsz) {
502 ASSIGN_4V( dest, 0, 0, 0, 1 );
503 COPY_SZ_4V( dest, oldsz, data );
504 data += oldsz;
505 dest += newsz;
506 }
507 else {
508 COPY_SZ_4V( dest, newsz, tnl->save.current[attr] );
509 dest += newsz;
510 }
511 }
512 else {
513 GLint sz = tnl->save.attrsz[j];
514 COPY_SZ_4V( dest, sz, data );
515 data += sz;
516 dest += sz;
517 }
518 }
519 }
520 }
521
522 tnl->save.vbptr = dest;
523 tnl->save.counter -= tnl->save.copied.nr;
524 }
525 }
526
527
528
529
530 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
531 * entrypoint is called for the first time.
532 */
533 static void do_choose( GLuint attr, GLuint sz,
534 void (*attr_func)( const GLfloat *),
535 void (*choose1)( const GLfloat *),
536 void (*choose2)( const GLfloat *),
537 void (*choose3)( const GLfloat *),
538 void (*choose4)( const GLfloat *),
539 const GLfloat *v )
540 {
541 GET_CURRENT_CONTEXT( ctx );
542 TNLcontext *tnl = TNL_CONTEXT(ctx);
543 static GLfloat id[4] = { 0, 0, 0, 1 };
544 int i;
545
546 if (tnl->save.attrsz[attr] < sz) {
547 /* New size is larger. Need to flush existing vertices and get
548 * an enlarged vertex format.
549 */
550 _save_upgrade_vertex( ctx, attr, sz );
551 }
552 else {
553 /* New size is equal or smaller - just need to fill in some
554 * zeros.
555 */
556 for (i = sz ; i <= tnl->save.attrsz[attr] ; i++)
557 tnl->save.attrptr[attr][i-1] = id[i-1];
558 }
559
560 /* Reset any active pointers for this attribute
561 */
562 tnl->save.tabfv[attr][0] = choose1;
563 tnl->save.tabfv[attr][1] = choose2;
564 tnl->save.tabfv[attr][2] = choose3;
565 tnl->save.tabfv[attr][3] = choose4;
566
567 /* Update the secondary dispatch table with the new function
568 */
569 tnl->save.tabfv[attr][sz-1] = attr_func;
570
571 (*attr_func)(v);
572 }
573
574
575
576 /* Only one size for each attribute may be active at once. Eg. if
577 * Color3f is installed/active, then Color4f may not be, even if the
578 * vertex actually contains 4 color coordinates. This is because the
579 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
580 * of the chooser function when switching between Color4f and Color3f.
581 */
582 #define ATTRFV( ATTR, N ) \
583 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
584 \
585 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
586 { \
587 GET_CURRENT_CONTEXT( ctx ); \
588 TNLcontext *tnl = TNL_CONTEXT(ctx); \
589 \
590 if ((ATTR) == 0) { \
591 GLuint i; \
592 \
593 if (N>0) tnl->save.vbptr[0] = v[0]; \
594 if (N>1) tnl->save.vbptr[1] = v[1]; \
595 if (N>2) tnl->save.vbptr[2] = v[2]; \
596 if (N>3) tnl->save.vbptr[3] = v[3]; \
597 \
598 for (i = N; i < tnl->save.vertex_size; i++) \
599 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
600 \
601 tnl->save.vbptr += tnl->save.vertex_size; \
602 \
603 if (--tnl->save.counter == 0) \
604 _save_wrap_filled_vertex( ctx ); \
605 } \
606 else { \
607 GLfloat *dest = tnl->save.attrptr[ATTR]; \
608 if (N>0) dest[0] = v[0]; \
609 if (N>1) dest[1] = v[1]; \
610 if (N>2) dest[2] = v[2]; \
611 if (N>3) dest[3] = v[3]; \
612 } \
613 }
614
615 #define CHOOSE( ATTR, N ) \
616 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
617 { \
618 do_choose(ATTR, N, \
619 save_attrib_##ATTR##_##N, \
620 save_choose_##ATTR##_1, \
621 save_choose_##ATTR##_2, \
622 save_choose_##ATTR##_3, \
623 save_choose_##ATTR##_4, \
624 v ); \
625 }
626
627 #define INIT(ATTR) \
628 static void save_init_##ATTR( TNLcontext *tnl ) \
629 { \
630 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
631 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
632 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
633 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
634 }
635
636 #define ATTRS( ATTRIB ) \
637 ATTRFV( ATTRIB, 1 ) \
638 ATTRFV( ATTRIB, 2 ) \
639 ATTRFV( ATTRIB, 3 ) \
640 ATTRFV( ATTRIB, 4 ) \
641 CHOOSE( ATTRIB, 1 ) \
642 CHOOSE( ATTRIB, 2 ) \
643 CHOOSE( ATTRIB, 3 ) \
644 CHOOSE( ATTRIB, 4 ) \
645 INIT( ATTRIB ) \
646
647
648 /* Generate a lot of functions. These are the actual worker
649 * functions, which are equivalent to those generated via codegen
650 * elsewhere.
651 */
652 ATTRS( 0 )
653 ATTRS( 1 )
654 ATTRS( 2 )
655 ATTRS( 3 )
656 ATTRS( 4 )
657 ATTRS( 5 )
658 ATTRS( 6 )
659 ATTRS( 7 )
660 ATTRS( 8 )
661 ATTRS( 9 )
662 ATTRS( 10 )
663 ATTRS( 11 )
664 ATTRS( 12 )
665 ATTRS( 13 )
666 ATTRS( 14 )
667 ATTRS( 15 )
668
669
670 static void _save_reset_vertex( GLcontext *ctx )
671 {
672 TNLcontext *tnl = TNL_CONTEXT(ctx);
673 GLuint i;
674
675 save_init_0( tnl );
676 save_init_1( tnl );
677 save_init_2( tnl );
678 save_init_3( tnl );
679 save_init_4( tnl );
680 save_init_5( tnl );
681 save_init_6( tnl );
682 save_init_7( tnl );
683 save_init_8( tnl );
684 save_init_9( tnl );
685 save_init_10( tnl );
686 save_init_11( tnl );
687 save_init_12( tnl );
688 save_init_13( tnl );
689 save_init_14( tnl );
690 save_init_15( tnl );
691
692 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
693 tnl->save.attrsz[i] = 0;
694
695 tnl->save.vertex_size = 0;
696 tnl->save.have_materials = 0;
697
698 _save_reset_counters( ctx );
699 }
700
701
702
703 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
704 * of glMultTexCoord and glProgramParamterNV by routing all these
705 * through a second level dispatch table.
706 */
707 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
708 do { \
709 GET_CURRENT_CONTEXT( ctx ); \
710 TNLcontext *tnl = TNL_CONTEXT(ctx); \
711 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
712 } while (0)
713
714 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
715 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
716 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
717 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
718
719 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
720
721 #if defined(USE_X86_ASM) && 0 /* will break register calling convention */
722 /* Naughty cheat:
723 */
724 #define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
725 #define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
726 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
727 #else
728 /* Safe:
729 */
730 #define DISPATCH_ATTR2F( ATTR, S,T ) \
731 do { \
732 GLfloat v[2]; \
733 v[0] = S; v[1] = T; \
734 DISPATCH_ATTR2FV( ATTR, v ); \
735 } while (0)
736 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
737 do { \
738 GLfloat v[3]; \
739 v[0] = S; v[1] = T; v[2] = R; \
740 DISPATCH_ATTR3FV( ATTR, v ); \
741 } while (0)
742 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
743 do { \
744 GLfloat v[4]; \
745 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
746 DISPATCH_ATTR4FV( ATTR, v ); \
747 } while (0)
748 #endif
749
750
751 static void enum_error( void )
752 {
753 GET_CURRENT_CONTEXT( ctx );
754 _mesa_compile_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
755 }
756
757 static void GLAPIENTRY _save_Vertex2f( GLfloat x, GLfloat y )
758 {
759 DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
760 }
761
762 static void GLAPIENTRY _save_Vertex2fv( const GLfloat *v )
763 {
764 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
765 }
766
767 static void GLAPIENTRY _save_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
768 {
769 DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
770 }
771
772 static void GLAPIENTRY _save_Vertex3fv( const GLfloat *v )
773 {
774 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
775 }
776
777 static void GLAPIENTRY _save_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
778 {
779 DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
780 }
781
782 static void GLAPIENTRY _save_Vertex4fv( const GLfloat *v )
783 {
784 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
785 }
786
787 static void GLAPIENTRY _save_TexCoord1f( GLfloat x )
788 {
789 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
790 }
791
792 static void GLAPIENTRY _save_TexCoord1fv( const GLfloat *v )
793 {
794 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
795 }
796
797 static void GLAPIENTRY _save_TexCoord2f( GLfloat x, GLfloat y )
798 {
799 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
800 }
801
802 static void GLAPIENTRY _save_TexCoord2fv( const GLfloat *v )
803 {
804 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
805 }
806
807 static void GLAPIENTRY _save_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
808 {
809 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
810 }
811
812 static void GLAPIENTRY _save_TexCoord3fv( const GLfloat *v )
813 {
814 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
815 }
816
817 static void GLAPIENTRY _save_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
818 {
819 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
820 }
821
822 static void GLAPIENTRY _save_TexCoord4fv( const GLfloat *v )
823 {
824 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
825 }
826
827 static void GLAPIENTRY _save_Normal3f( GLfloat x, GLfloat y, GLfloat z )
828 {
829 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
830 }
831
832 static void GLAPIENTRY _save_Normal3fv( const GLfloat *v )
833 {
834 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
835 }
836
837 static void GLAPIENTRY _save_FogCoordfEXT( GLfloat x )
838 {
839 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
840 }
841
842 static void GLAPIENTRY _save_FogCoordfvEXT( const GLfloat *v )
843 {
844 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
845 }
846
847 static void GLAPIENTRY _save_Color3f( GLfloat x, GLfloat y, GLfloat z )
848 {
849 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
850 }
851
852 static void GLAPIENTRY _save_Color3fv( const GLfloat *v )
853 {
854 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
855 }
856
857 static void GLAPIENTRY _save_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
858 {
859 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
860 }
861
862 static void GLAPIENTRY _save_Color4fv( const GLfloat *v )
863 {
864 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
865 }
866
867 static void GLAPIENTRY _save_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
868 {
869 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
870 }
871
872 static void GLAPIENTRY _save_SecondaryColor3fvEXT( const GLfloat *v )
873 {
874 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
875 }
876
877 static void GLAPIENTRY _save_MultiTexCoord1f( GLenum target, GLfloat x )
878 {
879 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
880 DISPATCH_ATTR1F( attr, x );
881 }
882
883 static void GLAPIENTRY _save_MultiTexCoord1fv( GLenum target, const GLfloat *v )
884 {
885 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
886 DISPATCH_ATTR1FV( attr, v );
887 }
888
889 static void GLAPIENTRY _save_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
890 {
891 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
892 DISPATCH_ATTR2F( attr, x, y );
893 }
894
895 static void GLAPIENTRY _save_MultiTexCoord2fv( GLenum target, const GLfloat *v )
896 {
897 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
898 DISPATCH_ATTR2FV( attr, v );
899 }
900
901 static void GLAPIENTRY _save_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
902 GLfloat z)
903 {
904 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
905 DISPATCH_ATTR3F( attr, x, y, z );
906 }
907
908 static void GLAPIENTRY _save_MultiTexCoord3fv( GLenum target, const GLfloat *v )
909 {
910 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
911 DISPATCH_ATTR3FV( attr, v );
912 }
913
914 static void GLAPIENTRY _save_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
915 GLfloat z, GLfloat w )
916 {
917 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
918 DISPATCH_ATTR4F( attr, x, y, z, w );
919 }
920
921 static void GLAPIENTRY _save_MultiTexCoord4fv( GLenum target, const GLfloat *v )
922 {
923 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
924 DISPATCH_ATTR4FV( attr, v );
925 }
926
927 static void GLAPIENTRY _save_VertexAttrib1fNV( GLuint index, GLfloat x )
928 {
929 if (index < VERT_ATTRIB_MAX)
930 DISPATCH_ATTR1F( index, x );
931 else
932 enum_error();
933 }
934
935 static void GLAPIENTRY _save_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
936 {
937 if (index < VERT_ATTRIB_MAX)
938 DISPATCH_ATTR1FV( index, v );
939 else
940 enum_error();
941 }
942
943 static void GLAPIENTRY _save_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y )
944 {
945 if (index < VERT_ATTRIB_MAX)
946 DISPATCH_ATTR2F( index, x, y );
947 else
948 enum_error();
949 }
950
951 static void GLAPIENTRY _save_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
952 {
953 if (index < VERT_ATTRIB_MAX)
954 DISPATCH_ATTR2FV( index, v );
955 else
956 enum_error();
957 }
958
959 static void GLAPIENTRY _save_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y,
960 GLfloat z )
961 {
962 if (index < VERT_ATTRIB_MAX)
963 DISPATCH_ATTR3F( index, x, y, z );
964 else
965 enum_error();
966 }
967
968 static void GLAPIENTRY _save_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
969 {
970 if (index < VERT_ATTRIB_MAX)
971 DISPATCH_ATTR3FV( index, v );
972 else
973 enum_error();
974 }
975
976 static void GLAPIENTRY _save_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y,
977 GLfloat z, GLfloat w )
978 {
979 if (index < VERT_ATTRIB_MAX)
980 DISPATCH_ATTR4F( index, x, y, z, w );
981 else
982 enum_error();
983 }
984
985 static void GLAPIENTRY _save_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
986 {
987 if (index < VERT_ATTRIB_MAX)
988 DISPATCH_ATTR4FV( index, v );
989 else
990 enum_error();
991 }
992
993
994 static void GLAPIENTRY
995 _save_VertexAttrib1fARB( GLuint index, GLfloat x )
996 {
997 if (index < VERT_ATTRIB_MAX)
998 DISPATCH_ATTR1F( index, x );
999 else
1000 enum_error();
1001 }
1002
1003 static void GLAPIENTRY
1004 _save_VertexAttrib1fvARB( GLuint index, const GLfloat *v )
1005 {
1006 if (index < VERT_ATTRIB_MAX)
1007 DISPATCH_ATTR1FV( index, v );
1008 else
1009 enum_error();
1010 }
1011
1012 static void GLAPIENTRY
1013 _save_VertexAttrib2fARB( GLuint index, GLfloat x, GLfloat y )
1014 {
1015 if (index < VERT_ATTRIB_MAX)
1016 DISPATCH_ATTR2F( index, x, y );
1017 else
1018 enum_error();
1019 }
1020
1021 static void GLAPIENTRY
1022 _save_VertexAttrib2fvARB( GLuint index, const GLfloat *v )
1023 {
1024 if (index < VERT_ATTRIB_MAX)
1025 DISPATCH_ATTR2FV( index, v );
1026 else
1027 enum_error();
1028 }
1029
1030 static void GLAPIENTRY
1031 _save_VertexAttrib3fARB( GLuint index, GLfloat x, GLfloat y, GLfloat z )
1032 {
1033 if (index < VERT_ATTRIB_MAX)
1034 DISPATCH_ATTR3F( index, x, y, z );
1035 else
1036 enum_error();
1037 }
1038
1039 static void GLAPIENTRY
1040 _save_VertexAttrib3fvARB( GLuint index, const GLfloat *v )
1041 {
1042 if (index < VERT_ATTRIB_MAX)
1043 DISPATCH_ATTR3FV( index, v );
1044 else
1045 enum_error();
1046 }
1047
1048 static void GLAPIENTRY
1049 _save_VertexAttrib4fARB( GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
1050 {
1051 if (index < VERT_ATTRIB_MAX)
1052 DISPATCH_ATTR4F( index, x, y, z, w );
1053 else
1054 enum_error();
1055 }
1056
1057 static void GLAPIENTRY
1058 _save_VertexAttrib4fvARB( GLuint index, const GLfloat *v )
1059 {
1060 if (index < VERT_ATTRIB_MAX)
1061 DISPATCH_ATTR4FV( index, v );
1062 else
1063 enum_error();
1064 }
1065
1066
1067 /* Materials:
1068 *
1069 * These are treated as per-vertex attributes, at indices above where
1070 * the NV_vertex_program leaves off. There are a lot of good things
1071 * about treating materials this way.
1072 *
1073 * However: I don't want to double the number of generated functions
1074 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
1075 * ATTRF into this function, and dispense with codegen and
1076 * second-level dispatch.
1077 *
1078 * There is no aliasing of material attributes with other entrypoints.
1079 */
1080 #define MAT_ATTR( A, N, params ) \
1081 do { \
1082 if (tnl->save.attrsz[A] < N) { \
1083 _save_upgrade_vertex( ctx, A, N ); \
1084 tnl->save.have_materials = GL_TRUE; \
1085 } \
1086 \
1087 { \
1088 GLfloat *dest = tnl->save.attrptr[A]; \
1089 if (N>0) dest[0] = params[0]; \
1090 if (N>1) dest[1] = params[1]; \
1091 if (N>2) dest[2] = params[2]; \
1092 if (N>3) dest[3] = params[3]; \
1093 } \
1094 } while (0)
1095
1096
1097 #define MAT( ATTR, N, face, params ) \
1098 do { \
1099 if (face != GL_BACK) \
1100 MAT_ATTR( ATTR, N, params ); /* front */ \
1101 if (face != GL_FRONT) \
1102 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1103 } while (0)
1104
1105
1106 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1107 * later on - in the meantime just store everything.
1108 */
1109 static void GLAPIENTRY _save_Materialfv( GLenum face, GLenum pname,
1110 const GLfloat *params )
1111 {
1112 GET_CURRENT_CONTEXT( ctx );
1113 TNLcontext *tnl = TNL_CONTEXT(ctx);
1114
1115 switch (pname) {
1116 case GL_EMISSION:
1117 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
1118 break;
1119 case GL_AMBIENT:
1120 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
1121 break;
1122 case GL_DIFFUSE:
1123 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
1124 break;
1125 case GL_SPECULAR:
1126 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
1127 break;
1128 case GL_SHININESS:
1129 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
1130 break;
1131 case GL_COLOR_INDEXES:
1132 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
1133 break;
1134 case GL_AMBIENT_AND_DIFFUSE:
1135 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
1136 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
1137 break;
1138 default:
1139 _mesa_compile_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
1140 return;
1141 }
1142 }
1143
1144
1145 #define IDX_ATTR( A, IDX ) \
1146 do { \
1147 GET_CURRENT_CONTEXT( ctx ); \
1148 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1149 \
1150 if (tnl->save.attrsz[A] < 1) { \
1151 _save_upgrade_vertex( ctx, A, 1 ); \
1152 } \
1153 \
1154 { \
1155 GLfloat *dest = tnl->save.attrptr[A]; \
1156 dest[0] = IDX; \
1157 } \
1158 } while (0)
1159
1160
1161 static void GLAPIENTRY _save_EdgeFlag( GLboolean b )
1162 {
1163 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
1164 }
1165
1166 static void GLAPIENTRY _save_EdgeFlagv( const GLboolean *v )
1167 {
1168 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)(v[0]) );
1169 }
1170
1171 static void GLAPIENTRY _save_Indexf( GLfloat f )
1172 {
1173 IDX_ATTR( _TNL_ATTRIB_INDEX, f );
1174 }
1175
1176 static void GLAPIENTRY _save_Indexfv( const GLfloat *f )
1177 {
1178 IDX_ATTR( _TNL_ATTRIB_INDEX, f[0] );
1179 }
1180
1181
1182
1183
1184 /* Cope with EvalCoord/CallList called within a begin/end object:
1185 * -- Flush current buffer
1186 * -- Fallback to opcodes for the rest of the begin/end object.
1187 */
1188 #define FALLBACK(ctx) \
1189 do { \
1190 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1191 \
1192 /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
1193 \
1194 if (tnl->save.initial_counter != tnl->save.counter || \
1195 tnl->save.prim_count) \
1196 _save_compile_vertex_list( ctx ); \
1197 \
1198 _save_copy_to_current( ctx ); \
1199 _save_reset_vertex( ctx ); \
1200 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1201 ctx->Driver.SaveNeedFlush = 0; \
1202 } while (0)
1203
1204 static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
1205 {
1206 GET_CURRENT_CONTEXT(ctx);
1207 FALLBACK(ctx);
1208 ctx->Save->EvalCoord1f( u );
1209 }
1210
1211 static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
1212 {
1213 GET_CURRENT_CONTEXT(ctx);
1214 FALLBACK(ctx);
1215 ctx->Save->EvalCoord1fv( v );
1216 }
1217
1218 static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
1219 {
1220 GET_CURRENT_CONTEXT(ctx);
1221 FALLBACK(ctx);
1222 ctx->Save->EvalCoord2f( u, v );
1223 }
1224
1225 static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
1226 {
1227 GET_CURRENT_CONTEXT(ctx);
1228 FALLBACK(ctx);
1229 ctx->Save->EvalCoord2fv( v );
1230 }
1231
1232 static void GLAPIENTRY _save_EvalPoint1( GLint i )
1233 {
1234 GET_CURRENT_CONTEXT(ctx);
1235 FALLBACK(ctx);
1236 ctx->Save->EvalPoint1( i );
1237 }
1238
1239 static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
1240 {
1241 GET_CURRENT_CONTEXT(ctx);
1242 FALLBACK(ctx);
1243 ctx->Save->EvalPoint2( i, j );
1244 }
1245
1246 static void GLAPIENTRY _save_CallList( GLuint l )
1247 {
1248 GET_CURRENT_CONTEXT(ctx);
1249 FALLBACK(ctx);
1250 ctx->Save->CallList( l );
1251 }
1252
1253 static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
1254 {
1255 GET_CURRENT_CONTEXT(ctx);
1256 FALLBACK(ctx);
1257 ctx->Save->CallLists( n, type, v );
1258 }
1259
1260
1261
1262
1263 /* This begin is hooked into ... Updating of
1264 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1265 */
1266 static GLboolean _save_NotifyBegin( GLcontext *ctx, GLenum mode )
1267 {
1268 TNLcontext *tnl = TNL_CONTEXT(ctx);
1269
1270 if (1) {
1271 GLuint i = tnl->save.prim_count++;
1272
1273 assert(i < tnl->save.prim_max);
1274 tnl->save.prim[i].mode = mode | PRIM_BEGIN;
1275 tnl->save.prim[i].start = tnl->save.initial_counter - tnl->save.counter;
1276 tnl->save.prim[i].count = 0;
1277
1278 _mesa_install_save_vtxfmt( ctx, &tnl->save_vtxfmt );
1279 ctx->Driver.SaveNeedFlush = 1;
1280 return GL_TRUE;
1281 }
1282 else
1283 return GL_FALSE;
1284 }
1285
1286
1287
1288 static void GLAPIENTRY _save_End( void )
1289 {
1290 GET_CURRENT_CONTEXT( ctx );
1291 TNLcontext *tnl = TNL_CONTEXT(ctx);
1292 GLint i = tnl->save.prim_count - 1;
1293
1294 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1295 tnl->save.prim[i].mode |= PRIM_END;
1296 tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
1297 tnl->save.prim[i].start);
1298
1299 if (i == (GLint) tnl->save.prim_max - 1) {
1300 _save_compile_vertex_list( ctx );
1301 assert(tnl->save.copied.nr == 0);
1302 }
1303
1304 /* Swap out this vertex format while outside begin/end. Any color,
1305 * etc. received between here and the next begin will be compiled
1306 * as opcodes.
1307 */
1308 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1309 }
1310
1311
1312 /* These are all errors as this vtxfmt is only installed inside
1313 * begin/end pairs.
1314 */
1315 static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
1316 const GLvoid *indices)
1317 {
1318 GET_CURRENT_CONTEXT(ctx);
1319 (void) mode; (void) count; (void) type; (void) indices;
1320 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
1321 }
1322
1323
1324 static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
1325 GLuint start, GLuint end,
1326 GLsizei count, GLenum type,
1327 const GLvoid *indices)
1328 {
1329 GET_CURRENT_CONTEXT(ctx);
1330 (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
1331 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
1332 }
1333
1334 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
1335 {
1336 GET_CURRENT_CONTEXT(ctx);
1337 (void) mode; (void) start; (void) count;
1338 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
1339 }
1340
1341 static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
1342 {
1343 GET_CURRENT_CONTEXT(ctx);
1344 (void) x1; (void) y1; (void) x2; (void) y2;
1345 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
1346 }
1347
1348 static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
1349 {
1350 GET_CURRENT_CONTEXT(ctx);
1351 (void) mode; (void) i1; (void) i2;
1352 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
1353 }
1354
1355 static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
1356 GLint j1, GLint j2 )
1357 {
1358 GET_CURRENT_CONTEXT(ctx);
1359 (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
1360 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
1361 }
1362
1363 static void GLAPIENTRY _save_Begin( GLenum mode )
1364 {
1365 GET_CURRENT_CONTEXT( ctx );
1366 (void) mode;
1367 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
1368 }
1369
1370
1371 /* Unlike the functions above, these are to be hooked into the vtxfmt
1372 * maintained in ctx->ListState, active when the list is known or
1373 * suspected to be outside any begin/end primitive.
1374 */
1375 static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
1376 {
1377 GET_CURRENT_CONTEXT(ctx);
1378 _save_NotifyBegin( ctx, GL_QUADS | PRIM_WEAK );
1379 GL_CALL(Vertex2f)( x1, y1 );
1380 GL_CALL(Vertex2f)( x2, y1 );
1381 GL_CALL(Vertex2f)( x2, y2 );
1382 GL_CALL(Vertex2f)( x1, y2 );
1383 GL_CALL(End)();
1384 }
1385
1386
1387 static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1388 {
1389 GET_CURRENT_CONTEXT(ctx);
1390 GLint i;
1391
1392 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
1393 return;
1394
1395 _save_NotifyBegin( ctx, mode | PRIM_WEAK );
1396 for (i = 0; i < count; i++)
1397 GL_CALL(ArrayElement)(start + i);
1398 GL_CALL(End)();
1399 }
1400
1401
1402 static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1403 const GLvoid *indices)
1404 {
1405 GET_CURRENT_CONTEXT(ctx);
1406 GLint i;
1407
1408 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
1409 return;
1410
1411 _save_NotifyBegin( ctx, mode | PRIM_WEAK );
1412
1413 switch (type) {
1414 case GL_UNSIGNED_BYTE:
1415 for (i = 0 ; i < count ; i++)
1416 GL_CALL(ArrayElement)( ((GLubyte *)indices)[i] );
1417 break;
1418 case GL_UNSIGNED_SHORT:
1419 for (i = 0 ; i < count ; i++)
1420 GL_CALL(ArrayElement)( ((GLushort *)indices)[i] );
1421 break;
1422 case GL_UNSIGNED_INT:
1423 for (i = 0 ; i < count ; i++)
1424 GL_CALL(ArrayElement)( ((GLuint *)indices)[i] );
1425 break;
1426 default:
1427 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
1428 break;
1429 }
1430
1431 GL_CALL(End)();
1432 }
1433
1434 static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
1435 GLuint start, GLuint end,
1436 GLsizei count, GLenum type,
1437 const GLvoid *indices)
1438 {
1439 GET_CURRENT_CONTEXT(ctx);
1440 if (_mesa_validate_DrawRangeElements( ctx, mode,
1441 start, end,
1442 count, type, indices ))
1443 _save_OBE_DrawElements( mode, count, type, indices );
1444 }
1445
1446
1447
1448
1449
1450 static void _save_vtxfmt_init( GLcontext *ctx )
1451 {
1452 TNLcontext *tnl = TNL_CONTEXT(ctx);
1453 GLvertexformat *vfmt = &tnl->save_vtxfmt;
1454
1455 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
1456 vfmt->Begin = _save_Begin;
1457 vfmt->Color3f = _save_Color3f;
1458 vfmt->Color3fv = _save_Color3fv;
1459 vfmt->Color4f = _save_Color4f;
1460 vfmt->Color4fv = _save_Color4fv;
1461 vfmt->EdgeFlag = _save_EdgeFlag;
1462 vfmt->EdgeFlagv = _save_EdgeFlagv;
1463 vfmt->End = _save_End;
1464 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1465 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1466 vfmt->Indexf = _save_Indexf;
1467 vfmt->Indexfv = _save_Indexfv;
1468 vfmt->Materialfv = _save_Materialfv;
1469 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1470 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1471 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1472 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1473 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1474 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1475 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1476 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1477 vfmt->Normal3f = _save_Normal3f;
1478 vfmt->Normal3fv = _save_Normal3fv;
1479 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1480 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1481 vfmt->TexCoord1f = _save_TexCoord1f;
1482 vfmt->TexCoord1fv = _save_TexCoord1fv;
1483 vfmt->TexCoord2f = _save_TexCoord2f;
1484 vfmt->TexCoord2fv = _save_TexCoord2fv;
1485 vfmt->TexCoord3f = _save_TexCoord3f;
1486 vfmt->TexCoord3fv = _save_TexCoord3fv;
1487 vfmt->TexCoord4f = _save_TexCoord4f;
1488 vfmt->TexCoord4fv = _save_TexCoord4fv;
1489 vfmt->Vertex2f = _save_Vertex2f;
1490 vfmt->Vertex2fv = _save_Vertex2fv;
1491 vfmt->Vertex3f = _save_Vertex3f;
1492 vfmt->Vertex3fv = _save_Vertex3fv;
1493 vfmt->Vertex4f = _save_Vertex4f;
1494 vfmt->Vertex4fv = _save_Vertex4fv;
1495 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1496 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1497 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1498 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1499 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1500 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1501 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1502 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1503 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1504 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1505 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1506 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1507 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1508 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1509 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1510 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1511
1512 /* This will all require us to fallback to saving the list as opcodes:
1513 */
1514 vfmt->CallList = _save_CallList; /* inside begin/end */
1515 vfmt->CallLists = _save_CallLists; /* inside begin/end */
1516 vfmt->EvalCoord1f = _save_EvalCoord1f;
1517 vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1518 vfmt->EvalCoord2f = _save_EvalCoord2f;
1519 vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1520 vfmt->EvalPoint1 = _save_EvalPoint1;
1521 vfmt->EvalPoint2 = _save_EvalPoint2;
1522
1523 /* These are all errors as we at least know we are in some sort of
1524 * begin/end pair:
1525 */
1526 vfmt->EvalMesh1 = _save_EvalMesh1;
1527 vfmt->EvalMesh2 = _save_EvalMesh2;
1528 vfmt->Begin = _save_Begin;
1529 vfmt->Rectf = _save_Rectf;
1530 vfmt->DrawArrays = _save_DrawArrays;
1531 vfmt->DrawElements = _save_DrawElements;
1532 vfmt->DrawRangeElements = _save_DrawRangeElements;
1533
1534 }
1535
1536
1537 void _tnl_SaveFlushVertices( GLcontext *ctx )
1538 {
1539 TNLcontext *tnl = TNL_CONTEXT(ctx);
1540
1541 /* Noop when we are actually active:
1542 */
1543 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
1544 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
1545 return;
1546
1547 if (tnl->save.initial_counter != tnl->save.counter ||
1548 tnl->save.prim_count)
1549 _save_compile_vertex_list( ctx );
1550
1551 _save_copy_to_current( ctx );
1552 _save_reset_vertex( ctx );
1553 ctx->Driver.SaveNeedFlush = 0;
1554 }
1555
1556 void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
1557 {
1558 TNLcontext *tnl = TNL_CONTEXT(ctx);
1559
1560 (void) list; (void) mode;
1561
1562 if (!tnl->save.prim_store)
1563 tnl->save.prim_store = alloc_prim_store( ctx );
1564
1565 if (!tnl->save.vertex_store) {
1566 tnl->save.vertex_store = alloc_vertex_store( ctx );
1567 tnl->save.vbptr = tnl->save.vertex_store->buffer;
1568 }
1569
1570 _save_reset_vertex( ctx );
1571 ctx->Driver.SaveNeedFlush = 0;
1572 }
1573
1574 void _tnl_EndList( GLcontext *ctx )
1575 {
1576 (void) ctx;
1577 assert(TNL_CONTEXT(ctx)->save.vertex_size == 0);
1578 }
1579
1580 void _tnl_BeginCallList( GLcontext *ctx, GLuint list )
1581 {
1582 (void) ctx; (void) list;
1583 }
1584
1585 void _tnl_EndCallList( GLcontext *ctx )
1586 {
1587 (void) ctx;
1588 }
1589
1590
1591 static void _tnl_destroy_vertex_list( GLcontext *ctx, void *data )
1592 {
1593 struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
1594 (void) ctx;
1595
1596 if ( --node->vertex_store->refcount == 0 )
1597 FREE( node->vertex_store );
1598
1599 if ( --node->prim_store->refcount == 0 )
1600 FREE( node->prim_store );
1601
1602 if ( node->normal_lengths )
1603 FREE( node->normal_lengths );
1604 }
1605
1606
1607 static void _tnl_print_vertex_list( GLcontext *ctx, void *data )
1608 {
1609 struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
1610 GLuint i;
1611 (void) ctx;
1612
1613 _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1614 node->count,
1615 node->prim_count,
1616 node->vertex_size);
1617
1618 for (i = 0 ; i < node->prim_count ; i++) {
1619 struct tnl_prim *prim = &node->prim[i];
1620 _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
1621 i,
1622 _mesa_lookup_enum_by_nr(prim->mode & PRIM_MODE_MASK),
1623 prim->start,
1624 prim->start + prim->count,
1625 (prim->mode & PRIM_BEGIN) ? "BEGIN" : "(wrap)",
1626 (prim->mode & PRIM_END) ? "END" : "(wrap)");
1627 }
1628 }
1629
1630
1631 static void _save_current_init( GLcontext *ctx )
1632 {
1633 TNLcontext *tnl = TNL_CONTEXT(ctx);
1634 GLint i;
1635
1636 for (i = 0; i < _TNL_ATTRIB_MAT_FRONT_AMBIENT; i++) {
1637 ASSERT(i < VERT_ATTRIB_MAX);
1638 tnl->save.currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
1639 tnl->save.current[i] = ctx->ListState.CurrentAttrib[i];
1640 }
1641
1642 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT; i < _TNL_ATTRIB_INDEX; i++) {
1643 const GLuint j = i - _TNL_ATTRIB_MAT_FRONT_AMBIENT;
1644 ASSERT(j < MAT_ATTRIB_MAX);
1645 tnl->save.currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1646 tnl->save.current[i] = ctx->ListState.CurrentMaterial[j];
1647 }
1648
1649 tnl->save.currentsz[_TNL_ATTRIB_INDEX] = &ctx->ListState.ActiveIndex;
1650 tnl->save.current[_TNL_ATTRIB_INDEX] = &ctx->ListState.CurrentIndex;
1651
1652 /* Current edgeflag is handled individually */
1653 }
1654
1655 /**
1656 * Initialize the display list compiler
1657 */
1658 void _tnl_save_init( GLcontext *ctx )
1659 {
1660 TNLcontext *tnl = TNL_CONTEXT(ctx);
1661 struct tnl_vertex_arrays *tmp = &tnl->save_inputs;
1662 GLuint i;
1663
1664
1665 for (i = 0; i < _TNL_ATTRIB_MAX; i++)
1666 _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
1667
1668 tnl->save.opcode_vertex_list =
1669 _mesa_alloc_opcode( ctx,
1670 sizeof(struct tnl_vertex_list),
1671 _tnl_playback_vertex_list,
1672 _tnl_destroy_vertex_list,
1673 _tnl_print_vertex_list );
1674
1675 ctx->Driver.NotifySaveBegin = _save_NotifyBegin;
1676
1677 _save_vtxfmt_init( ctx );
1678 _save_current_init( ctx );
1679
1680 /* Hook our array functions into the outside-begin-end vtxfmt in
1681 * ctx->ListState.
1682 */
1683 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
1684 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
1685 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
1686 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
1687 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1688 }
1689
1690
1691 /**
1692 * Deallocate the immediate-mode buffer for the given context, if
1693 * its reference count goes to zero.
1694 */
1695 void _tnl_save_destroy( GLcontext *ctx )
1696 {
1697 (void) ctx;
1698 }