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