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