fixup vertex building code ..
[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 store->used = 0;
183 store->refcount = 1;
184 return store;
185 }
186
187 static struct tnl_primitive_store *alloc_prim_store( GLcontext *ctx )
188 {
189 struct tnl_primitive_store *store = MALLOC_STRUCT(tnl_primitive_store);
190 store->used = 0;
191 store->refcount = 1;
192 return store;
193 }
194
195 static void _save_reset_counters( GLcontext *ctx )
196 {
197 TNLcontext *tnl = TNL_CONTEXT(ctx);
198
199 tnl->save.prim = tnl->save.prim_store->buffer + tnl->save.prim_store->used;
200 tnl->save.buffer = (tnl->save.vertex_store->buffer +
201 tnl->save.vertex_store->used);
202
203 if (tnl->save.vertex_size)
204 tnl->save.initial_counter = ((SAVE_BUFFER_SIZE -
205 tnl->save.vertex_store->used) /
206 tnl->save.vertex_size);
207 else
208 tnl->save.initial_counter = 0;
209
210 if (tnl->save.initial_counter > ctx->Const.MaxArrayLockSize )
211 tnl->save.initial_counter = ctx->Const.MaxArrayLockSize;
212
213 tnl->save.counter = tnl->save.initial_counter;
214 tnl->save.prim_count = 0;
215 tnl->save.prim_max = SAVE_PRIM_SIZE - tnl->save.prim_store->used;
216 tnl->save.copied.nr = 0;
217 tnl->save.dangling_attr_ref = 0;
218 }
219
220
221 /* Insert the active immediate struct onto the display list currently
222 * being built.
223 */
224 static void _save_compile_vertex_list( GLcontext *ctx )
225 {
226 TNLcontext *tnl = TNL_CONTEXT(ctx);
227 struct tnl_vertex_list *node;
228
229 /* Allocate space for this structure in the display list currently
230 * being compiled.
231 */
232 node = (struct tnl_vertex_list *)
233 _mesa_alloc_instruction(ctx, tnl->save.opcode_vertex_list, sizeof(*node));
234
235 if (!node)
236 return;
237
238 /* Duplicate our template, increment refcounts to the storage structs:
239 */
240 _mesa_memcpy(node->attrsz, tnl->save.attrsz, sizeof(node->attrsz));
241 node->vertex_size = tnl->save.vertex_size;
242 node->buffer = tnl->save.buffer;
243 node->wrap_count = tnl->save.copied.nr;
244 node->count = tnl->save.initial_counter - tnl->save.counter;
245 node->prim = tnl->save.prim;
246 node->prim_count = tnl->save.prim_count;
247 node->vertex_store = tnl->save.vertex_store;
248 node->prim_store = tnl->save.prim_store;
249 node->dangling_attr_ref = tnl->save.dangling_attr_ref;
250 node->normal_lengths = 0;
251
252 node->vertex_store->refcount++;
253 node->prim_store->refcount++;
254
255 assert(node->attrsz[_TNL_ATTRIB_POS] != 0 ||
256 node->count == 0);
257
258 /* Maybe calculate normal lengths:
259 */
260 if (tnl->CalcDListNormalLengths &&
261 node->attrsz[_TNL_ATTRIB_NORMAL] == 3 &&
262 !node->dangling_attr_ref)
263 build_normal_lengths( node );
264
265 tnl->save.vertex_store->used += tnl->save.vertex_size * node->count;
266 tnl->save.prim_store->used += node->prim_count;
267
268 /* Decide whether the storage structs are full, or can be used for
269 * the next vertex lists as well.
270 */
271 if (tnl->save.vertex_store->used >
272 SAVE_BUFFER_SIZE - 16 * (tnl->save.vertex_size + 4)) {
273
274 tnl->save.vertex_store->refcount--;
275 assert(tnl->save.vertex_store->refcount != 0);
276 tnl->save.vertex_store = alloc_vertex_store( ctx );
277 tnl->save.vbptr = tnl->save.vertex_store->buffer;
278 }
279
280 if (tnl->save.prim_store->used > SAVE_PRIM_SIZE - 6) {
281 tnl->save.prim_store->refcount--;
282 assert(tnl->save.prim_store->refcount != 0);
283 tnl->save.prim_store = alloc_prim_store( ctx );
284 }
285
286 /* Reset our structures for the next run of vertices:
287 */
288 _save_reset_counters( ctx );
289
290 /* Copy duplicated vertices
291 */
292 tnl->save.copied.nr = _save_copy_vertices( ctx, node );
293
294
295 /* Deal with GL_COMPILE_AND_EXECUTE:
296 */
297 if (ctx->ExecuteFlag) {
298 _tnl_playback_vertex_list( ctx, (void *) node );
299 }
300 }
301
302
303 /* TODO -- If no new vertices have been stored, don't bother saving
304 * it.
305 */
306 static void _save_wrap_buffers( GLcontext *ctx )
307 {
308 TNLcontext *tnl = TNL_CONTEXT(ctx);
309 GLint i = tnl->save.prim_count - 1;
310 GLenum mode;
311
312 assert(i < (GLint) tnl->save.prim_max);
313 assert(i >= 0);
314
315 /* Close off in-progress primitive.
316 */
317 tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
318 tnl->save.prim[i].start);
319 mode = tnl->save.prim[i].mode & ~(PRIM_BEGIN|PRIM_END);
320
321 /* store the copied vertices, and allocate a new list.
322 */
323 _save_compile_vertex_list( ctx );
324
325 /* Restart interrupted primitive
326 */
327 tnl->save.prim[0].mode = mode;
328 tnl->save.prim[0].start = 0;
329 tnl->save.prim[0].count = 0;
330 tnl->save.prim_count = 1;
331 }
332
333
334
335 /* Called only when buffers are wrapped as the result of filling the
336 * vertex_store struct.
337 */
338 static void _save_wrap_filled_vertex( GLcontext *ctx )
339 {
340 TNLcontext *tnl = TNL_CONTEXT(ctx);
341 GLfloat *data = tnl->save.copied.buffer;
342 GLuint i;
343
344 /* Emit a glEnd to close off the last vertex list.
345 */
346 _save_wrap_buffers( ctx );
347
348 /* Copy stored stored vertices to start of new list.
349 */
350 assert(tnl->save.counter > tnl->save.copied.nr);
351
352 for (i = 0 ; i < tnl->save.copied.nr ; i++) {
353 _mesa_memcpy( tnl->save.vbptr, data, tnl->save.vertex_size * sizeof(GLfloat));
354 data += tnl->save.vertex_size;
355 tnl->save.vbptr += tnl->save.vertex_size;
356 tnl->save.counter--;
357 }
358 }
359
360
361 static void _save_copy_to_current( GLcontext *ctx )
362 {
363 TNLcontext *tnl = TNL_CONTEXT(ctx);
364 GLuint i;
365
366 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++) {
367 if (tnl->save.attrsz[i]) {
368 tnl->save.currentsz[i][0] = tnl->save.attrsz[i];
369 ASSIGN_4V(tnl->save.current[i], 0, 0, 0, 1);
370 COPY_SZ_4V(tnl->save.current[i],
371 tnl->save.attrsz[i],
372 tnl->save.attrptr[i]);
373 }
374 }
375
376 /* Edgeflag requires special treatment:
377 */
378 if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
379 ctx->ListState.ActiveEdgeFlag = 1;
380 ctx->ListState.CurrentEdgeFlag =
381 (tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] == 1.0);
382 }
383 }
384
385
386 static void _save_copy_from_current( GLcontext *ctx )
387 {
388 TNLcontext *tnl = TNL_CONTEXT(ctx);
389 GLint i;
390
391 for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_INDEX ; i++)
392 switch (tnl->save.attrsz[i]) {
393 case 4: tnl->save.attrptr[i][3] = tnl->save.current[i][3];
394 case 3: tnl->save.attrptr[i][2] = tnl->save.current[i][2];
395 case 2: tnl->save.attrptr[i][1] = tnl->save.current[i][1];
396 case 1: tnl->save.attrptr[i][0] = tnl->save.current[i][0];
397 case 0: break;
398 }
399
400 /* Edgeflag requires special treatment:
401 */
402 if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG])
403 tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] =
404 (GLfloat)ctx->ListState.CurrentEdgeFlag;
405 }
406
407
408
409
410 /* Flush existing data, set new attrib size, replay copied vertices.
411 */
412 static void _save_upgrade_vertex( GLcontext *ctx,
413 GLuint attr,
414 GLuint newsz )
415 {
416 TNLcontext *tnl = TNL_CONTEXT(ctx);
417 GLuint oldsz;
418 GLuint i;
419 GLfloat *tmp;
420
421 /* Store the current run of vertices, and emit a GL_END. Emit a
422 * BEGIN in the new buffer.
423 */
424 if (tnl->save.initial_counter != tnl->save.counter)
425 _save_wrap_buffers( ctx );
426 else
427 assert( tnl->save.copied.nr == 0 );
428
429 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
430 * when the attribute already exists in the vertex and is having
431 * its size increased.
432 */
433 _save_copy_to_current( ctx );
434
435 /* Fix up sizes:
436 */
437 oldsz = tnl->save.attrsz[attr];
438 tnl->save.attrsz[attr] = newsz;
439
440 tnl->save.vertex_size += newsz - oldsz;
441 tnl->save.counter = ((SAVE_BUFFER_SIZE - tnl->save.vertex_store->used) /
442 tnl->save.vertex_size);
443 if (tnl->save.counter > ctx->Const.MaxArrayLockSize )
444 tnl->save.counter = ctx->Const.MaxArrayLockSize;
445 tnl->save.initial_counter = tnl->save.counter;
446
447
448 /* Recalculate all the attrptr[] values:
449 */
450 for (i = 0, tmp = tnl->save.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
451 if (tnl->save.attrsz[i]) {
452 tnl->save.attrptr[i] = tmp;
453 tmp += tnl->save.attrsz[i];
454 }
455 else
456 tnl->save.attrptr[i] = 0; /* will not be dereferenced. */
457 }
458
459 /* Copy from current to repopulate the vertex with correct values.
460 */
461 _save_copy_from_current( ctx );
462
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) {
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 ASSIGN_4V( dest, 0, 0, 0, 1 );
502 COPY_SZ_4V( dest, oldsz, data );
503 data += oldsz;
504 dest += newsz;
505 }
506 else {
507 GLint sz = tnl->save.attrsz[j];
508 COPY_SZ_4V( dest, sz, data );
509 data += sz;
510 dest += sz;
511 }
512 }
513 }
514 }
515
516 tnl->save.vbptr = dest;
517 tnl->save.counter -= tnl->save.copied.nr;
518 }
519 }
520
521
522
523
524 /* Helper function for 'CHOOSE' macro. Do what's necessary when an
525 * entrypoint is called for the first time.
526 */
527 static void do_choose( GLuint attr, GLuint sz,
528 void (*attr_func)( const GLfloat *),
529 void (*choose1)( const GLfloat *),
530 void (*choose2)( const GLfloat *),
531 void (*choose3)( const GLfloat *),
532 void (*choose4)( const GLfloat *),
533 const GLfloat *v )
534 {
535 GET_CURRENT_CONTEXT( ctx );
536 TNLcontext *tnl = TNL_CONTEXT(ctx);
537 static GLfloat id[4] = { 0, 0, 0, 1 };
538 int i;
539
540 if (tnl->save.attrsz[attr] < sz) {
541 /* New size is larger. Need to flush existing vertices and get
542 * an enlarged vertex format.
543 */
544 _save_upgrade_vertex( ctx, attr, sz );
545 }
546 else {
547 /* New size is equal or smaller - just need to fill in some
548 * zeros.
549 */
550 for (i = sz ; i <= tnl->save.attrsz[attr] ; i++)
551 tnl->save.attrptr[attr][i-1] = id[i-1];
552 }
553
554 /* Reset any active pointers for this attribute
555 */
556 tnl->save.tabfv[attr][0] = choose1;
557 tnl->save.tabfv[attr][1] = choose2;
558 tnl->save.tabfv[attr][2] = choose3;
559 tnl->save.tabfv[attr][3] = choose4;
560
561 /* Update the secondary dispatch table with the new function
562 */
563 tnl->save.tabfv[attr][sz-1] = attr_func;
564
565 (*attr_func)(v);
566 }
567
568
569
570 /* Only one size for each attribute may be active at once. Eg. if
571 * Color3f is installed/active, then Color4f may not be, even if the
572 * vertex actually contains 4 color coordinates. This is because the
573 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
574 * of the chooser function when switching between Color4f and Color3f.
575 */
576 #define ATTRFV( ATTR, N ) \
577 static void save_choose_##ATTR##_##N( const GLfloat *v ); \
578 \
579 static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
580 { \
581 GET_CURRENT_CONTEXT( ctx ); \
582 TNLcontext *tnl = TNL_CONTEXT(ctx); \
583 \
584 if ((ATTR) == 0) { \
585 GLuint i; \
586 \
587 if (N>0) tnl->save.vbptr[0] = v[0]; \
588 if (N>1) tnl->save.vbptr[1] = v[1]; \
589 if (N>2) tnl->save.vbptr[2] = v[2]; \
590 if (N>3) tnl->save.vbptr[3] = v[3]; \
591 \
592 for (i = N; i < tnl->save.vertex_size; i++) \
593 tnl->save.vbptr[i] = tnl->save.vertex[i]; \
594 \
595 tnl->save.vbptr += tnl->save.vertex_size; \
596 \
597 if (--tnl->save.counter == 0) \
598 _save_wrap_filled_vertex( ctx ); \
599 } \
600 else { \
601 GLfloat *dest = tnl->save.attrptr[ATTR]; \
602 if (N>0) dest[0] = v[0]; \
603 if (N>1) dest[1] = v[1]; \
604 if (N>2) dest[2] = v[2]; \
605 if (N>3) dest[3] = v[3]; \
606 } \
607 }
608
609 #define CHOOSE( ATTR, N ) \
610 static void save_choose_##ATTR##_##N( const GLfloat *v ) \
611 { \
612 do_choose(ATTR, N, \
613 save_attrib_##ATTR##_##N, \
614 save_choose_##ATTR##_1, \
615 save_choose_##ATTR##_2, \
616 save_choose_##ATTR##_3, \
617 save_choose_##ATTR##_4, \
618 v ); \
619 }
620
621 #define INIT(ATTR) \
622 static void save_init_##ATTR( TNLcontext *tnl ) \
623 { \
624 tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
625 tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
626 tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
627 tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
628 }
629
630 #define ATTRS( ATTRIB ) \
631 ATTRFV( ATTRIB, 1 ) \
632 ATTRFV( ATTRIB, 2 ) \
633 ATTRFV( ATTRIB, 3 ) \
634 ATTRFV( ATTRIB, 4 ) \
635 CHOOSE( ATTRIB, 1 ) \
636 CHOOSE( ATTRIB, 2 ) \
637 CHOOSE( ATTRIB, 3 ) \
638 CHOOSE( ATTRIB, 4 ) \
639 INIT( ATTRIB ) \
640
641
642 /* Generate a lot of functions. These are the actual worker
643 * functions, which are equivalent to those generated via codegen
644 * elsewhere.
645 */
646 ATTRS( 0 )
647 ATTRS( 1 )
648 ATTRS( 2 )
649 ATTRS( 3 )
650 ATTRS( 4 )
651 ATTRS( 5 )
652 ATTRS( 6 )
653 ATTRS( 7 )
654 ATTRS( 8 )
655 ATTRS( 9 )
656 ATTRS( 10 )
657 ATTRS( 11 )
658 ATTRS( 12 )
659 ATTRS( 13 )
660 ATTRS( 14 )
661 ATTRS( 15 )
662
663
664 static void _save_reset_vertex( GLcontext *ctx )
665 {
666 TNLcontext *tnl = TNL_CONTEXT(ctx);
667 GLuint i;
668
669 save_init_0( tnl );
670 save_init_1( tnl );
671 save_init_2( tnl );
672 save_init_3( tnl );
673 save_init_4( tnl );
674 save_init_5( tnl );
675 save_init_6( tnl );
676 save_init_7( tnl );
677 save_init_8( tnl );
678 save_init_9( tnl );
679 save_init_10( tnl );
680 save_init_11( tnl );
681 save_init_12( tnl );
682 save_init_13( tnl );
683 save_init_14( tnl );
684 save_init_15( tnl );
685
686 for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
687 tnl->save.attrsz[i] = 0;
688
689 tnl->save.vertex_size = 0;
690 tnl->save.have_materials = 0;
691
692 _save_reset_counters( ctx );
693 }
694
695
696
697 /* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
698 * of glMultTexCoord and glProgramParamterNV by routing all these
699 * through a second level dispatch table.
700 */
701 #define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
702 do { \
703 GET_CURRENT_CONTEXT( ctx ); \
704 TNLcontext *tnl = TNL_CONTEXT(ctx); \
705 tnl->save.tabfv[ATTR][COUNT-1]( P ); \
706 } while (0)
707
708 #define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
709 #define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
710 #define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
711 #define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
712
713 #define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
714
715 #define DISPATCH_ATTR2F( ATTR, S,T ) \
716 do { \
717 GLfloat v[2]; \
718 v[0] = S; v[1] = T; \
719 DISPATCH_ATTR2FV( ATTR, v ); \
720 } while (0)
721 #define DISPATCH_ATTR3F( ATTR, S,T,R ) \
722 do { \
723 GLfloat v[3]; \
724 v[0] = S; v[1] = T; v[2] = R; \
725 DISPATCH_ATTR3FV( ATTR, v ); \
726 } while (0)
727 #define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
728 do { \
729 GLfloat v[4]; \
730 v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
731 DISPATCH_ATTR4FV( ATTR, v ); \
732 } while (0)
733
734
735 static void enum_error( void )
736 {
737 GET_CURRENT_CONTEXT( ctx );
738 _mesa_compile_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
739 }
740
741 static void GLAPIENTRY _save_Vertex2f( GLfloat x, GLfloat y )
742 {
743 DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
744 }
745
746 static void GLAPIENTRY _save_Vertex2fv( const GLfloat *v )
747 {
748 DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
749 }
750
751 static void GLAPIENTRY _save_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
752 {
753 DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
754 }
755
756 static void GLAPIENTRY _save_Vertex3fv( const GLfloat *v )
757 {
758 DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
759 }
760
761 static void GLAPIENTRY _save_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
762 {
763 DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
764 }
765
766 static void GLAPIENTRY _save_Vertex4fv( const GLfloat *v )
767 {
768 DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
769 }
770
771 static void GLAPIENTRY _save_TexCoord1f( GLfloat x )
772 {
773 DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
774 }
775
776 static void GLAPIENTRY _save_TexCoord1fv( const GLfloat *v )
777 {
778 DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
779 }
780
781 static void GLAPIENTRY _save_TexCoord2f( GLfloat x, GLfloat y )
782 {
783 DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
784 }
785
786 static void GLAPIENTRY _save_TexCoord2fv( const GLfloat *v )
787 {
788 DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
789 }
790
791 static void GLAPIENTRY _save_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
792 {
793 DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
794 }
795
796 static void GLAPIENTRY _save_TexCoord3fv( const GLfloat *v )
797 {
798 DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
799 }
800
801 static void GLAPIENTRY _save_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
802 {
803 DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
804 }
805
806 static void GLAPIENTRY _save_TexCoord4fv( const GLfloat *v )
807 {
808 DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
809 }
810
811 static void GLAPIENTRY _save_Normal3f( GLfloat x, GLfloat y, GLfloat z )
812 {
813 DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
814 }
815
816 static void GLAPIENTRY _save_Normal3fv( const GLfloat *v )
817 {
818 DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
819 }
820
821 static void GLAPIENTRY _save_FogCoordfEXT( GLfloat x )
822 {
823 DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
824 }
825
826 static void GLAPIENTRY _save_FogCoordfvEXT( const GLfloat *v )
827 {
828 DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
829 }
830
831 static void GLAPIENTRY _save_Color3f( GLfloat x, GLfloat y, GLfloat z )
832 {
833 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
834 }
835
836 static void GLAPIENTRY _save_Color3fv( const GLfloat *v )
837 {
838 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
839 }
840
841 static void GLAPIENTRY _save_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
842 {
843 DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
844 }
845
846 static void GLAPIENTRY _save_Color4fv( const GLfloat *v )
847 {
848 DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
849 }
850
851 static void GLAPIENTRY _save_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
852 {
853 DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
854 }
855
856 static void GLAPIENTRY _save_SecondaryColor3fvEXT( const GLfloat *v )
857 {
858 DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
859 }
860
861 static void GLAPIENTRY _save_MultiTexCoord1f( GLenum target, GLfloat x )
862 {
863 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
864 DISPATCH_ATTR1F( attr, x );
865 }
866
867 static void GLAPIENTRY _save_MultiTexCoord1fv( GLenum target, const GLfloat *v )
868 {
869 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
870 DISPATCH_ATTR1FV( attr, v );
871 }
872
873 static void GLAPIENTRY _save_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
874 {
875 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
876 DISPATCH_ATTR2F( attr, x, y );
877 }
878
879 static void GLAPIENTRY _save_MultiTexCoord2fv( GLenum target, const GLfloat *v )
880 {
881 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
882 DISPATCH_ATTR2FV( attr, v );
883 }
884
885 static void GLAPIENTRY _save_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
886 GLfloat z)
887 {
888 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
889 DISPATCH_ATTR3F( attr, x, y, z );
890 }
891
892 static void GLAPIENTRY _save_MultiTexCoord3fv( GLenum target, const GLfloat *v )
893 {
894 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
895 DISPATCH_ATTR3FV( attr, v );
896 }
897
898 static void GLAPIENTRY _save_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
899 GLfloat z, GLfloat w )
900 {
901 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
902 DISPATCH_ATTR4F( attr, x, y, z, w );
903 }
904
905 static void GLAPIENTRY _save_MultiTexCoord4fv( GLenum target, const GLfloat *v )
906 {
907 GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
908 DISPATCH_ATTR4FV( attr, v );
909 }
910
911 static void GLAPIENTRY _save_VertexAttrib1fNV( GLuint index, GLfloat x )
912 {
913 if (index < VERT_ATTRIB_MAX)
914 DISPATCH_ATTR1F( index, x );
915 else
916 enum_error();
917 }
918
919 static void GLAPIENTRY _save_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
920 {
921 if (index < VERT_ATTRIB_MAX)
922 DISPATCH_ATTR1FV( index, v );
923 else
924 enum_error();
925 }
926
927 static void GLAPIENTRY _save_VertexAttrib2fNV( GLuint index, GLfloat x, GLfloat y )
928 {
929 if (index < VERT_ATTRIB_MAX)
930 DISPATCH_ATTR2F( index, x, y );
931 else
932 enum_error();
933 }
934
935 static void GLAPIENTRY _save_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
936 {
937 if (index < VERT_ATTRIB_MAX)
938 DISPATCH_ATTR2FV( index, v );
939 else
940 enum_error();
941 }
942
943 static void GLAPIENTRY _save_VertexAttrib3fNV( GLuint index, GLfloat x, GLfloat y,
944 GLfloat z )
945 {
946 if (index < VERT_ATTRIB_MAX)
947 DISPATCH_ATTR3F( index, x, y, z );
948 else
949 enum_error();
950 }
951
952 static void GLAPIENTRY _save_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
953 {
954 if (index < VERT_ATTRIB_MAX)
955 DISPATCH_ATTR3FV( index, v );
956 else
957 enum_error();
958 }
959
960 static void GLAPIENTRY _save_VertexAttrib4fNV( GLuint index, GLfloat x, GLfloat y,
961 GLfloat z, GLfloat w )
962 {
963 if (index < VERT_ATTRIB_MAX)
964 DISPATCH_ATTR4F( index, x, y, z, w );
965 else
966 enum_error();
967 }
968
969 static void GLAPIENTRY _save_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
970 {
971 if (index < VERT_ATTRIB_MAX)
972 DISPATCH_ATTR4FV( index, v );
973 else
974 enum_error();
975 }
976
977
978 /* Materials:
979 *
980 * These are treated as per-vertex attributes, at indices above where
981 * the NV_vertex_program leaves off. There are a lot of good things
982 * about treating materials this way.
983 *
984 * However: I don't want to double the number of generated functions
985 * just to cope with this, so I unroll the 'C' varients of CHOOSE and
986 * ATTRF into this function, and dispense with codegen and
987 * second-level dispatch.
988 *
989 * There is no aliasing of material attributes with other entrypoints.
990 */
991 #define MAT_ATTR( A, N, params ) \
992 do { \
993 if (tnl->save.attrsz[A] < N) { \
994 _save_upgrade_vertex( ctx, A, N ); \
995 tnl->save.have_materials = GL_TRUE; \
996 } \
997 \
998 { \
999 GLfloat *dest = tnl->save.attrptr[A]; \
1000 if (N>0) dest[0] = params[0]; \
1001 if (N>1) dest[1] = params[1]; \
1002 if (N>2) dest[2] = params[2]; \
1003 if (N>3) dest[3] = params[3]; \
1004 } \
1005 } while (0)
1006
1007
1008 #define MAT( ATTR, N, face, params ) \
1009 do { \
1010 if (face != GL_BACK) \
1011 MAT_ATTR( ATTR, N, params ); /* front */ \
1012 if (face != GL_FRONT) \
1013 MAT_ATTR( ATTR + 1, N, params ); /* back */ \
1014 } while (0)
1015
1016
1017 /* NOTE: Have to remove/deal-with colormaterial crossovers, probably
1018 * later on - in the meantime just store everything.
1019 */
1020 static void GLAPIENTRY _save_Materialfv( GLenum face, GLenum pname,
1021 const GLfloat *params )
1022 {
1023 GET_CURRENT_CONTEXT( ctx );
1024 TNLcontext *tnl = TNL_CONTEXT(ctx);
1025
1026 switch (pname) {
1027 case GL_EMISSION:
1028 MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
1029 break;
1030 case GL_AMBIENT:
1031 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
1032 break;
1033 case GL_DIFFUSE:
1034 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
1035 break;
1036 case GL_SPECULAR:
1037 MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
1038 break;
1039 case GL_SHININESS:
1040 MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
1041 break;
1042 case GL_COLOR_INDEXES:
1043 MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
1044 break;
1045 case GL_AMBIENT_AND_DIFFUSE:
1046 MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
1047 MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
1048 break;
1049 default:
1050 _mesa_compile_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
1051 return;
1052 }
1053 }
1054
1055
1056 #define IDX_ATTR( A, IDX ) \
1057 do { \
1058 GET_CURRENT_CONTEXT( ctx ); \
1059 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1060 \
1061 if (tnl->save.attrsz[A] < 1) { \
1062 _save_upgrade_vertex( ctx, A, 1 ); \
1063 } \
1064 \
1065 { \
1066 GLfloat *dest = tnl->save.attrptr[A]; \
1067 dest[0] = IDX; \
1068 } \
1069 } while (0)
1070
1071
1072 static void GLAPIENTRY _save_EdgeFlag( GLboolean b )
1073 {
1074 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
1075 }
1076
1077 static void GLAPIENTRY _save_EdgeFlagv( const GLboolean *v )
1078 {
1079 IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)(v[0]) );
1080 }
1081
1082 static void GLAPIENTRY _save_Indexf( GLfloat f )
1083 {
1084 IDX_ATTR( _TNL_ATTRIB_INDEX, f );
1085 }
1086
1087 static void GLAPIENTRY _save_Indexfv( const GLfloat *f )
1088 {
1089 IDX_ATTR( _TNL_ATTRIB_INDEX, f[0] );
1090 }
1091
1092
1093
1094
1095 /* Cope with EvalCoord/CallList called within a begin/end object:
1096 * -- Flush current buffer
1097 * -- Fallback to opcodes for the rest of the begin/end object.
1098 */
1099 #define FALLBACK(ctx) \
1100 do { \
1101 TNLcontext *tnl = TNL_CONTEXT(ctx); \
1102 \
1103 /*fprintf(stderr, "fallback %s inside begin/end\n", __FUNCTION__);*/ \
1104 \
1105 if (tnl->save.initial_counter != tnl->save.counter || \
1106 tnl->save.prim_count) \
1107 _save_compile_vertex_list( ctx ); \
1108 \
1109 _save_copy_to_current( ctx ); \
1110 _save_reset_vertex( ctx ); \
1111 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
1112 ctx->Driver.SaveNeedFlush = 0; \
1113 } while (0)
1114
1115 static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
1116 {
1117 GET_CURRENT_CONTEXT(ctx);
1118 FALLBACK(ctx);
1119 ctx->Save->EvalCoord1f( u );
1120 }
1121
1122 static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
1123 {
1124 GET_CURRENT_CONTEXT(ctx);
1125 FALLBACK(ctx);
1126 ctx->Save->EvalCoord1fv( v );
1127 }
1128
1129 static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
1130 {
1131 GET_CURRENT_CONTEXT(ctx);
1132 FALLBACK(ctx);
1133 ctx->Save->EvalCoord2f( u, v );
1134 }
1135
1136 static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
1137 {
1138 GET_CURRENT_CONTEXT(ctx);
1139 FALLBACK(ctx);
1140 ctx->Save->EvalCoord2fv( v );
1141 }
1142
1143 static void GLAPIENTRY _save_EvalPoint1( GLint i )
1144 {
1145 GET_CURRENT_CONTEXT(ctx);
1146 FALLBACK(ctx);
1147 ctx->Save->EvalPoint1( i );
1148 }
1149
1150 static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
1151 {
1152 GET_CURRENT_CONTEXT(ctx);
1153 FALLBACK(ctx);
1154 ctx->Save->EvalPoint2( i, j );
1155 }
1156
1157 static void GLAPIENTRY _save_CallList( GLuint l )
1158 {
1159 GET_CURRENT_CONTEXT(ctx);
1160 FALLBACK(ctx);
1161 ctx->Save->CallList( l );
1162 }
1163
1164 static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
1165 {
1166 GET_CURRENT_CONTEXT(ctx);
1167 FALLBACK(ctx);
1168 ctx->Save->CallLists( n, type, v );
1169 }
1170
1171
1172
1173
1174 /* This begin is hooked into ... Updating of
1175 * ctx->Driver.CurrentSavePrimitive is already taken care of.
1176 */
1177 static GLboolean _save_NotifyBegin( GLcontext *ctx, GLenum mode )
1178 {
1179 TNLcontext *tnl = TNL_CONTEXT(ctx);
1180
1181 if (1) {
1182 GLuint i = tnl->save.prim_count++;
1183
1184 assert(i < tnl->save.prim_max);
1185 tnl->save.prim[i].mode = mode | PRIM_BEGIN;
1186 tnl->save.prim[i].start = tnl->save.initial_counter - tnl->save.counter;
1187 tnl->save.prim[i].count = 0;
1188
1189 _mesa_install_save_vtxfmt( ctx, &tnl->save_vtxfmt );
1190 ctx->Driver.SaveNeedFlush = 1;
1191 return GL_TRUE;
1192 }
1193 else
1194 return GL_FALSE;
1195 }
1196
1197
1198
1199 static void GLAPIENTRY _save_End( void )
1200 {
1201 GET_CURRENT_CONTEXT( ctx );
1202 TNLcontext *tnl = TNL_CONTEXT(ctx);
1203 GLint i = tnl->save.prim_count - 1;
1204
1205 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1206 tnl->save.prim[i].mode |= PRIM_END;
1207 tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
1208 tnl->save.prim[i].start);
1209
1210 if (i == (GLint) tnl->save.prim_max - 1) {
1211 _save_compile_vertex_list( ctx );
1212 assert(tnl->save.copied.nr == 0);
1213 }
1214
1215 /* Swap out this vertex format while outside begin/end. Any color,
1216 * etc. received between here and the next begin will be compiled
1217 * as opcodes.
1218 */
1219 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1220 }
1221
1222
1223 /* These are all errors as this vtxfmt is only installed inside
1224 * begin/end pairs.
1225 */
1226 static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
1227 const GLvoid *indices)
1228 {
1229 GET_CURRENT_CONTEXT(ctx);
1230 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
1231 }
1232
1233
1234 static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
1235 GLuint start, GLuint end,
1236 GLsizei count, GLenum type,
1237 const GLvoid *indices)
1238 {
1239 GET_CURRENT_CONTEXT(ctx);
1240 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
1241 }
1242
1243 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
1244 {
1245 GET_CURRENT_CONTEXT(ctx);
1246 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
1247 }
1248
1249 static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
1250 {
1251 GET_CURRENT_CONTEXT(ctx);
1252 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
1253 }
1254
1255 static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
1256 {
1257 GET_CURRENT_CONTEXT(ctx);
1258 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
1259 }
1260
1261 static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
1262 GLint j1, GLint j2 )
1263 {
1264 GET_CURRENT_CONTEXT(ctx);
1265 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
1266 }
1267
1268 static void GLAPIENTRY _save_Begin( GLenum mode )
1269 {
1270 GET_CURRENT_CONTEXT( ctx );
1271 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
1272 }
1273
1274
1275 /* Unlike the functions above, these are to be hooked into the vtxfmt
1276 * maintained in ctx->ListState, active when the list is known or
1277 * suspected to be outside any begin/end primitive.
1278 */
1279 static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
1280 {
1281 GET_CURRENT_CONTEXT(ctx);
1282 _save_NotifyBegin( ctx, GL_QUADS | PRIM_WEAK );
1283 _glapi_Dispatch->Vertex2f( x1, y1 );
1284 _glapi_Dispatch->Vertex2f( x2, y1 );
1285 _glapi_Dispatch->Vertex2f( x2, y2 );
1286 _glapi_Dispatch->Vertex2f( x1, y2 );
1287 _glapi_Dispatch->End();
1288 }
1289
1290
1291 static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1292 {
1293 GET_CURRENT_CONTEXT(ctx);
1294 GLint i;
1295
1296 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
1297 return;
1298
1299 _save_NotifyBegin( ctx, mode | PRIM_WEAK );
1300 for (i = start ; i < count ; i++)
1301 _glapi_Dispatch->ArrayElement( i );
1302 _glapi_Dispatch->End();
1303 }
1304
1305
1306 static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1307 const GLvoid *indices)
1308 {
1309 GET_CURRENT_CONTEXT(ctx);
1310 GLint i;
1311
1312 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
1313 return;
1314
1315 _save_NotifyBegin( ctx, mode | PRIM_WEAK );
1316
1317 switch (type) {
1318 case GL_UNSIGNED_BYTE:
1319 for (i = 0 ; i < count ; i++)
1320 _glapi_Dispatch->ArrayElement( ((GLubyte *)indices)[i] );
1321 break;
1322 case GL_UNSIGNED_SHORT:
1323 for (i = 0 ; i < count ; i++)
1324 _glapi_Dispatch->ArrayElement( ((GLushort *)indices)[i] );
1325 break;
1326 case GL_UNSIGNED_INT:
1327 for (i = 0 ; i < count ; i++)
1328 _glapi_Dispatch->ArrayElement( ((GLuint *)indices)[i] );
1329 break;
1330 default:
1331 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
1332 break;
1333 }
1334
1335 _glapi_Dispatch->End();
1336 }
1337
1338 static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
1339 GLuint start, GLuint end,
1340 GLsizei count, GLenum type,
1341 const GLvoid *indices)
1342 {
1343 GET_CURRENT_CONTEXT(ctx);
1344 if (_mesa_validate_DrawRangeElements( ctx, mode,
1345 start, end,
1346 count, type, indices ))
1347 _save_OBE_DrawElements( mode, count, type, indices );
1348 }
1349
1350
1351
1352
1353
1354 static void _save_vtxfmt_init( GLcontext *ctx )
1355 {
1356 TNLcontext *tnl = TNL_CONTEXT(ctx);
1357 GLvertexformat *vfmt = &tnl->save_vtxfmt;
1358
1359 vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
1360 vfmt->Begin = _save_Begin;
1361 vfmt->Color3f = _save_Color3f;
1362 vfmt->Color3fv = _save_Color3fv;
1363 vfmt->Color4f = _save_Color4f;
1364 vfmt->Color4fv = _save_Color4fv;
1365 vfmt->EdgeFlag = _save_EdgeFlag;
1366 vfmt->EdgeFlagv = _save_EdgeFlagv;
1367 vfmt->End = _save_End;
1368 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1369 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1370 vfmt->Indexf = _save_Indexf;
1371 vfmt->Indexfv = _save_Indexfv;
1372 vfmt->Materialfv = _save_Materialfv;
1373 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1374 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1375 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1376 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1377 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1378 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1379 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1380 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1381 vfmt->Normal3f = _save_Normal3f;
1382 vfmt->Normal3fv = _save_Normal3fv;
1383 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1384 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1385 vfmt->TexCoord1f = _save_TexCoord1f;
1386 vfmt->TexCoord1fv = _save_TexCoord1fv;
1387 vfmt->TexCoord2f = _save_TexCoord2f;
1388 vfmt->TexCoord2fv = _save_TexCoord2fv;
1389 vfmt->TexCoord3f = _save_TexCoord3f;
1390 vfmt->TexCoord3fv = _save_TexCoord3fv;
1391 vfmt->TexCoord4f = _save_TexCoord4f;
1392 vfmt->TexCoord4fv = _save_TexCoord4fv;
1393 vfmt->Vertex2f = _save_Vertex2f;
1394 vfmt->Vertex2fv = _save_Vertex2fv;
1395 vfmt->Vertex3f = _save_Vertex3f;
1396 vfmt->Vertex3fv = _save_Vertex3fv;
1397 vfmt->Vertex4f = _save_Vertex4f;
1398 vfmt->Vertex4fv = _save_Vertex4fv;
1399 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1400 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1401 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1402 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1403 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1404 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1405 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1406 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1407
1408 /* This will all require us to fallback to saving the list as opcodes:
1409 */
1410 vfmt->CallList = _save_CallList; /* inside begin/end */
1411 vfmt->CallLists = _save_CallLists; /* inside begin/end */
1412 vfmt->EvalCoord1f = _save_EvalCoord1f;
1413 vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1414 vfmt->EvalCoord2f = _save_EvalCoord2f;
1415 vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1416 vfmt->EvalPoint1 = _save_EvalPoint1;
1417 vfmt->EvalPoint2 = _save_EvalPoint2;
1418
1419 /* These are all errors as we at least know we are in some sort of
1420 * begin/end pair:
1421 */
1422 vfmt->EvalMesh1 = _save_EvalMesh1;
1423 vfmt->EvalMesh2 = _save_EvalMesh2;
1424 vfmt->Begin = _save_Begin;
1425 vfmt->Rectf = _save_Rectf;
1426 vfmt->DrawArrays = _save_DrawArrays;
1427 vfmt->DrawElements = _save_DrawElements;
1428 vfmt->DrawRangeElements = _save_DrawRangeElements;
1429
1430 }
1431
1432
1433 void _tnl_SaveFlushVertices( GLcontext *ctx )
1434 {
1435 TNLcontext *tnl = TNL_CONTEXT(ctx);
1436
1437 /* Noop when we are actually active:
1438 */
1439 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
1440 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
1441 return;
1442
1443 if (tnl->save.initial_counter != tnl->save.counter ||
1444 tnl->save.prim_count)
1445 _save_compile_vertex_list( ctx );
1446
1447 _save_copy_to_current( ctx );
1448 _save_reset_vertex( ctx );
1449 ctx->Driver.SaveNeedFlush = 0;
1450 }
1451
1452 void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
1453 {
1454 TNLcontext *tnl = TNL_CONTEXT(ctx);
1455
1456 if (!tnl->save.prim_store)
1457 tnl->save.prim_store = alloc_prim_store( ctx );
1458
1459 if (!tnl->save.vertex_store) {
1460 tnl->save.vertex_store = alloc_vertex_store( ctx );
1461 tnl->save.vbptr = tnl->save.vertex_store->buffer;
1462 }
1463
1464 _save_reset_vertex( ctx );
1465 ctx->Driver.SaveNeedFlush = 0;
1466 }
1467
1468 void _tnl_EndList( GLcontext *ctx )
1469 {
1470 TNLcontext *tnl = TNL_CONTEXT(ctx);
1471 assert(tnl->save.vertex_size == 0);
1472 }
1473
1474 void _tnl_BeginCallList( GLcontext *ctx, GLuint list )
1475 {
1476 }
1477
1478 void _tnl_EndCallList( GLcontext *ctx )
1479 {
1480 }
1481
1482
1483 static void _tnl_destroy_vertex_list( GLcontext *ctx, void *data )
1484 {
1485 struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
1486
1487 if ( --node->vertex_store->refcount == 0 )
1488 FREE( node->vertex_store );
1489
1490 if ( --node->prim_store->refcount == 0 )
1491 FREE( node->prim_store );
1492
1493 if ( node->normal_lengths )
1494 FREE( node->normal_lengths );
1495 }
1496
1497
1498 static void _tnl_print_vertex_list( GLcontext *ctx, void *data )
1499 {
1500 struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
1501 GLuint i;
1502
1503 _mesa_debug(0, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1504 node->count,
1505 node->prim_count,
1506 node->vertex_size);
1507
1508 for (i = 0 ; i < node->prim_count ; i++) {
1509 struct tnl_prim *prim = &node->prim[i];
1510 _mesa_debug(0, " prim %d: %s %d..%d %s %s\n",
1511 i,
1512 _mesa_lookup_enum_by_nr(prim->mode & PRIM_MODE_MASK),
1513 prim->start,
1514 prim->start + prim->count,
1515 (prim->mode & PRIM_BEGIN) ? "BEGIN" : "(wrap)",
1516 (prim->mode & PRIM_END) ? "END" : "(wrap)");
1517 }
1518 }
1519
1520
1521 static void _save_current_init( GLcontext *ctx )
1522 {
1523 TNLcontext *tnl = TNL_CONTEXT(ctx);
1524 GLint i;
1525
1526 for (i = 0; i < _TNL_ATTRIB_MAT_FRONT_AMBIENT; i++) {
1527 tnl->save.currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
1528 tnl->save.current[i] = ctx->ListState.CurrentAttrib[i];
1529 }
1530
1531 for (i = _TNL_ATTRIB_MAT_FRONT_AMBIENT; i < _TNL_ATTRIB_INDEX; i++) {
1532 tnl->save.currentsz[i] = &ctx->ListState.ActiveMaterialSize[i];
1533 tnl->save.current[i] = ctx->ListState.CurrentMaterial[i];
1534 }
1535
1536 tnl->save.currentsz[_TNL_ATTRIB_INDEX] = &ctx->ListState.ActiveIndex;
1537 tnl->save.current[_TNL_ATTRIB_INDEX] = &ctx->ListState.CurrentIndex;
1538
1539 /* Current edgeflag is handled individually */
1540 }
1541
1542 /**
1543 * Initialize the display list compiler
1544 */
1545 void _tnl_save_init( GLcontext *ctx )
1546 {
1547 TNLcontext *tnl = TNL_CONTEXT(ctx);
1548 struct tnl_vertex_arrays *tmp = &tnl->save_inputs;
1549 GLuint i;
1550
1551
1552 for (i = 0; i < _TNL_ATTRIB_MAX; i++)
1553 _mesa_vector4f_init( &tmp->Attribs[i], 0, 0);
1554
1555 tnl->save.opcode_vertex_list =
1556 _mesa_alloc_opcode( ctx,
1557 sizeof(struct tnl_vertex_list),
1558 _tnl_playback_vertex_list,
1559 _tnl_destroy_vertex_list,
1560 _tnl_print_vertex_list );
1561
1562 ctx->Driver.NotifySaveBegin = _save_NotifyBegin;
1563
1564 _save_vtxfmt_init( ctx );
1565 _save_current_init( ctx );
1566
1567 /* Hook our array functions into the outside-begin-end vtxfmt in
1568 * ctx->ListState.
1569 */
1570 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
1571 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
1572 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
1573 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
1574 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1575 }
1576
1577
1578 /**
1579 * Deallocate the immediate-mode buffer for the given context, if
1580 * its reference count goes to zero.
1581 */
1582 void _tnl_save_destroy( GLcontext *ctx )
1583 {
1584 }