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