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