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