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