OSDN Git Service

vbo: allow DrawElementsBaseVertex in display lists
[android-x86/external-mesa.git] / src / mesa / vbo / vbo_save_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 VMware, Inc.
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 VMWARE 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 <keithw@vmware.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_validate.h"
78 #include "main/api_arrayelt.h"
79 #include "main/vtxfmt.h"
80 #include "main/dispatch.h"
81
82 #include "vbo_context.h"
83 #include "vbo_noop.h"
84
85
86 #ifdef ERROR
87 #undef ERROR
88 #endif
89
90
91 /* An interesting VBO number/name to help with debugging */
92 #define VBO_BUF_ID  12345
93
94
95 /*
96  * NOTE: Old 'parity' issue is gone, but copying can still be
97  * wrong-footed on replay.
98  */
99 static GLuint
100 _save_copy_vertices(struct gl_context *ctx,
101                     const struct vbo_save_vertex_list *node,
102                     const fi_type * src_buffer)
103 {
104    struct vbo_save_context *save = &vbo_context(ctx)->save;
105    const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
106    GLuint nr = prim->count;
107    GLuint sz = save->vertex_size;
108    const fi_type *src = src_buffer + prim->start * sz;
109    fi_type *dst = save->copied.buffer;
110    GLuint ovf, i;
111
112    if (prim->end)
113       return 0;
114
115    switch (prim->mode) {
116    case GL_POINTS:
117       return 0;
118    case GL_LINES:
119       ovf = nr & 1;
120       for (i = 0; i < ovf; i++)
121          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
122                 sz * sizeof(GLfloat));
123       return i;
124    case GL_TRIANGLES:
125       ovf = nr % 3;
126       for (i = 0; i < ovf; i++)
127          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
128                 sz * sizeof(GLfloat));
129       return i;
130    case GL_QUADS:
131       ovf = nr & 3;
132       for (i = 0; i < ovf; i++)
133          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
134                 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       }
152       else {
153          memcpy(dst, src + 0, sz * sizeof(GLfloat));
154          memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
155          return 2;
156       }
157    case GL_TRIANGLE_STRIP:
158    case GL_QUAD_STRIP:
159       switch (nr) {
160       case 0:
161          ovf = 0;
162          break;
163       case 1:
164          ovf = 1;
165          break;
166       default:
167          ovf = 2 + (nr & 1);
168          break;
169       }
170       for (i = 0; i < ovf; i++)
171          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
172                 sz * sizeof(GLfloat));
173       return i;
174    default:
175       assert(0);
176       return 0;
177    }
178 }
179
180
181 static struct vbo_save_vertex_store *
182 alloc_vertex_store(struct gl_context *ctx)
183 {
184    struct vbo_save_context *save = &vbo_context(ctx)->save;
185    struct vbo_save_vertex_store *vertex_store =
186       CALLOC_STRUCT(vbo_save_vertex_store);
187
188    /* obj->Name needs to be non-zero, but won't ever be examined more
189     * closely than that.  In particular these buffers won't be entered
190     * into the hash and can never be confused with ones visible to the
191     * user.  Perhaps there could be a special number for internal
192     * buffers:
193     */
194    vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID);
195    if (vertex_store->bufferobj) {
196       save->out_of_memory =
197          !ctx->Driver.BufferData(ctx,
198                                  GL_ARRAY_BUFFER_ARB,
199                                  VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
200                                  NULL, GL_STATIC_DRAW_ARB,
201                                  GL_MAP_WRITE_BIT |
202                                  GL_DYNAMIC_STORAGE_BIT,
203                                  vertex_store->bufferobj);
204    }
205    else {
206       save->out_of_memory = GL_TRUE;
207    }
208
209    if (save->out_of_memory) {
210       _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
211       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
212    }
213
214    vertex_store->buffer = NULL;
215    vertex_store->used = 0;
216    vertex_store->refcount = 1;
217
218    return vertex_store;
219 }
220
221
222 static void
223 free_vertex_store(struct gl_context *ctx,
224                   struct vbo_save_vertex_store *vertex_store)
225 {
226    assert(!vertex_store->buffer);
227
228    if (vertex_store->bufferobj) {
229       _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
230    }
231
232    free(vertex_store);
233 }
234
235
236 fi_type *
237 vbo_save_map_vertex_store(struct gl_context *ctx,
238                           struct vbo_save_vertex_store *vertex_store)
239 {
240    const GLbitfield access = (GL_MAP_WRITE_BIT |
241                               GL_MAP_INVALIDATE_RANGE_BIT |
242                               GL_MAP_UNSYNCHRONIZED_BIT |
243                               GL_MAP_FLUSH_EXPLICIT_BIT);
244
245    assert(vertex_store->bufferobj);
246    assert(!vertex_store->buffer);  /* the buffer should not be mapped */
247
248    if (vertex_store->bufferobj->Size > 0) {
249       /* Map the remaining free space in the VBO */
250       GLintptr offset = vertex_store->used * sizeof(GLfloat);
251       GLsizeiptr size = vertex_store->bufferobj->Size - offset;
252       fi_type *range = (fi_type *)
253          ctx->Driver.MapBufferRange(ctx, offset, size, access,
254                                     vertex_store->bufferobj,
255                                     MAP_INTERNAL);
256       if (range) {
257          /* compute address of start of whole buffer (needed elsewhere) */
258          vertex_store->buffer = range - vertex_store->used;
259          assert(vertex_store->buffer);
260          return range;
261       }
262       else {
263          vertex_store->buffer = NULL;
264          return NULL;
265       }
266    }
267    else {
268       /* probably ran out of memory for buffers */
269       return NULL;
270    }
271 }
272
273
274 void
275 vbo_save_unmap_vertex_store(struct gl_context *ctx,
276                             struct vbo_save_vertex_store *vertex_store)
277 {
278    if (vertex_store->bufferobj->Size > 0) {
279       GLintptr offset = 0;
280       GLsizeiptr length = vertex_store->used * sizeof(GLfloat)
281          - vertex_store->bufferobj->Mappings[MAP_INTERNAL].Offset;
282
283       /* Explicitly flush the region we wrote to */
284       ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
285                                          vertex_store->bufferobj,
286                                          MAP_INTERNAL);
287
288       ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj, MAP_INTERNAL);
289    }
290    vertex_store->buffer = NULL;
291 }
292
293
294 static struct vbo_save_primitive_store *
295 alloc_prim_store(struct gl_context *ctx)
296 {
297    struct vbo_save_primitive_store *store =
298       CALLOC_STRUCT(vbo_save_primitive_store);
299    (void) ctx;
300    store->used = 0;
301    store->refcount = 1;
302    return store;
303 }
304
305
306 static void
307 _save_reset_counters(struct gl_context *ctx)
308 {
309    struct vbo_save_context *save = &vbo_context(ctx)->save;
310
311    save->prim = save->prim_store->buffer + save->prim_store->used;
312    save->buffer = save->vertex_store->buffer + save->vertex_store->used;
313
314    assert(save->buffer == save->buffer_ptr);
315
316    if (save->vertex_size)
317       save->max_vert = (VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
318                         save->vertex_size;
319    else
320       save->max_vert = 0;
321
322    save->vert_count = 0;
323    save->prim_count = 0;
324    save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
325    save->dangling_attr_ref = GL_FALSE;
326 }
327
328 /**
329  * For a list of prims, try merging prims that can just be extensions of the
330  * previous prim.
331  */
332 static void
333 merge_prims(struct _mesa_prim *prim_list,
334             GLuint *prim_count)
335 {
336    GLuint i;
337    struct _mesa_prim *prev_prim = prim_list;
338
339    for (i = 1; i < *prim_count; i++) {
340       struct _mesa_prim *this_prim = prim_list + i;
341
342       vbo_try_prim_conversion(this_prim);
343
344       if (vbo_can_merge_prims(prev_prim, this_prim)) {
345          /* We've found a prim that just extend the previous one.  Tack it
346           * onto the previous one, and let this primitive struct get dropped.
347           */
348          vbo_merge_prims(prev_prim, this_prim);
349          continue;
350       }
351
352       /* If any previous primitives have been dropped, then we need to copy
353        * this later one into the next available slot.
354        */
355       prev_prim++;
356       if (prev_prim != this_prim)
357          *prev_prim = *this_prim;
358    }
359
360    *prim_count = prev_prim - prim_list + 1;
361 }
362
363
364 /**
365  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
366  * don't have to worry about handling the _mesa_prim::begin/end flags.
367  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
368  */
369 static void
370 convert_line_loop_to_strip(struct vbo_save_context *save,
371                            struct vbo_save_vertex_list *node)
372 {
373    struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
374
375    assert(prim->mode == GL_LINE_LOOP);
376
377    if (prim->end) {
378       /* Copy the 0th vertex to end of the buffer and extend the
379        * vertex count by one to finish the line loop.
380        */
381       const GLuint sz = save->vertex_size;
382       /* 0th vertex: */
383       const fi_type *src = save->buffer + prim->start * sz;
384       /* end of buffer: */
385       fi_type *dst = save->buffer + (prim->start + prim->count) * sz;
386
387       memcpy(dst, src, sz * sizeof(float));
388
389       prim->count++;
390       node->count++;
391       save->vert_count++;
392       save->buffer_ptr += sz;
393       save->vertex_store->used += sz;
394    }
395
396    if (!prim->begin) {
397       /* Drawing the second or later section of a long line loop.
398        * Skip the 0th vertex.
399        */
400       prim->start++;
401       prim->count--;
402    }
403
404    prim->mode = GL_LINE_STRIP;
405 }
406
407
408 /**
409  * Insert the active immediate struct onto the display list currently
410  * being built.
411  */
412 static void
413 _save_compile_vertex_list(struct gl_context *ctx)
414 {
415    struct vbo_save_context *save = &vbo_context(ctx)->save;
416    struct vbo_save_vertex_list *node;
417
418    /* Allocate space for this structure in the display list currently
419     * being compiled.
420     */
421    node = (struct vbo_save_vertex_list *)
422       _mesa_dlist_alloc_aligned(ctx, save->opcode_vertex_list, sizeof(*node));
423
424    if (!node)
425       return;
426
427    /* Make sure the pointer is aligned to the size of a pointer */
428    assert((GLintptr) node % sizeof(void *) == 0);
429
430    /* Duplicate our template, increment refcounts to the storage structs:
431     */
432    memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
433    memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
434    node->vertex_size = save->vertex_size;
435    node->buffer_offset =
436       (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
437    node->count = save->vert_count;
438    node->wrap_count = save->copied.nr;
439    node->dangling_attr_ref = save->dangling_attr_ref;
440    node->prim = save->prim;
441    node->prim_count = save->prim_count;
442    node->vertex_store = save->vertex_store;
443    node->prim_store = save->prim_store;
444
445    node->vertex_store->refcount++;
446    node->prim_store->refcount++;
447
448    if (node->prim[0].no_current_update) {
449       node->current_size = 0;
450       node->current_data = NULL;
451    }
452    else {
453       node->current_size = node->vertex_size - node->attrsz[0];
454       node->current_data = NULL;
455
456       if (node->current_size) {
457          /* If the malloc fails, we just pull the data out of the VBO
458           * later instead.
459           */
460          node->current_data = malloc(node->current_size * sizeof(GLfloat));
461          if (node->current_data) {
462             const char *buffer = (const char *) save->vertex_store->buffer;
463             unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
464             unsigned vertex_offset = 0;
465
466             if (node->count)
467                vertex_offset =
468                   (node->count - 1) * node->vertex_size * sizeof(GLfloat);
469
470             memcpy(node->current_data,
471                    buffer + node->buffer_offset + vertex_offset + attr_offset,
472                    node->current_size * sizeof(GLfloat));
473          }
474       }
475    }
476
477    assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
478
479    if (save->dangling_attr_ref)
480       ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
481
482    save->vertex_store->used += save->vertex_size * node->count;
483    save->prim_store->used += node->prim_count;
484
485    /* Copy duplicated vertices
486     */
487    save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
488
489    if (node->prim[node->prim_count - 1].mode == GL_LINE_LOOP) {
490       convert_line_loop_to_strip(save, node);
491    }
492
493    merge_prims(node->prim, &node->prim_count);
494
495    /* Deal with GL_COMPILE_AND_EXECUTE:
496     */
497    if (ctx->ExecuteFlag) {
498       struct _glapi_table *dispatch = GET_DISPATCH();
499
500       _glapi_set_dispatch(ctx->Exec);
501
502       vbo_loopback_vertex_list(ctx,
503                                (const GLfloat *) ((const char *) save->
504                                                   vertex_store->buffer +
505                                                   node->buffer_offset),
506                                node->attrsz, node->prim, node->prim_count,
507                                node->wrap_count, node->vertex_size);
508
509       _glapi_set_dispatch(dispatch);
510    }
511
512    /* Decide whether the storage structs are full, or can be used for
513     * the next vertex lists as well.
514     */
515    if (save->vertex_store->used >
516        VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
517
518       /* Unmap old store:
519        */
520       vbo_save_unmap_vertex_store(ctx, save->vertex_store);
521
522       /* Release old reference:
523        */
524       save->vertex_store->refcount--;
525       assert(save->vertex_store->refcount != 0);
526       save->vertex_store = NULL;
527
528       /* Allocate and map new store:
529        */
530       save->vertex_store = alloc_vertex_store(ctx);
531       save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
532       save->out_of_memory = save->buffer_ptr == NULL;
533    }
534    else {
535       /* update buffer_ptr for next vertex */
536       save->buffer_ptr = save->vertex_store->buffer + save->vertex_store->used;
537    }
538
539    if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
540       save->prim_store->refcount--;
541       assert(save->prim_store->refcount != 0);
542       save->prim_store = alloc_prim_store(ctx);
543    }
544
545    /* Reset our structures for the next run of vertices:
546     */
547    _save_reset_counters(ctx);
548 }
549
550
551 /**
552  * This is called when we fill a vertex buffer before we hit a glEnd().
553  * We
554  * TODO -- If no new vertices have been stored, don't bother saving it.
555  */
556 static void
557 _save_wrap_buffers(struct gl_context *ctx)
558 {
559    struct vbo_save_context *save = &vbo_context(ctx)->save;
560    GLint i = save->prim_count - 1;
561    GLenum mode;
562    GLboolean weak;
563    GLboolean no_current_update;
564
565    assert(i < (GLint) save->prim_max);
566    assert(i >= 0);
567
568    /* Close off in-progress primitive.
569     */
570    save->prim[i].count = (save->vert_count - save->prim[i].start);
571    mode = save->prim[i].mode;
572    weak = save->prim[i].weak;
573    no_current_update = save->prim[i].no_current_update;
574
575    /* store the copied vertices, and allocate a new list.
576     */
577    _save_compile_vertex_list(ctx);
578
579    /* Restart interrupted primitive
580     */
581    save->prim[0].mode = mode;
582    save->prim[0].weak = weak;
583    save->prim[0].no_current_update = no_current_update;
584    save->prim[0].begin = 0;
585    save->prim[0].end = 0;
586    save->prim[0].pad = 0;
587    save->prim[0].start = 0;
588    save->prim[0].count = 0;
589    save->prim[0].num_instances = 1;
590    save->prim[0].base_instance = 0;
591    save->prim[0].is_indirect = 0;
592    save->prim_count = 1;
593 }
594
595
596 /**
597  * Called only when buffers are wrapped as the result of filling the
598  * vertex_store struct.
599  */
600 static void
601 _save_wrap_filled_vertex(struct gl_context *ctx)
602 {
603    struct vbo_save_context *save = &vbo_context(ctx)->save;
604    unsigned numComponents;
605
606    /* Emit a glEnd to close off the last vertex list.
607     */
608    _save_wrap_buffers(ctx);
609
610    /* Copy stored stored vertices to start of new list.
611     */
612    assert(save->max_vert - save->vert_count > save->copied.nr);
613
614    numComponents = save->copied.nr * save->vertex_size;
615    memcpy(save->buffer_ptr,
616           save->copied.buffer,
617           numComponents * sizeof(fi_type));
618    save->buffer_ptr += numComponents;
619    save->vert_count += save->copied.nr;
620 }
621
622
623 static void
624 _save_copy_to_current(struct gl_context *ctx)
625 {
626    struct vbo_save_context *save = &vbo_context(ctx)->save;
627    GLuint i;
628
629    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
630       if (save->attrsz[i]) {
631          save->currentsz[i][0] = save->attrsz[i];
632          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
633                                      save->attrptr[i], save->attrtype[i]);
634       }
635    }
636 }
637
638
639 static void
640 _save_copy_from_current(struct gl_context *ctx)
641 {
642    struct vbo_save_context *save = &vbo_context(ctx)->save;
643    GLint i;
644
645    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
646       switch (save->attrsz[i]) {
647       case 4:
648          save->attrptr[i][3] = save->current[i][3];
649       case 3:
650          save->attrptr[i][2] = save->current[i][2];
651       case 2:
652          save->attrptr[i][1] = save->current[i][1];
653       case 1:
654          save->attrptr[i][0] = save->current[i][0];
655       case 0:
656          break;
657       }
658    }
659 }
660
661
662 /**
663  * Called when we increase the size of a vertex attribute.  For example,
664  * if we've seen one or more glTexCoord2f() calls and now we get a
665  * glTexCoord3f() call.
666  * Flush existing data, set new attrib size, replay copied vertices.
667  */
668 static void
669 _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
670 {
671    struct vbo_save_context *save = &vbo_context(ctx)->save;
672    GLuint oldsz;
673    GLuint i;
674    fi_type *tmp;
675
676    /* Store the current run of vertices, and emit a GL_END.  Emit a
677     * BEGIN in the new buffer.
678     */
679    if (save->vert_count)
680       _save_wrap_buffers(ctx);
681    else
682       assert(save->copied.nr == 0);
683
684    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
685     * when the attribute already exists in the vertex and is having
686     * its size increased.
687     */
688    _save_copy_to_current(ctx);
689
690    /* Fix up sizes:
691     */
692    oldsz = save->attrsz[attr];
693    save->attrsz[attr] = newsz;
694
695    save->vertex_size += newsz - oldsz;
696    save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
697                      save->vertex_size);
698    save->vert_count = 0;
699
700    /* Recalculate all the attrptr[] values:
701     */
702    tmp = save->vertex;
703    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
704       if (save->attrsz[i]) {
705          save->attrptr[i] = tmp;
706          tmp += save->attrsz[i];
707       }
708       else {
709          save->attrptr[i] = NULL;       /* will not be dereferenced. */
710       }
711    }
712
713    /* Copy from current to repopulate the vertex with correct values.
714     */
715    _save_copy_from_current(ctx);
716
717    /* Replay stored vertices to translate them to new format here.
718     *
719     * If there are copied vertices and the new (upgraded) attribute
720     * has not been defined before, this list is somewhat degenerate,
721     * and will need fixup at runtime.
722     */
723    if (save->copied.nr) {
724       const fi_type *data = save->copied.buffer;
725       fi_type *dest = save->buffer;
726       GLuint j;
727
728       /* Need to note this and fix up at runtime (or loopback):
729        */
730       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
731          assert(oldsz == 0);
732          save->dangling_attr_ref = GL_TRUE;
733       }
734
735       for (i = 0; i < save->copied.nr; i++) {
736          for (j = 0; j < VBO_ATTRIB_MAX; j++) {
737             if (save->attrsz[j]) {
738                if (j == attr) {
739                   if (oldsz) {
740                      COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
741                                                  save->attrtype[j]);
742                      data += oldsz;
743                      dest += newsz;
744                   }
745                   else {
746                      COPY_SZ_4V(dest, newsz, save->current[attr]);
747                      dest += newsz;
748                   }
749                }
750                else {
751                   GLint sz = save->attrsz[j];
752                   COPY_SZ_4V(dest, sz, data);
753                   data += sz;
754                   dest += sz;
755                }
756             }
757          }
758       }
759
760       save->buffer_ptr = dest;
761       save->vert_count += save->copied.nr;
762    }
763 }
764
765
766 /**
767  * This is called when the size of a vertex attribute changes.
768  * For example, after seeing one or more glTexCoord2f() calls we
769  * get a glTexCoord4f() or glTexCoord1f() call.
770  */
771 static void
772 save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
773 {
774    struct vbo_save_context *save = &vbo_context(ctx)->save;
775
776    if (sz > save->attrsz[attr]) {
777       /* New size is larger.  Need to flush existing vertices and get
778        * an enlarged vertex format.
779        */
780       _save_upgrade_vertex(ctx, attr, sz);
781    }
782    else if (sz < save->active_sz[attr]) {
783       GLuint i;
784       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
785
786       /* New size is equal or smaller - just need to fill in some
787        * zeros.
788        */
789       for (i = sz; i <= save->attrsz[attr]; i++)
790          save->attrptr[attr][i - 1] = id[i - 1];
791    }
792
793    save->active_sz[attr] = sz;
794 }
795
796
797 /**
798  * Reset the current size of all vertex attributes to the default
799  * value of 0.  This signals that we haven't yet seen any per-vertex
800  * commands such as glNormal3f() or glTexCoord2f().
801  */
802 static void
803 _save_reset_vertex(struct gl_context *ctx)
804 {
805    struct vbo_save_context *save = &vbo_context(ctx)->save;
806    GLuint i;
807
808    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
809       save->attrsz[i] = 0;
810       save->active_sz[i] = 0;
811    }
812
813    save->vertex_size = 0;
814 }
815
816
817
818 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
819
820
821 /* Only one size for each attribute may be active at once.  Eg. if
822  * Color3f is installed/active, then Color4f may not be, even if the
823  * vertex actually contains 4 color coordinates.  This is because the
824  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
825  * of the chooser function when switching between Color4f and Color3f.
826  */
827 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
828 do {                                                            \
829    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
830                                                                 \
831    if (save->active_sz[A] != N)                                 \
832       save_fixup_vertex(ctx, A, N);                             \
833                                                                 \
834    {                                                            \
835       C *dest = (C *)save->attrptr[A];                          \
836       if (N>0) dest[0] = V0;                                    \
837       if (N>1) dest[1] = V1;                                    \
838       if (N>2) dest[2] = V2;                                    \
839       if (N>3) dest[3] = V3;                                    \
840       save->attrtype[A] = T;                                    \
841    }                                                            \
842                                                                 \
843    if ((A) == 0) {                                              \
844       GLuint i;                                                 \
845                                                                 \
846       for (i = 0; i < save->vertex_size; i++)                   \
847          save->buffer_ptr[i] = save->vertex[i];                 \
848                                                                 \
849       save->buffer_ptr += save->vertex_size;                    \
850                                                                 \
851       if (++save->vert_count >= save->max_vert)                 \
852          _save_wrap_filled_vertex(ctx);                         \
853    }                                                            \
854 } while (0)
855
856 #define TAG(x) _save_##x
857
858 #include "vbo_attrib_tmp.h"
859
860
861
862 #define MAT( ATTR, N, face, params )                    \
863 do {                                                    \
864    if (face != GL_BACK)                                 \
865       MAT_ATTR( ATTR, N, params ); /* front */          \
866    if (face != GL_FRONT)                                \
867       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
868 } while (0)
869
870
871 /**
872  * Save a glMaterial call found between glBegin/End.
873  * glMaterial calls outside Begin/End are handled in dlist.c.
874  */
875 static void GLAPIENTRY
876 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
877 {
878    GET_CURRENT_CONTEXT(ctx);
879
880    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
881       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
882       return;
883    }
884
885    switch (pname) {
886    case GL_EMISSION:
887       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
888       break;
889    case GL_AMBIENT:
890       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
891       break;
892    case GL_DIFFUSE:
893       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
894       break;
895    case GL_SPECULAR:
896       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
897       break;
898    case GL_SHININESS:
899       if (*params < 0 || *params > ctx->Const.MaxShininess) {
900          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
901       }
902       else {
903          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
904       }
905       break;
906    case GL_COLOR_INDEXES:
907       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
908       break;
909    case GL_AMBIENT_AND_DIFFUSE:
910       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
911       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
912       break;
913    default:
914       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
915       return;
916    }
917 }
918
919
920 /* Cope with EvalCoord/CallList called within a begin/end object:
921  *     -- Flush current buffer
922  *     -- Fallback to opcodes for the rest of the begin/end object.
923  */
924 static void
925 dlist_fallback(struct gl_context *ctx)
926 {
927    struct vbo_save_context *save = &vbo_context(ctx)->save;
928
929    if (save->vert_count || save->prim_count) {
930       if (save->prim_count > 0) {
931          /* Close off in-progress primitive. */
932          GLint i = save->prim_count - 1;
933          save->prim[i].count = save->vert_count - save->prim[i].start;
934       }
935
936       /* Need to replay this display list with loopback,
937        * unfortunately, otherwise this primitive won't be handled
938        * properly:
939        */
940       save->dangling_attr_ref = GL_TRUE;
941
942       _save_compile_vertex_list(ctx);
943    }
944
945    _save_copy_to_current(ctx);
946    _save_reset_vertex(ctx);
947    _save_reset_counters(ctx);
948    if (save->out_of_memory) {
949       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
950    }
951    else {
952       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
953    }
954    ctx->Driver.SaveNeedFlush = GL_FALSE;
955 }
956
957
958 static void GLAPIENTRY
959 _save_EvalCoord1f(GLfloat u)
960 {
961    GET_CURRENT_CONTEXT(ctx);
962    dlist_fallback(ctx);
963    CALL_EvalCoord1f(ctx->Save, (u));
964 }
965
966 static void GLAPIENTRY
967 _save_EvalCoord1fv(const GLfloat * v)
968 {
969    GET_CURRENT_CONTEXT(ctx);
970    dlist_fallback(ctx);
971    CALL_EvalCoord1fv(ctx->Save, (v));
972 }
973
974 static void GLAPIENTRY
975 _save_EvalCoord2f(GLfloat u, GLfloat v)
976 {
977    GET_CURRENT_CONTEXT(ctx);
978    dlist_fallback(ctx);
979    CALL_EvalCoord2f(ctx->Save, (u, v));
980 }
981
982 static void GLAPIENTRY
983 _save_EvalCoord2fv(const GLfloat * v)
984 {
985    GET_CURRENT_CONTEXT(ctx);
986    dlist_fallback(ctx);
987    CALL_EvalCoord2fv(ctx->Save, (v));
988 }
989
990 static void GLAPIENTRY
991 _save_EvalPoint1(GLint i)
992 {
993    GET_CURRENT_CONTEXT(ctx);
994    dlist_fallback(ctx);
995    CALL_EvalPoint1(ctx->Save, (i));
996 }
997
998 static void GLAPIENTRY
999 _save_EvalPoint2(GLint i, GLint j)
1000 {
1001    GET_CURRENT_CONTEXT(ctx);
1002    dlist_fallback(ctx);
1003    CALL_EvalPoint2(ctx->Save, (i, j));
1004 }
1005
1006 static void GLAPIENTRY
1007 _save_CallList(GLuint l)
1008 {
1009    GET_CURRENT_CONTEXT(ctx);
1010    dlist_fallback(ctx);
1011    CALL_CallList(ctx->Save, (l));
1012 }
1013
1014 static void GLAPIENTRY
1015 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1016 {
1017    GET_CURRENT_CONTEXT(ctx);
1018    dlist_fallback(ctx);
1019    CALL_CallLists(ctx->Save, (n, type, v));
1020 }
1021
1022
1023
1024 /**
1025  * Called when a glBegin is getting compiled into a display list.
1026  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1027  */
1028 GLboolean
1029 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
1030 {
1031    struct vbo_save_context *save = &vbo_context(ctx)->save;
1032    const GLuint i = save->prim_count++;
1033
1034    assert(i < save->prim_max);
1035    save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1036    save->prim[i].begin = 1;
1037    save->prim[i].end = 0;
1038    save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
1039    save->prim[i].no_current_update =
1040       (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
1041    save->prim[i].pad = 0;
1042    save->prim[i].start = save->vert_count;
1043    save->prim[i].count = 0;
1044    save->prim[i].num_instances = 1;
1045    save->prim[i].base_instance = 0;
1046    save->prim[i].is_indirect = 0;
1047
1048    if (save->out_of_memory) {
1049       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1050    }
1051    else {
1052       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1053    }
1054
1055    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1056    ctx->Driver.SaveNeedFlush = GL_TRUE;
1057
1058    /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
1059     * opcode into the display list.
1060     */
1061    return GL_TRUE;
1062 }
1063
1064
1065 static void GLAPIENTRY
1066 _save_End(void)
1067 {
1068    GET_CURRENT_CONTEXT(ctx);
1069    struct vbo_save_context *save = &vbo_context(ctx)->save;
1070    const GLint i = save->prim_count - 1;
1071
1072    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1073    save->prim[i].end = 1;
1074    save->prim[i].count = (save->vert_count - save->prim[i].start);
1075
1076    if (i == (GLint) save->prim_max - 1) {
1077       _save_compile_vertex_list(ctx);
1078       assert(save->copied.nr == 0);
1079    }
1080
1081    /* Swap out this vertex format while outside begin/end.  Any color,
1082     * etc. received between here and the next begin will be compiled
1083     * as opcodes.
1084     */
1085    if (save->out_of_memory) {
1086       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1087    }
1088    else {
1089       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1090    }
1091 }
1092
1093
1094 static void GLAPIENTRY
1095 _save_Begin(GLenum mode)
1096 {
1097    GET_CURRENT_CONTEXT(ctx);
1098    (void) mode;
1099    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1100 }
1101
1102
1103 static void GLAPIENTRY
1104 _save_PrimitiveRestartNV(void)
1105 {
1106    GLenum curPrim;
1107    GET_CURRENT_CONTEXT(ctx);
1108
1109    curPrim = ctx->Driver.CurrentSavePrimitive;
1110
1111    _save_End();
1112    _save_Begin(curPrim);
1113 }
1114
1115
1116 /* Unlike the functions above, these are to be hooked into the vtxfmt
1117  * maintained in ctx->ListState, active when the list is known or
1118  * suspected to be outside any begin/end primitive.
1119  * Note: OBE = Outside Begin/End
1120  */
1121 static void GLAPIENTRY
1122 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1123 {
1124    GET_CURRENT_CONTEXT(ctx);
1125    vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
1126    CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1127    CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1128    CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1129    CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1130    CALL_End(GET_DISPATCH(), ());
1131 }
1132
1133
1134 static void GLAPIENTRY
1135 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1136 {
1137    GET_CURRENT_CONTEXT(ctx);
1138    struct vbo_save_context *save = &vbo_context(ctx)->save;
1139    GLint i;
1140
1141    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1142       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1143       return;
1144    }
1145    if (count < 0) {
1146       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1147       return;
1148    }
1149
1150    if (save->out_of_memory)
1151       return;
1152
1153    _ae_map_vbos(ctx);
1154
1155    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
1156                               | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1157
1158    for (i = 0; i < count; i++)
1159       CALL_ArrayElement(GET_DISPATCH(), (start + i));
1160    CALL_End(GET_DISPATCH(), ());
1161
1162    _ae_unmap_vbos(ctx);
1163 }
1164
1165
1166 /* Could do better by copying the arrays and element list intact and
1167  * then emitting an indexed prim at runtime.
1168  */
1169 static void GLAPIENTRY
1170 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1171                                  const GLvoid * indices, GLint basevertex)
1172 {
1173    GET_CURRENT_CONTEXT(ctx);
1174    struct vbo_save_context *save = &vbo_context(ctx)->save;
1175    struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj;
1176    GLint i;
1177
1178    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1179       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1180       return;
1181    }
1182    if (count < 0) {
1183       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1184       return;
1185    }
1186    if (type != GL_UNSIGNED_BYTE &&
1187        type != GL_UNSIGNED_SHORT &&
1188        type != GL_UNSIGNED_INT) {
1189       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1190       return;
1191    }
1192
1193    if (save->out_of_memory)
1194       return;
1195
1196    _ae_map_vbos(ctx);
1197
1198    if (_mesa_is_bufferobj(indexbuf))
1199       indices =
1200          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1201
1202    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
1203                               VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1204
1205    switch (type) {
1206    case GL_UNSIGNED_BYTE:
1207       for (i = 0; i < count; i++)
1208          CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLubyte *) indices)[i]));
1209       break;
1210    case GL_UNSIGNED_SHORT:
1211       for (i = 0; i < count; i++)
1212          CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLushort *) indices)[i]));
1213       break;
1214    case GL_UNSIGNED_INT:
1215       for (i = 0; i < count; i++)
1216          CALL_ArrayElement(GET_DISPATCH(), (basevertex + ((GLuint *) indices)[i]));
1217       break;
1218    default:
1219       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1220       break;
1221    }
1222
1223    CALL_End(GET_DISPATCH(), ());
1224
1225    _ae_unmap_vbos(ctx);
1226 }
1227
1228 static void GLAPIENTRY
1229 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1230                        const GLvoid * indices)
1231 {
1232    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1233 }
1234
1235
1236 static void GLAPIENTRY
1237 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1238                             GLsizei count, GLenum type,
1239                             const GLvoid * indices)
1240 {
1241    GET_CURRENT_CONTEXT(ctx);
1242    struct vbo_save_context *save = &vbo_context(ctx)->save;
1243
1244    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1245       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1246       return;
1247    }
1248    if (count < 0) {
1249       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1250                           "glDrawRangeElements(count<0)");
1251       return;
1252    }
1253    if (type != GL_UNSIGNED_BYTE &&
1254        type != GL_UNSIGNED_SHORT &&
1255        type != GL_UNSIGNED_INT) {
1256       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1257       return;
1258    }
1259    if (end < start) {
1260       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1261                           "glDrawRangeElements(end < start)");
1262       return;
1263    }
1264
1265    if (save->out_of_memory)
1266       return;
1267
1268    _save_OBE_DrawElements(mode, count, type, indices);
1269 }
1270
1271
1272 static void GLAPIENTRY
1273 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1274                             const GLvoid * const *indices, GLsizei primcount)
1275 {
1276    GLsizei i;
1277
1278    for (i = 0; i < primcount; i++) {
1279       if (count[i] > 0) {
1280          CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1281       }
1282    }
1283 }
1284
1285
1286 static void GLAPIENTRY
1287 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1288                                       GLenum type,
1289                                       const GLvoid * const *indices,
1290                                       GLsizei primcount,
1291                                       const GLint *basevertex)
1292 {
1293    GLsizei i;
1294
1295    for (i = 0; i < primcount; i++) {
1296       if (count[i] > 0) {
1297          CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1298                                                       indices[i],
1299                                                       basevertex[i]));
1300       }
1301    }
1302 }
1303
1304
1305 static void
1306 _save_vtxfmt_init(struct gl_context *ctx)
1307 {
1308    struct vbo_save_context *save = &vbo_context(ctx)->save;
1309    GLvertexformat *vfmt = &save->vtxfmt;
1310
1311    vfmt->ArrayElement = _ae_ArrayElement;
1312
1313    vfmt->Color3f = _save_Color3f;
1314    vfmt->Color3fv = _save_Color3fv;
1315    vfmt->Color4f = _save_Color4f;
1316    vfmt->Color4fv = _save_Color4fv;
1317    vfmt->EdgeFlag = _save_EdgeFlag;
1318    vfmt->End = _save_End;
1319    vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1320    vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1321    vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1322    vfmt->Indexf = _save_Indexf;
1323    vfmt->Indexfv = _save_Indexfv;
1324    vfmt->Materialfv = _save_Materialfv;
1325    vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1326    vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1327    vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1328    vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1329    vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1330    vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1331    vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1332    vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1333    vfmt->Normal3f = _save_Normal3f;
1334    vfmt->Normal3fv = _save_Normal3fv;
1335    vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1336    vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1337    vfmt->TexCoord1f = _save_TexCoord1f;
1338    vfmt->TexCoord1fv = _save_TexCoord1fv;
1339    vfmt->TexCoord2f = _save_TexCoord2f;
1340    vfmt->TexCoord2fv = _save_TexCoord2fv;
1341    vfmt->TexCoord3f = _save_TexCoord3f;
1342    vfmt->TexCoord3fv = _save_TexCoord3fv;
1343    vfmt->TexCoord4f = _save_TexCoord4f;
1344    vfmt->TexCoord4fv = _save_TexCoord4fv;
1345    vfmt->Vertex2f = _save_Vertex2f;
1346    vfmt->Vertex2fv = _save_Vertex2fv;
1347    vfmt->Vertex3f = _save_Vertex3f;
1348    vfmt->Vertex3fv = _save_Vertex3fv;
1349    vfmt->Vertex4f = _save_Vertex4f;
1350    vfmt->Vertex4fv = _save_Vertex4fv;
1351    vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1352    vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1353    vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1354    vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1355    vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1356    vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1357    vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1358    vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1359
1360    vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1361    vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1362    vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1363    vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1364    vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1365    vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1366    vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1367    vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1368
1369    /* integer-valued */
1370    vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1371    vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1372    vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1373    vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1374    vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1375    vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1376    vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1377
1378    /* unsigned integer-valued */
1379    vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1380    vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1381    vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1382    vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1383    vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1384    vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1385    vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1386
1387    vfmt->VertexP2ui = _save_VertexP2ui;
1388    vfmt->VertexP3ui = _save_VertexP3ui;
1389    vfmt->VertexP4ui = _save_VertexP4ui;
1390    vfmt->VertexP2uiv = _save_VertexP2uiv;
1391    vfmt->VertexP3uiv = _save_VertexP3uiv;
1392    vfmt->VertexP4uiv = _save_VertexP4uiv;
1393
1394    vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1395    vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1396    vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1397    vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1398    vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1399    vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1400    vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1401    vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1402
1403    vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1404    vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1405    vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1406    vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1407    vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1408    vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1409    vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1410    vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1411
1412    vfmt->NormalP3ui = _save_NormalP3ui;
1413    vfmt->NormalP3uiv = _save_NormalP3uiv;
1414
1415    vfmt->ColorP3ui = _save_ColorP3ui;
1416    vfmt->ColorP4ui = _save_ColorP4ui;
1417    vfmt->ColorP3uiv = _save_ColorP3uiv;
1418    vfmt->ColorP4uiv = _save_ColorP4uiv;
1419
1420    vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1421    vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1422
1423    vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1424    vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1425    vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1426    vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1427
1428    vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1429    vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1430    vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1431    vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1432
1433    vfmt->VertexAttribL1d = _save_VertexAttribL1d;
1434    vfmt->VertexAttribL2d = _save_VertexAttribL2d;
1435    vfmt->VertexAttribL3d = _save_VertexAttribL3d;
1436    vfmt->VertexAttribL4d = _save_VertexAttribL4d;
1437
1438    vfmt->VertexAttribL1dv = _save_VertexAttribL1dv;
1439    vfmt->VertexAttribL2dv = _save_VertexAttribL2dv;
1440    vfmt->VertexAttribL3dv = _save_VertexAttribL3dv;
1441    vfmt->VertexAttribL4dv = _save_VertexAttribL4dv;
1442
1443    /* This will all require us to fallback to saving the list as opcodes:
1444     */
1445    vfmt->CallList = _save_CallList;
1446    vfmt->CallLists = _save_CallLists;
1447
1448    vfmt->EvalCoord1f = _save_EvalCoord1f;
1449    vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1450    vfmt->EvalCoord2f = _save_EvalCoord2f;
1451    vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1452    vfmt->EvalPoint1 = _save_EvalPoint1;
1453    vfmt->EvalPoint2 = _save_EvalPoint2;
1454
1455    /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1456     * only used when we're inside a glBegin/End pair.
1457     */
1458    vfmt->Begin = _save_Begin;
1459 }
1460
1461
1462 /**
1463  * Initialize the dispatch table with the VBO functions for display
1464  * list compilation.
1465  */
1466 void
1467 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1468                              struct _glapi_table *exec)
1469 {
1470    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1471    SET_DrawElements(exec, _save_OBE_DrawElements);
1472    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1473    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1474    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1475    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1476    SET_Rectf(exec, _save_OBE_Rectf);
1477    /* Note: other glDraw functins aren't compiled into display lists */
1478 }
1479
1480
1481
1482 void
1483 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1484 {
1485    struct vbo_save_context *save = &vbo_context(ctx)->save;
1486
1487    /* Noop when we are actually active:
1488     */
1489    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1490       return;
1491
1492    if (save->vert_count || save->prim_count)
1493       _save_compile_vertex_list(ctx);
1494
1495    _save_copy_to_current(ctx);
1496    _save_reset_vertex(ctx);
1497    _save_reset_counters(ctx);
1498    ctx->Driver.SaveNeedFlush = GL_FALSE;
1499 }
1500
1501
1502 void
1503 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1504 {
1505    struct vbo_save_context *save = &vbo_context(ctx)->save;
1506
1507    (void) list;
1508    (void) mode;
1509
1510    if (!save->prim_store)
1511       save->prim_store = alloc_prim_store(ctx);
1512
1513    if (!save->vertex_store)
1514       save->vertex_store = alloc_vertex_store(ctx);
1515
1516    save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1517
1518    _save_reset_vertex(ctx);
1519    _save_reset_counters(ctx);
1520    ctx->Driver.SaveNeedFlush = GL_FALSE;
1521 }
1522
1523
1524 void
1525 vbo_save_EndList(struct gl_context *ctx)
1526 {
1527    struct vbo_save_context *save = &vbo_context(ctx)->save;
1528
1529    /* EndList called inside a (saved) Begin/End pair?
1530     */
1531    if (_mesa_inside_dlist_begin_end(ctx)) {
1532       if (save->prim_count > 0) {
1533          GLint i = save->prim_count - 1;
1534          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1535          save->prim[i].end = 0;
1536          save->prim[i].count = save->vert_count - save->prim[i].start;
1537       }
1538
1539       /* Make sure this vertex list gets replayed by the "loopback"
1540        * mechanism:
1541        */
1542       save->dangling_attr_ref = GL_TRUE;
1543       vbo_save_SaveFlushVertices(ctx);
1544
1545       /* Swap out this vertex format while outside begin/end.  Any color,
1546        * etc. received between here and the next begin will be compiled
1547        * as opcodes.
1548        */
1549       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1550    }
1551
1552    vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1553
1554    assert(save->vertex_size == 0);
1555 }
1556
1557
1558 void
1559 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1560 {
1561    struct vbo_save_context *save = &vbo_context(ctx)->save;
1562    save->replay_flags |= dlist->Flags;
1563 }
1564
1565
1566 void
1567 vbo_save_EndCallList(struct gl_context *ctx)
1568 {
1569    struct vbo_save_context *save = &vbo_context(ctx)->save;
1570
1571    if (ctx->ListState.CallDepth == 1) {
1572       /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1573        * flag, if it is set:
1574        */
1575       save->replay_flags &= VBO_SAVE_FALLBACK;
1576    }
1577 }
1578
1579
1580 static void
1581 vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1582 {
1583    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1584    (void) ctx;
1585
1586    if (--node->vertex_store->refcount == 0)
1587       free_vertex_store(ctx, node->vertex_store);
1588
1589    if (--node->prim_store->refcount == 0)
1590       free(node->prim_store);
1591
1592    free(node->current_data);
1593    node->current_data = NULL;
1594 }
1595
1596
1597 static void
1598 vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f)
1599 {
1600    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1601    GLuint i;
1602    struct gl_buffer_object *buffer = node->vertex_store ?
1603       node->vertex_store->bufferobj : NULL;
1604    (void) ctx;
1605
1606    fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1607            "buffer %p\n",
1608            node->count, node->prim_count, node->vertex_size,
1609            buffer);
1610
1611    for (i = 0; i < node->prim_count; i++) {
1612       struct _mesa_prim *prim = &node->prim[i];
1613       fprintf(f, "   prim %d: %s%s %d..%d %s %s\n",
1614              i,
1615              _mesa_lookup_prim_by_nr(prim->mode),
1616              prim->weak ? " (weak)" : "",
1617              prim->start,
1618              prim->start + prim->count,
1619              (prim->begin) ? "BEGIN" : "(wrap)",
1620              (prim->end) ? "END" : "(wrap)");
1621    }
1622 }
1623
1624
1625 /**
1626  * Called during context creation/init.
1627  */
1628 static void
1629 _save_current_init(struct gl_context *ctx)
1630 {
1631    struct vbo_save_context *save = &vbo_context(ctx)->save;
1632    GLint i;
1633
1634    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1635       const GLuint j = i - VBO_ATTRIB_POS;
1636       assert(j < VERT_ATTRIB_MAX);
1637       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1638       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1639    }
1640
1641    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1642       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1643       assert(j < MAT_ATTRIB_MAX);
1644       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1645       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1646    }
1647 }
1648
1649
1650 /**
1651  * Initialize the display list compiler.  Called during context creation.
1652  */
1653 void
1654 vbo_save_api_init(struct vbo_save_context *save)
1655 {
1656    struct gl_context *ctx = save->ctx;
1657    GLuint i;
1658
1659    save->opcode_vertex_list =
1660       _mesa_dlist_alloc_opcode(ctx,
1661                                sizeof(struct vbo_save_vertex_list),
1662                                vbo_save_playback_vertex_list,
1663                                vbo_destroy_vertex_list,
1664                                vbo_print_vertex_list);
1665
1666    _save_vtxfmt_init(ctx);
1667    _save_current_init(ctx);
1668    _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1669
1670    /* These will actually get set again when binding/drawing */
1671    for (i = 0; i < VBO_ATTRIB_MAX; i++)
1672       save->inputs[i] = &save->arrays[i];
1673 }