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