Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / mesa / vbo / vbo_save_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 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 /* Display list compiler attempts to store lists of vertices with the
36 * same vertex layout. Additionally it attempts to minimize the need
37 * for execute-time fixup of these vertex lists, allowing them to be
38 * cached on hardware.
39 *
40 * There are still some circumstances where this can be thwarted, for
41 * example by building a list that consists of one very long primitive
42 * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43 * from inside a different begin/end object (Begin(Lines), CallList,
44 * End).
45 *
46 * In that case the code will have to replay the list as individual
47 * commands through the Exec dispatch table, or fix up the copied
48 * vertices at execute-time.
49 *
50 * The other case where fixup is required is when a vertex attribute
51 * is introduced in the middle of a primitive. Eg:
52 * Begin(Lines)
53 * TexCoord1f() Vertex2f()
54 * TexCoord1f() Color3f() Vertex2f()
55 * End()
56 *
57 * If the current value of Color isn't known at compile-time, this
58 * primitive will require fixup.
59 *
60 *
61 * The list compiler currently doesn't attempt to compile lists
62 * containing EvalCoord or EvalPoint commands. On encountering one of
63 * these, compilation falls back to opcodes.
64 *
65 * This could be improved to fallback only when a mix of EvalCoord and
66 * Vertex commands are issued within a single primitive.
67 */
68
69
70 #include "main/glheader.h"
71 #include "main/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/eval.h"
76 #include "main/macros.h"
77 #include "main/mfeatures.h"
78 #include "main/api_noop.h"
79 #include "main/api_validate.h"
80 #include "main/api_arrayelt.h"
81 #include "main/vtxfmt.h"
82 #include "main/dispatch.h"
83
84 #include "vbo_context.h"
85
86
87 #if FEATURE_dlist
88
89
90 #ifdef ERROR
91 #undef ERROR
92 #endif
93
94
95 /* An interesting VBO number/name to help with debugging */
96 #define VBO_BUF_ID 12345
97
98
99 /*
100 * NOTE: Old 'parity' issue is gone, but copying can still be
101 * wrong-footed on replay.
102 */
103 static GLuint _save_copy_vertices( struct gl_context *ctx,
104 const struct vbo_save_vertex_list *node,
105 const GLfloat *src_buffer)
106 {
107 struct vbo_save_context *save = &vbo_context( ctx )->save;
108 const struct _mesa_prim *prim = &node->prim[node->prim_count-1];
109 GLuint nr = prim->count;
110 GLuint sz = save->vertex_size;
111 const GLfloat *src = src_buffer + prim->start * sz;
112 GLfloat *dst = save->copied.buffer;
113 GLuint ovf, i;
114
115 if (prim->end)
116 return 0;
117
118 switch( prim->mode )
119 {
120 case GL_POINTS:
121 return 0;
122 case GL_LINES:
123 ovf = nr&1;
124 for (i = 0 ; i < ovf ; i++)
125 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
126 return i;
127 case GL_TRIANGLES:
128 ovf = nr%3;
129 for (i = 0 ; i < ovf ; i++)
130 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
131 return i;
132 case GL_QUADS:
133 ovf = nr&3;
134 for (i = 0 ; i < ovf ; i++)
135 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
136 return i;
137 case GL_LINE_STRIP:
138 if (nr == 0)
139 return 0;
140 else {
141 memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
142 return 1;
143 }
144 case GL_LINE_LOOP:
145 case GL_TRIANGLE_FAN:
146 case GL_POLYGON:
147 if (nr == 0)
148 return 0;
149 else if (nr == 1) {
150 memcpy( dst, src+0, sz*sizeof(GLfloat) );
151 return 1;
152 } else {
153 memcpy( dst, src+0, sz*sizeof(GLfloat) );
154 memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
155 return 2;
156 }
157 case GL_TRIANGLE_STRIP:
158 case GL_QUAD_STRIP:
159 switch (nr) {
160 case 0: ovf = 0; break;
161 case 1: ovf = 1; break;
162 default: ovf = 2 + (nr&1); break;
163 }
164 for (i = 0 ; i < ovf ; i++)
165 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
166 return i;
167 default:
168 assert(0);
169 return 0;
170 }
171 }
172
173
174 static struct vbo_save_vertex_store *alloc_vertex_store( struct gl_context *ctx )
175 {
176 struct vbo_save_vertex_store *vertex_store = CALLOC_STRUCT(vbo_save_vertex_store);
177
178 /* obj->Name needs to be non-zero, but won't ever be examined more
179 * closely than that. In particular these buffers won't be entered
180 * into the hash and can never be confused with ones visible to the
181 * user. Perhaps there could be a special number for internal
182 * buffers:
183 */
184 vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx,
185 VBO_BUF_ID,
186 GL_ARRAY_BUFFER_ARB);
187
188 ctx->Driver.BufferData( ctx,
189 GL_ARRAY_BUFFER_ARB,
190 VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
191 NULL,
192 GL_STATIC_DRAW_ARB,
193 vertex_store->bufferobj);
194
195 vertex_store->buffer = NULL;
196 vertex_store->used = 0;
197 vertex_store->refcount = 1;
198
199 return vertex_store;
200 }
201
202 static void free_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store )
203 {
204 assert(!vertex_store->buffer);
205
206 if (vertex_store->bufferobj) {
207 _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
208 }
209
210 FREE( vertex_store );
211 }
212
213 static GLfloat *map_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store )
214 {
215 assert(vertex_store->bufferobj);
216 assert(!vertex_store->buffer);
217 vertex_store->buffer = (GLfloat *)ctx->Driver.MapBuffer(ctx,
218 GL_ARRAY_BUFFER_ARB, /* not used */
219 GL_WRITE_ONLY, /* not used */
220 vertex_store->bufferobj);
221
222 assert(vertex_store->buffer);
223 return vertex_store->buffer + vertex_store->used;
224 }
225
226 static void unmap_vertex_store( struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store )
227 {
228 ctx->Driver.UnmapBuffer( ctx, GL_ARRAY_BUFFER_ARB, vertex_store->bufferobj );
229 vertex_store->buffer = NULL;
230 }
231
232
233 static struct vbo_save_primitive_store *alloc_prim_store( struct gl_context *ctx )
234 {
235 struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store);
236 (void) ctx;
237 store->used = 0;
238 store->refcount = 1;
239 return store;
240 }
241
242 static void _save_reset_counters( struct gl_context *ctx )
243 {
244 struct vbo_save_context *save = &vbo_context(ctx)->save;
245
246 save->prim = save->prim_store->buffer + save->prim_store->used;
247 save->buffer = (save->vertex_store->buffer +
248 save->vertex_store->used);
249
250 assert(save->buffer == save->buffer_ptr);
251
252 if (save->vertex_size)
253 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
254 save->vertex_size);
255 else
256 save->max_vert = 0;
257
258 save->vert_count = 0;
259 save->prim_count = 0;
260 save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
261 save->dangling_attr_ref = 0;
262 }
263
264
265 /* Insert the active immediate struct onto the display list currently
266 * being built.
267 */
268 static void _save_compile_vertex_list( struct gl_context *ctx )
269 {
270 struct vbo_save_context *save = &vbo_context(ctx)->save;
271 struct vbo_save_vertex_list *node;
272
273 /* Allocate space for this structure in the display list currently
274 * being compiled.
275 */
276 node = (struct vbo_save_vertex_list *)
277 _mesa_dlist_alloc(ctx, save->opcode_vertex_list, sizeof(*node));
278
279 if (!node)
280 return;
281
282 /* Duplicate our template, increment refcounts to the storage structs:
283 */
284 memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
285 node->vertex_size = save->vertex_size;
286 node->buffer_offset = (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
287 node->count = save->vert_count;
288 node->wrap_count = save->copied.nr;
289 node->dangling_attr_ref = save->dangling_attr_ref;
290 node->prim = save->prim;
291 node->prim_count = save->prim_count;
292 node->vertex_store = save->vertex_store;
293 node->prim_store = save->prim_store;
294
295 node->vertex_store->refcount++;
296 node->prim_store->refcount++;
297
298 if (node->prim[0].no_current_update) {
299 node->current_size = 0;
300 node->current_data = NULL;
301 } else {
302 node->current_size = node->vertex_size - node->attrsz[0];
303 node->current_data = NULL;
304
305 if (node->current_size) {
306 /* If the malloc fails, we just pull the data out of the VBO
307 * later instead.
308 */
309 node->current_data = MALLOC( node->current_size * sizeof(GLfloat) );
310 if (node->current_data) {
311 const char *buffer = (const char *)save->vertex_store->buffer;
312 unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
313 unsigned vertex_offset = 0;
314
315 if (node->count)
316 vertex_offset = (node->count-1) * node->vertex_size * sizeof(GLfloat);
317
318 memcpy( node->current_data,
319 buffer + node->buffer_offset + vertex_offset + attr_offset,
320 node->current_size * sizeof(GLfloat) );
321 }
322 }
323 }
324
325
326
327 assert(node->attrsz[VBO_ATTRIB_POS] != 0 ||
328 node->count == 0);
329
330 if (save->dangling_attr_ref)
331 ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
332
333 save->vertex_store->used += save->vertex_size * node->count;
334 save->prim_store->used += node->prim_count;
335
336
337 /* Copy duplicated vertices
338 */
339 save->copied.nr = _save_copy_vertices( ctx, node, save->buffer );
340
341
342 /* Deal with GL_COMPILE_AND_EXECUTE:
343 */
344 if (ctx->ExecuteFlag) {
345 struct _glapi_table *dispatch = GET_DISPATCH();
346
347 _glapi_set_dispatch(ctx->Exec);
348
349 vbo_loopback_vertex_list( ctx,
350 (const GLfloat *)((const char *)save->vertex_store->buffer +
351 node->buffer_offset),
352 node->attrsz,
353 node->prim,
354 node->prim_count,
355 node->wrap_count,
356 node->vertex_size);
357
358 _glapi_set_dispatch(dispatch);
359 }
360
361
362 /* Decide whether the storage structs are full, or can be used for
363 * the next vertex lists as well.
364 */
365 if (save->vertex_store->used >
366 VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
367
368 /* Unmap old store:
369 */
370 unmap_vertex_store( ctx, save->vertex_store );
371
372 /* Release old reference:
373 */
374 save->vertex_store->refcount--;
375 assert(save->vertex_store->refcount != 0);
376 save->vertex_store = NULL;
377
378 /* Allocate and map new store:
379 */
380 save->vertex_store = alloc_vertex_store( ctx );
381 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
382 }
383
384 if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
385 save->prim_store->refcount--;
386 assert(save->prim_store->refcount != 0);
387 save->prim_store = alloc_prim_store( ctx );
388 }
389
390 /* Reset our structures for the next run of vertices:
391 */
392 _save_reset_counters( ctx );
393 }
394
395
396 /* TODO -- If no new vertices have been stored, don't bother saving
397 * it.
398 */
399 static void _save_wrap_buffers( struct gl_context *ctx )
400 {
401 struct vbo_save_context *save = &vbo_context(ctx)->save;
402 GLint i = save->prim_count - 1;
403 GLenum mode;
404 GLboolean weak;
405 GLboolean no_current_update;
406
407 assert(i < (GLint) save->prim_max);
408 assert(i >= 0);
409
410 /* Close off in-progress primitive.
411 */
412 save->prim[i].count = (save->vert_count -
413 save->prim[i].start);
414 mode = save->prim[i].mode;
415 weak = save->prim[i].weak;
416 no_current_update = save->prim[i].no_current_update;
417
418 /* store the copied vertices, and allocate a new list.
419 */
420 _save_compile_vertex_list( ctx );
421
422 /* Restart interrupted primitive
423 */
424 save->prim[0].mode = mode;
425 save->prim[0].weak = weak;
426 save->prim[0].no_current_update = no_current_update;
427 save->prim[0].begin = 0;
428 save->prim[0].end = 0;
429 save->prim[0].pad = 0;
430 save->prim[0].start = 0;
431 save->prim[0].count = 0;
432 save->prim[0].num_instances = 1;
433 save->prim_count = 1;
434 }
435
436
437
438 /* Called only when buffers are wrapped as the result of filling the
439 * vertex_store struct.
440 */
441 static void _save_wrap_filled_vertex( struct gl_context *ctx )
442 {
443 struct vbo_save_context *save = &vbo_context(ctx)->save;
444 GLfloat *data = save->copied.buffer;
445 GLuint i;
446
447 /* Emit a glEnd to close off the last vertex list.
448 */
449 _save_wrap_buffers( ctx );
450
451 /* Copy stored stored vertices to start of new list.
452 */
453 assert(save->max_vert - save->vert_count > save->copied.nr);
454
455 for (i = 0 ; i < save->copied.nr ; i++) {
456 memcpy( save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
457 data += save->vertex_size;
458 save->buffer_ptr += save->vertex_size;
459 save->vert_count++;
460 }
461 }
462
463
464 static void _save_copy_to_current( struct gl_context *ctx )
465 {
466 struct vbo_save_context *save = &vbo_context(ctx)->save;
467 GLuint i;
468
469 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
470 if (save->attrsz[i]) {
471 save->currentsz[i][0] = save->attrsz[i];
472 COPY_CLEAN_4V(save->current[i],
473 save->attrsz[i],
474 save->attrptr[i]);
475 }
476 }
477 }
478
479
480 static void _save_copy_from_current( struct gl_context *ctx )
481 {
482 struct vbo_save_context *save = &vbo_context(ctx)->save;
483 GLint i;
484
485 for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
486 switch (save->attrsz[i]) {
487 case 4: save->attrptr[i][3] = save->current[i][3];
488 case 3: save->attrptr[i][2] = save->current[i][2];
489 case 2: save->attrptr[i][1] = save->current[i][1];
490 case 1: save->attrptr[i][0] = save->current[i][0];
491 case 0: break;
492 }
493 }
494 }
495
496
497
498
499 /* Flush existing data, set new attrib size, replay copied vertices.
500 */
501 static void _save_upgrade_vertex( struct gl_context *ctx,
502 GLuint attr,
503 GLuint newsz )
504 {
505 struct vbo_save_context *save = &vbo_context(ctx)->save;
506 GLuint oldsz;
507 GLuint i;
508 GLfloat *tmp;
509
510 /* Store the current run of vertices, and emit a GL_END. Emit a
511 * BEGIN in the new buffer.
512 */
513 if (save->vert_count)
514 _save_wrap_buffers( ctx );
515 else
516 assert( save->copied.nr == 0 );
517
518 /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
519 * when the attribute already exists in the vertex and is having
520 * its size increased.
521 */
522 _save_copy_to_current( ctx );
523
524 /* Fix up sizes:
525 */
526 oldsz = save->attrsz[attr];
527 save->attrsz[attr] = newsz;
528
529 save->vertex_size += newsz - oldsz;
530 save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
531 save->vertex_size);
532 save->vert_count = 0;
533
534 /* Recalculate all the attrptr[] values:
535 */
536 for (i = 0, tmp = save->vertex ; i < VBO_ATTRIB_MAX ; i++) {
537 if (save->attrsz[i]) {
538 save->attrptr[i] = tmp;
539 tmp += save->attrsz[i];
540 }
541 else
542 save->attrptr[i] = NULL; /* will not be dereferenced. */
543 }
544
545 /* Copy from current to repopulate the vertex with correct values.
546 */
547 _save_copy_from_current( ctx );
548
549 /* Replay stored vertices to translate them to new format here.
550 *
551 * If there are copied vertices and the new (upgraded) attribute
552 * has not been defined before, this list is somewhat degenerate,
553 * and will need fixup at runtime.
554 */
555 if (save->copied.nr)
556 {
557 GLfloat *data = save->copied.buffer;
558 GLfloat *dest = save->buffer;
559 GLuint j;
560
561 /* Need to note this and fix up at runtime (or loopback):
562 */
563 if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
564 assert(oldsz == 0);
565 save->dangling_attr_ref = GL_TRUE;
566 }
567
568 for (i = 0 ; i < save->copied.nr ; i++) {
569 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
570 if (save->attrsz[j]) {
571 if (j == attr) {
572 if (oldsz) {
573 COPY_CLEAN_4V( dest, oldsz, data );
574 data += oldsz;
575 dest += newsz;
576 }
577 else {
578 COPY_SZ_4V( dest, newsz, save->current[attr] );
579 dest += newsz;
580 }
581 }
582 else {
583 GLint sz = save->attrsz[j];
584 COPY_SZ_4V( dest, sz, data );
585 data += sz;
586 dest += sz;
587 }
588 }
589 }
590 }
591
592 save->buffer_ptr = dest;
593 save->vert_count += save->copied.nr;
594 }
595 }
596
597 static void save_fixup_vertex( struct gl_context *ctx, GLuint attr, GLuint sz )
598 {
599 struct vbo_save_context *save = &vbo_context(ctx)->save;
600
601 if (sz > save->attrsz[attr]) {
602 /* New size is larger. Need to flush existing vertices and get
603 * an enlarged vertex format.
604 */
605 _save_upgrade_vertex( ctx, attr, sz );
606 }
607 else if (sz < save->active_sz[attr]) {
608 static GLfloat id[4] = { 0, 0, 0, 1 };
609 GLuint i;
610
611 /* New size is equal or smaller - just need to fill in some
612 * zeros.
613 */
614 for (i = sz ; i <= save->attrsz[attr] ; i++)
615 save->attrptr[attr][i-1] = id[i-1];
616 }
617
618 save->active_sz[attr] = sz;
619 }
620
621 static void _save_reset_vertex( struct gl_context *ctx )
622 {
623 struct vbo_save_context *save = &vbo_context(ctx)->save;
624 GLuint i;
625
626 for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
627 save->attrsz[i] = 0;
628 save->active_sz[i] = 0;
629 }
630
631 save->vertex_size = 0;
632 }
633
634
635
636 #define ERROR() _mesa_compile_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
637
638
639 /* Only one size for each attribute may be active at once. Eg. if
640 * Color3f is installed/active, then Color4f may not be, even if the
641 * vertex actually contains 4 color coordinates. This is because the
642 * 3f version won't otherwise set color[3] to 1.0 -- this is the job
643 * of the chooser function when switching between Color4f and Color3f.
644 */
645 #define ATTR( A, N, V0, V1, V2, V3 ) \
646 do { \
647 struct vbo_save_context *save = &vbo_context(ctx)->save; \
648 \
649 if (save->active_sz[A] != N) \
650 save_fixup_vertex(ctx, A, N); \
651 \
652 { \
653 GLfloat *dest = save->attrptr[A]; \
654 if (N>0) dest[0] = V0; \
655 if (N>1) dest[1] = V1; \
656 if (N>2) dest[2] = V2; \
657 if (N>3) dest[3] = V3; \
658 } \
659 \
660 if ((A) == 0) { \
661 GLuint i; \
662 \
663 for (i = 0; i < save->vertex_size; i++) \
664 save->buffer_ptr[i] = save->vertex[i]; \
665 \
666 save->buffer_ptr += save->vertex_size; \
667 \
668 if (++save->vert_count >= save->max_vert) \
669 _save_wrap_filled_vertex( ctx ); \
670 } \
671 } while (0)
672
673 #define TAG(x) _save_##x
674
675 #include "vbo_attrib_tmp.h"
676
677
678
679
680 /* Cope with EvalCoord/CallList called within a begin/end object:
681 * -- Flush current buffer
682 * -- Fallback to opcodes for the rest of the begin/end object.
683 */
684 static void DO_FALLBACK( struct gl_context *ctx )
685 {
686 struct vbo_save_context *save = &vbo_context(ctx)->save;
687
688 if (save->vert_count || save->prim_count) {
689 GLint i = save->prim_count - 1;
690
691 /* Close off in-progress primitive.
692 */
693 save->prim[i].count = (save->vert_count -
694 save->prim[i].start);
695
696 /* Need to replay this display list with loopback,
697 * unfortunately, otherwise this primitive won't be handled
698 * properly:
699 */
700 save->dangling_attr_ref = 1;
701
702 _save_compile_vertex_list( ctx );
703 }
704
705 _save_copy_to_current( ctx );
706 _save_reset_vertex( ctx );
707 _save_reset_counters( ctx );
708 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
709 ctx->Driver.SaveNeedFlush = 0;
710 }
711
712 static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
713 {
714 GET_CURRENT_CONTEXT(ctx);
715 DO_FALLBACK(ctx);
716 CALL_EvalCoord1f(ctx->Save, (u));
717 }
718
719 static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
720 {
721 GET_CURRENT_CONTEXT(ctx);
722 DO_FALLBACK(ctx);
723 CALL_EvalCoord1fv(ctx->Save, (v));
724 }
725
726 static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
727 {
728 GET_CURRENT_CONTEXT(ctx);
729 DO_FALLBACK(ctx);
730 CALL_EvalCoord2f(ctx->Save, (u, v));
731 }
732
733 static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
734 {
735 GET_CURRENT_CONTEXT(ctx);
736 DO_FALLBACK(ctx);
737 CALL_EvalCoord2fv(ctx->Save, (v));
738 }
739
740 static void GLAPIENTRY _save_EvalPoint1( GLint i )
741 {
742 GET_CURRENT_CONTEXT(ctx);
743 DO_FALLBACK(ctx);
744 CALL_EvalPoint1(ctx->Save, (i));
745 }
746
747 static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
748 {
749 GET_CURRENT_CONTEXT(ctx);
750 DO_FALLBACK(ctx);
751 CALL_EvalPoint2(ctx->Save, (i, j));
752 }
753
754 static void GLAPIENTRY _save_CallList( GLuint l )
755 {
756 GET_CURRENT_CONTEXT(ctx);
757 DO_FALLBACK(ctx);
758 CALL_CallList(ctx->Save, (l));
759 }
760
761 static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
762 {
763 GET_CURRENT_CONTEXT(ctx);
764 DO_FALLBACK(ctx);
765 CALL_CallLists(ctx->Save, (n, type, v));
766 }
767
768
769
770
771 /* This begin is hooked into ... Updating of
772 * ctx->Driver.CurrentSavePrimitive is already taken care of.
773 */
774 GLboolean vbo_save_NotifyBegin( struct gl_context *ctx, GLenum mode )
775 {
776 struct vbo_save_context *save = &vbo_context(ctx)->save;
777
778 GLuint i = save->prim_count++;
779
780 assert(i < save->prim_max);
781 save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
782 save->prim[i].begin = 1;
783 save->prim[i].end = 0;
784 save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
785 save->prim[i].no_current_update = (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
786 save->prim[i].pad = 0;
787 save->prim[i].start = save->vert_count;
788 save->prim[i].count = 0;
789 save->prim[i].num_instances = 1;
790
791 _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );
792 ctx->Driver.SaveNeedFlush = 1;
793 return GL_TRUE;
794 }
795
796
797
798 static void GLAPIENTRY _save_End( void )
799 {
800 GET_CURRENT_CONTEXT( ctx );
801 struct vbo_save_context *save = &vbo_context(ctx)->save;
802 GLint i = save->prim_count - 1;
803
804 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
805 save->prim[i].end = 1;
806 save->prim[i].count = (save->vert_count -
807 save->prim[i].start);
808
809 if (i == (GLint) save->prim_max - 1) {
810 _save_compile_vertex_list( ctx );
811 assert(save->copied.nr == 0);
812 }
813
814 /* Swap out this vertex format while outside begin/end. Any color,
815 * etc. received between here and the next begin will be compiled
816 * as opcodes.
817 */
818 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
819 }
820
821
822 /* These are all errors as this vtxfmt is only installed inside
823 * begin/end pairs.
824 */
825 static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
826 const GLvoid *indices)
827 {
828 GET_CURRENT_CONTEXT(ctx);
829 (void) mode; (void) count; (void) type; (void) indices;
830 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
831 }
832
833
834 static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
835 GLuint start, GLuint end,
836 GLsizei count, GLenum type,
837 const GLvoid *indices)
838 {
839 GET_CURRENT_CONTEXT(ctx);
840 (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
841 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
842 }
843
844 static void GLAPIENTRY _save_DrawElementsBaseVertex(GLenum mode,
845 GLsizei count,
846 GLenum type,
847 const GLvoid *indices,
848 GLint basevertex)
849 {
850 GET_CURRENT_CONTEXT(ctx);
851 (void) mode; (void) count; (void) type; (void) indices; (void)basevertex;
852
853 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
854 }
855
856 static void GLAPIENTRY _save_DrawRangeElementsBaseVertex(GLenum mode,
857 GLuint start,
858 GLuint end,
859 GLsizei count,
860 GLenum type,
861 const GLvoid *indices,
862 GLint basevertex)
863 {
864 GET_CURRENT_CONTEXT(ctx);
865 (void) mode; (void) start; (void) end; (void) count; (void) type;
866 (void) indices; (void)basevertex;
867
868 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
869 }
870
871 static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
872 {
873 GET_CURRENT_CONTEXT(ctx);
874 (void) mode; (void) start; (void) count;
875 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
876 }
877
878 static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
879 {
880 GET_CURRENT_CONTEXT(ctx);
881 (void) x1; (void) y1; (void) x2; (void) y2;
882 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
883 }
884
885 static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
886 {
887 GET_CURRENT_CONTEXT(ctx);
888 (void) mode; (void) i1; (void) i2;
889 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
890 }
891
892 static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
893 GLint j1, GLint j2 )
894 {
895 GET_CURRENT_CONTEXT(ctx);
896 (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
897 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
898 }
899
900 static void GLAPIENTRY _save_Begin( GLenum mode )
901 {
902 GET_CURRENT_CONTEXT( ctx );
903 (void) mode;
904 _mesa_compile_error( ctx, GL_INVALID_OPERATION, "Recursive glBegin" );
905 }
906
907
908 static void GLAPIENTRY _save_PrimitiveRestartNV( void )
909 {
910 GLenum curPrim;
911 GET_CURRENT_CONTEXT( ctx );
912
913 curPrim = ctx->Driver.CurrentSavePrimitive;
914
915 _save_End();
916 _save_Begin(curPrim);
917 }
918
919
920 /* Unlike the functions above, these are to be hooked into the vtxfmt
921 * maintained in ctx->ListState, active when the list is known or
922 * suspected to be outside any begin/end primitive.
923 */
924 static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
925 {
926 GET_CURRENT_CONTEXT(ctx);
927 vbo_save_NotifyBegin( ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK );
928 CALL_Vertex2f(GET_DISPATCH(), ( x1, y1 ));
929 CALL_Vertex2f(GET_DISPATCH(), ( x2, y1 ));
930 CALL_Vertex2f(GET_DISPATCH(), ( x2, y2 ));
931 CALL_Vertex2f(GET_DISPATCH(), ( x1, y2 ));
932 CALL_End(GET_DISPATCH(), ());
933 }
934
935
936 static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
937 {
938 GET_CURRENT_CONTEXT(ctx);
939 GLint i;
940
941 if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
942 return;
943
944 _ae_map_vbos( ctx );
945
946 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK | VBO_SAVE_PRIM_NO_CURRENT_UPDATE);
947
948 for (i = 0; i < count; i++)
949 CALL_ArrayElement(GET_DISPATCH(), (start + i));
950 CALL_End(GET_DISPATCH(), ());
951
952 _ae_unmap_vbos( ctx );
953 }
954
955 /* Could do better by copying the arrays and element list intact and
956 * then emitting an indexed prim at runtime.
957 */
958 static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
959 const GLvoid *indices)
960 {
961 GET_CURRENT_CONTEXT(ctx);
962 GLint i;
963
964 if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices, 0 ))
965 return;
966
967 _ae_map_vbos( ctx );
968
969 if (_mesa_is_bufferobj(ctx->Array.ElementArrayBufferObj))
970 indices = ADD_POINTERS(ctx->Array.ElementArrayBufferObj->Pointer, indices);
971
972 vbo_save_NotifyBegin( ctx, mode | VBO_SAVE_PRIM_WEAK | VBO_SAVE_PRIM_NO_CURRENT_UPDATE );
973
974 switch (type) {
975 case GL_UNSIGNED_BYTE:
976 for (i = 0 ; i < count ; i++)
977 CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
978 break;
979 case GL_UNSIGNED_SHORT:
980 for (i = 0 ; i < count ; i++)
981 CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
982 break;
983 case GL_UNSIGNED_INT:
984 for (i = 0 ; i < count ; i++)
985 CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
986 break;
987 default:
988 _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
989 break;
990 }
991
992 CALL_End(GET_DISPATCH(), ());
993
994 _ae_unmap_vbos( ctx );
995 }
996
997 static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
998 GLuint start, GLuint end,
999 GLsizei count, GLenum type,
1000 const GLvoid *indices)
1001 {
1002 GET_CURRENT_CONTEXT(ctx);
1003 if (_mesa_validate_DrawRangeElements( ctx, mode,
1004 start, end,
1005 count, type, indices, 0 ))
1006 _save_OBE_DrawElements( mode, count, type, indices );
1007 }
1008
1009
1010
1011
1012
1013 static void _save_vtxfmt_init( struct gl_context *ctx )
1014 {
1015 struct vbo_save_context *save = &vbo_context(ctx)->save;
1016 GLvertexformat *vfmt = &save->vtxfmt;
1017
1018 _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
1019
1020 vfmt->Begin = _save_Begin;
1021 vfmt->Color3f = _save_Color3f;
1022 vfmt->Color3fv = _save_Color3fv;
1023 vfmt->Color4f = _save_Color4f;
1024 vfmt->Color4fv = _save_Color4fv;
1025 vfmt->EdgeFlag = _save_EdgeFlag;
1026 vfmt->End = _save_End;
1027 vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1028 vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1029 vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1030 vfmt->Indexf = _save_Indexf;
1031 vfmt->Indexfv = _save_Indexfv;
1032 vfmt->Materialfv = _save_Materialfv;
1033 vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1034 vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1035 vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1036 vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1037 vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1038 vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1039 vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1040 vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1041 vfmt->Normal3f = _save_Normal3f;
1042 vfmt->Normal3fv = _save_Normal3fv;
1043 vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1044 vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1045 vfmt->TexCoord1f = _save_TexCoord1f;
1046 vfmt->TexCoord1fv = _save_TexCoord1fv;
1047 vfmt->TexCoord2f = _save_TexCoord2f;
1048 vfmt->TexCoord2fv = _save_TexCoord2fv;
1049 vfmt->TexCoord3f = _save_TexCoord3f;
1050 vfmt->TexCoord3fv = _save_TexCoord3fv;
1051 vfmt->TexCoord4f = _save_TexCoord4f;
1052 vfmt->TexCoord4fv = _save_TexCoord4fv;
1053 vfmt->Vertex2f = _save_Vertex2f;
1054 vfmt->Vertex2fv = _save_Vertex2fv;
1055 vfmt->Vertex3f = _save_Vertex3f;
1056 vfmt->Vertex3fv = _save_Vertex3fv;
1057 vfmt->Vertex4f = _save_Vertex4f;
1058 vfmt->Vertex4fv = _save_Vertex4fv;
1059 vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1060 vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1061 vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1062 vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1063 vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1064 vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1065 vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1066 vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1067
1068 vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1069 vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1070 vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1071 vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1072 vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1073 vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1074 vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1075 vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1076
1077 /* integer-valued */
1078 vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1079 vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1080 vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1081 vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1082 vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1083 vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1084 vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1085
1086 /* unsigned integer-valued */
1087 vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1088 vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1089 vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1090 vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1091 vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1092 vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1093 vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1094
1095 /* This will all require us to fallback to saving the list as opcodes:
1096 */
1097 _MESA_INIT_DLIST_VTXFMT(vfmt, _save_); /* inside begin/end */
1098
1099 _MESA_INIT_EVAL_VTXFMT(vfmt, _save_);
1100
1101 /* These are all errors as we at least know we are in some sort of
1102 * begin/end pair:
1103 */
1104 vfmt->Begin = _save_Begin;
1105 vfmt->Rectf = _save_Rectf;
1106 vfmt->DrawArrays = _save_DrawArrays;
1107 vfmt->DrawElements = _save_DrawElements;
1108 vfmt->DrawRangeElements = _save_DrawRangeElements;
1109 vfmt->DrawElementsBaseVertex = _save_DrawElementsBaseVertex;
1110 vfmt->DrawRangeElementsBaseVertex = _save_DrawRangeElementsBaseVertex;
1111 /* Loops back into vfmt->DrawElements */
1112 vfmt->MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1113 vfmt->MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1114 }
1115
1116
1117 void vbo_save_SaveFlushVertices( struct gl_context *ctx )
1118 {
1119 struct vbo_save_context *save = &vbo_context(ctx)->save;
1120
1121 /* Noop when we are actually active:
1122 */
1123 if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
1124 ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
1125 return;
1126
1127 if (save->vert_count ||
1128 save->prim_count)
1129 _save_compile_vertex_list( ctx );
1130
1131 _save_copy_to_current( ctx );
1132 _save_reset_vertex( ctx );
1133 _save_reset_counters( ctx );
1134 ctx->Driver.SaveNeedFlush = 0;
1135 }
1136
1137 void vbo_save_NewList( struct gl_context *ctx, GLuint list, GLenum mode )
1138 {
1139 struct vbo_save_context *save = &vbo_context(ctx)->save;
1140
1141 (void) list; (void) mode;
1142
1143 if (!save->prim_store)
1144 save->prim_store = alloc_prim_store( ctx );
1145
1146 if (!save->vertex_store)
1147 save->vertex_store = alloc_vertex_store( ctx );
1148
1149 save->buffer_ptr = map_vertex_store( ctx, save->vertex_store );
1150
1151 _save_reset_vertex( ctx );
1152 _save_reset_counters( ctx );
1153 ctx->Driver.SaveNeedFlush = 0;
1154 }
1155
1156 void vbo_save_EndList( struct gl_context *ctx )
1157 {
1158 struct vbo_save_context *save = &vbo_context(ctx)->save;
1159
1160 /* EndList called inside a (saved) Begin/End pair?
1161 */
1162 if (ctx->Driver.CurrentSavePrimitive != PRIM_OUTSIDE_BEGIN_END) {
1163
1164 if (save->prim_count > 0) {
1165 GLint i = save->prim_count - 1;
1166 ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1167 save->prim[i].end = 0;
1168 save->prim[i].count = (save->vert_count -
1169 save->prim[i].start);
1170 }
1171
1172 /* Make sure this vertex list gets replayed by the "loopback"
1173 * mechanism:
1174 */
1175 save->dangling_attr_ref = 1;
1176 vbo_save_SaveFlushVertices( ctx );
1177
1178 /* Swap out this vertex format while outside begin/end. Any color,
1179 * etc. received between here and the next begin will be compiled
1180 * as opcodes.
1181 */
1182 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1183 }
1184
1185 unmap_vertex_store( ctx, save->vertex_store );
1186
1187 assert(save->vertex_size == 0);
1188 }
1189
1190 void vbo_save_BeginCallList( struct gl_context *ctx, struct gl_display_list *dlist )
1191 {
1192 struct vbo_save_context *save = &vbo_context(ctx)->save;
1193 save->replay_flags |= dlist->Flags;
1194 }
1195
1196 void vbo_save_EndCallList( struct gl_context *ctx )
1197 {
1198 struct vbo_save_context *save = &vbo_context(ctx)->save;
1199
1200 if (ctx->ListState.CallDepth == 1) {
1201 /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1202 * flag, if it is set:
1203 */
1204 save->replay_flags &= VBO_SAVE_FALLBACK;
1205 }
1206 }
1207
1208
1209 static void vbo_destroy_vertex_list( struct gl_context *ctx, void *data )
1210 {
1211 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1212 (void) ctx;
1213
1214 if ( --node->vertex_store->refcount == 0 )
1215 free_vertex_store( ctx, node->vertex_store );
1216
1217 if ( --node->prim_store->refcount == 0 )
1218 FREE( node->prim_store );
1219
1220 if (node->current_data) {
1221 FREE(node->current_data);
1222 node->current_data = NULL;
1223 }
1224 }
1225
1226
1227 static void vbo_print_vertex_list( struct gl_context *ctx, void *data )
1228 {
1229 struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *)data;
1230 GLuint i;
1231 (void) ctx;
1232
1233 printf("VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
1234 node->count,
1235 node->prim_count,
1236 node->vertex_size);
1237
1238 for (i = 0 ; i < node->prim_count ; i++) {
1239 struct _mesa_prim *prim = &node->prim[i];
1240 _mesa_debug(NULL, " prim %d: %s%s %d..%d %s %s\n",
1241 i,
1242 _mesa_lookup_prim_by_nr(prim->mode),
1243 prim->weak ? " (weak)" : "",
1244 prim->start,
1245 prim->start + prim->count,
1246 (prim->begin) ? "BEGIN" : "(wrap)",
1247 (prim->end) ? "END" : "(wrap)");
1248 }
1249 }
1250
1251
1252 static void _save_current_init( struct gl_context *ctx )
1253 {
1254 struct vbo_save_context *save = &vbo_context(ctx)->save;
1255 GLint i;
1256
1257 for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1258 const GLuint j = i - VBO_ATTRIB_POS;
1259 ASSERT(j < VERT_ATTRIB_MAX);
1260 save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1261 save->current[i] = ctx->ListState.CurrentAttrib[j];
1262 }
1263
1264 for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1265 const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1266 ASSERT(j < MAT_ATTRIB_MAX);
1267 save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1268 save->current[i] = ctx->ListState.CurrentMaterial[j];
1269 }
1270 }
1271
1272 /**
1273 * Initialize the display list compiler
1274 */
1275 void vbo_save_api_init( struct vbo_save_context *save )
1276 {
1277 struct gl_context *ctx = save->ctx;
1278 GLuint i;
1279
1280 save->opcode_vertex_list =
1281 _mesa_dlist_alloc_opcode( ctx,
1282 sizeof(struct vbo_save_vertex_list),
1283 vbo_save_playback_vertex_list,
1284 vbo_destroy_vertex_list,
1285 vbo_print_vertex_list );
1286
1287 ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
1288
1289 _save_vtxfmt_init( ctx );
1290 _save_current_init( ctx );
1291
1292 /* These will actually get set again when binding/drawing */
1293 for (i = 0; i < VBO_ATTRIB_MAX; i++)
1294 save->inputs[i] = &save->arrays[i];
1295
1296 /* Hook our array functions into the outside-begin-end vtxfmt in
1297 * ctx->ListState.
1298 */
1299 ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
1300 ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
1301 ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
1302 ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
1303 /* loops back into _save_OBE_DrawElements */
1304 ctx->ListState.ListVtxfmt.MultiDrawElementsEXT = _mesa_noop_MultiDrawElements;
1305 ctx->ListState.ListVtxfmt.MultiDrawElementsBaseVertex = _mesa_noop_MultiDrawElementsBaseVertex;
1306 _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
1307 }
1308
1309
1310 #endif /* FEATURE_dlist */