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