dlist: split hot/cold data from vertex_list
[platform/upstream/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/arrayobj.h"
72 #include "main/bufferobj.h"
73 #include "main/context.h"
74 #include "main/dlist.h"
75 #include "main/enums.h"
76 #include "main/eval.h"
77 #include "main/macros.h"
78 #include "main/draw_validate.h"
79 #include "main/api_arrayelt.h"
80 #include "main/vtxfmt.h"
81 #include "main/dispatch.h"
82 #include "main/state.h"
83 #include "main/varray.h"
84 #include "util/bitscan.h"
85 #include "util/u_memory.h"
86
87 #include "gallium/include/pipe/p_state.h"
88
89 #include "vbo_noop.h"
90 #include "vbo_private.h"
91
92
93 #ifdef ERROR
94 #undef ERROR
95 #endif
96
97 /**
98  * Display list flag only used by this VBO code.
99  */
100 #define DLIST_DANGLING_REFS     0x1
101
102
103 /* An interesting VBO number/name to help with debugging */
104 #define VBO_BUF_ID  12345
105
106 static void GLAPIENTRY
107 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
108
109 static void GLAPIENTRY
110 _save_EvalCoord1f(GLfloat u);
111
112 static void GLAPIENTRY
113 _save_EvalCoord2f(GLfloat u, GLfloat v);
114
115 /*
116  * NOTE: Old 'parity' issue is gone, but copying can still be
117  * wrong-footed on replay.
118  */
119 static GLuint
120 copy_vertices(struct gl_context *ctx,
121               const struct vbo_save_vertex_list *node,
122               const fi_type * src_buffer)
123 {
124    struct vbo_save_context *save = &vbo_context(ctx)->save;
125    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
126    GLuint sz = save->vertex_size;
127    const fi_type *src = src_buffer + prim->start * sz;
128    fi_type *dst = save->copied.buffer;
129
130    if (prim->end)
131       return 0;
132
133    return vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count,
134                             prim->begin, sz, true, dst, src);
135 }
136
137
138 static struct vbo_save_vertex_store *
139 alloc_vertex_store(struct gl_context *ctx, int vertex_count)
140 {
141    struct vbo_save_context *save = &vbo_context(ctx)->save;
142    struct vbo_save_vertex_store *vertex_store =
143       CALLOC_STRUCT(vbo_save_vertex_store);
144
145    int size = MAX2(vertex_count * save->vertex_size, VBO_SAVE_BUFFER_SIZE);
146
147    /* obj->Name needs to be non-zero, but won't ever be examined more
148     * closely than that.  In particular these buffers won't be entered
149     * into the hash and can never be confused with ones visible to the
150     * user.  Perhaps there could be a special number for internal
151     * buffers:
152     */
153    vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID);
154    if (vertex_store->bufferobj) {
155       save->out_of_memory =
156          !ctx->Driver.BufferData(ctx,
157                                  GL_ARRAY_BUFFER_ARB,
158                                  size * sizeof(GLfloat),
159                                  NULL, GL_STATIC_DRAW_ARB,
160                                  GL_MAP_WRITE_BIT |
161                                  GL_DYNAMIC_STORAGE_BIT,
162                                  vertex_store->bufferobj);
163    }
164    else {
165       save->out_of_memory = GL_TRUE;
166    }
167
168    if (save->out_of_memory) {
169       _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
170       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
171    }
172
173    vertex_store->buffer_map = NULL;
174    vertex_store->used = 0;
175
176    return vertex_store;
177 }
178
179
180 static void
181 free_vertex_store(struct gl_context *ctx,
182                   struct vbo_save_vertex_store *vertex_store)
183 {
184    assert(!vertex_store->buffer_map);
185
186    if (vertex_store->bufferobj) {
187       _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
188    }
189
190    free(vertex_store);
191 }
192
193
194 fi_type *
195 vbo_save_map_vertex_store(struct gl_context *ctx,
196                           struct vbo_save_vertex_store *vertex_store)
197 {
198    const GLbitfield access = (GL_MAP_WRITE_BIT |
199                               GL_MAP_INVALIDATE_RANGE_BIT |
200                               GL_MAP_UNSYNCHRONIZED_BIT |
201                               GL_MAP_FLUSH_EXPLICIT_BIT |
202                               MESA_MAP_ONCE);
203
204    assert(vertex_store->bufferobj);
205    assert(!vertex_store->buffer_map);  /* the buffer should not be mapped */
206
207    if (vertex_store->bufferobj->Size > 0) {
208       /* Map the remaining free space in the VBO */
209       GLintptr offset = vertex_store->used * sizeof(GLfloat);
210       GLsizeiptr size = vertex_store->bufferobj->Size - offset;
211       fi_type *range = (fi_type *)
212          ctx->Driver.MapBufferRange(ctx, offset, size, access,
213                                     vertex_store->bufferobj,
214                                     MAP_INTERNAL);
215       if (range) {
216          /* compute address of start of whole buffer (needed elsewhere) */
217          vertex_store->buffer_map = range - vertex_store->used;
218          assert(vertex_store->buffer_map);
219          return range;
220       }
221       else {
222          vertex_store->buffer_map = NULL;
223          return NULL;
224       }
225    }
226    else {
227       /* probably ran out of memory for buffers */
228       return NULL;
229    }
230 }
231
232
233 void
234 vbo_save_unmap_vertex_store(struct gl_context *ctx,
235                             struct vbo_save_vertex_store *vertex_store)
236 {
237    if (vertex_store->bufferobj->Size > 0) {
238       GLintptr offset = 0;
239       GLsizeiptr length = vertex_store->used * sizeof(GLfloat)
240          - vertex_store->bufferobj->Mappings[MAP_INTERNAL].Offset;
241
242       /* Explicitly flush the region we wrote to */
243       ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
244                                          vertex_store->bufferobj,
245                                          MAP_INTERNAL);
246
247       ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj, MAP_INTERNAL);
248    }
249    vertex_store->buffer_map = NULL;
250 }
251
252
253 static struct vbo_save_primitive_store *
254 alloc_prim_store(int prim_count)
255 {
256    struct vbo_save_primitive_store *store =
257       CALLOC_STRUCT(vbo_save_primitive_store);
258    store->size = MAX2(prim_count, VBO_SAVE_PRIM_SIZE);
259    store->prims = calloc(store->size, sizeof(struct _mesa_prim));
260    store->used = 0;
261    store->refcount = 1;
262    return store;
263 }
264
265
266 static void
267 reset_counters(struct gl_context *ctx)
268 {
269    struct vbo_save_context *save = &vbo_context(ctx)->save;
270
271    save->prims = save->prim_store->prims + save->prim_store->used;
272    save->buffer_map = save->vertex_store->buffer_map + save->vertex_store->used;
273
274    assert(save->buffer_map == save->buffer_ptr);
275
276    if (save->vertex_size)
277       save->max_vert = (save->vertex_store->bufferobj->Size / sizeof(float) - 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 = save->prim_store->size - save->prim_store->used;
285    save->dangling_attr_ref = GL_FALSE;
286 }
287
288 /**
289  * For a list of prims, try merging prims that can just be extensions of the
290  * previous prim.
291  */
292 static void
293 merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
294             GLuint *prim_count)
295 {
296    GLuint i;
297    struct _mesa_prim *prev_prim = prim_list;
298
299    for (i = 1; i < *prim_count; i++) {
300       struct _mesa_prim *this_prim = prim_list + i;
301
302       vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
303
304       if (vbo_merge_draws(ctx, true,
305                           prev_prim->mode, this_prim->mode,
306                           prev_prim->start, this_prim->start,
307                           &prev_prim->count, this_prim->count,
308                           prev_prim->basevertex, this_prim->basevertex,
309                           &prev_prim->end,
310                           this_prim->begin, this_prim->end)) {
311          /* We've found a prim that just extend the previous one.  Tack it
312           * onto the previous one, and let this primitive struct get dropped.
313           */
314          continue;
315       }
316
317       /* If any previous primitives have been dropped, then we need to copy
318        * this later one into the next available slot.
319        */
320       prev_prim++;
321       if (prev_prim != this_prim)
322          *prev_prim = *this_prim;
323    }
324
325    *prim_count = prev_prim - prim_list + 1;
326 }
327
328
329 /**
330  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
331  * don't have to worry about handling the _mesa_prim::begin/end flags.
332  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
333  */
334 static void
335 convert_line_loop_to_strip(struct vbo_save_context *save,
336                            struct vbo_save_vertex_list *node)
337 {
338    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
339
340    assert(prim->mode == GL_LINE_LOOP);
341
342    if (prim->end) {
343       /* Copy the 0th vertex to end of the buffer and extend the
344        * vertex count by one to finish the line loop.
345        */
346       const GLuint sz = save->vertex_size;
347       /* 0th vertex: */
348       const fi_type *src = save->buffer_map + prim->start * sz;
349       /* end of buffer: */
350       fi_type *dst = save->buffer_map + (prim->start + prim->count) * sz;
351
352       memcpy(dst, src, sz * sizeof(float));
353
354       prim->count++;
355       node->cold->vertex_count++;
356       save->vert_count++;
357       save->buffer_ptr += sz;
358       save->vertex_store->used += sz;
359    }
360
361    if (!prim->begin) {
362       /* Drawing the second or later section of a long line loop.
363        * Skip the 0th vertex.
364        */
365       prim->start++;
366       prim->count--;
367    }
368
369    prim->mode = GL_LINE_STRIP;
370 }
371
372
373 /* Compare the present vao if it has the same setup. */
374 static bool
375 compare_vao(gl_vertex_processing_mode mode,
376             const struct gl_vertex_array_object *vao,
377             const struct gl_buffer_object *bo, GLintptr buffer_offset,
378             GLuint stride, GLbitfield64 vao_enabled,
379             const GLubyte size[VBO_ATTRIB_MAX],
380             const GLenum16 type[VBO_ATTRIB_MAX],
381             const GLuint offset[VBO_ATTRIB_MAX])
382 {
383    if (!vao)
384       return false;
385
386    /* If the enabled arrays are not the same we are not equal. */
387    if (vao_enabled != vao->Enabled)
388       return false;
389
390    /* Check the buffer binding at 0 */
391    if (vao->BufferBinding[0].BufferObj != bo)
392       return false;
393    /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
394    if (vao->BufferBinding[0].Stride != stride)
395       return false;
396    assert(vao->BufferBinding[0].InstanceDivisor == 0);
397
398    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
399    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
400
401    /* Now check the enabled arrays */
402    GLbitfield mask = vao_enabled;
403    while (mask) {
404       const int attr = u_bit_scan(&mask);
405       const unsigned char vbo_attr = vao_to_vbo_map[attr];
406       const GLenum16 tp = type[vbo_attr];
407       const GLintptr off = offset[vbo_attr] + buffer_offset;
408       const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
409       if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
410          return false;
411       if (attrib->Format.Type != tp)
412          return false;
413       if (attrib->Format.Size != size[vbo_attr])
414          return false;
415       assert(attrib->Format.Format == GL_RGBA);
416       assert(attrib->Format.Normalized == GL_FALSE);
417       assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
418       assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
419       assert(attrib->BufferBindingIndex == 0);
420    }
421
422    return true;
423 }
424
425
426 /* Create or reuse the vao for the vertex processing mode. */
427 static void
428 update_vao(struct gl_context *ctx,
429            gl_vertex_processing_mode mode,
430            struct gl_vertex_array_object **vao,
431            struct gl_buffer_object *bo, GLintptr buffer_offset,
432            GLuint stride, GLbitfield64 vbo_enabled,
433            const GLubyte size[VBO_ATTRIB_MAX],
434            const GLenum16 type[VBO_ATTRIB_MAX],
435            const GLuint offset[VBO_ATTRIB_MAX])
436 {
437    /* Compute the bitmasks of vao_enabled arrays */
438    GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
439
440    /*
441     * Check if we can possibly reuse the exisiting one.
442     * In the long term we should reset them when something changes.
443     */
444    if (compare_vao(mode, *vao, bo, buffer_offset, stride,
445                    vao_enabled, size, type, offset))
446       return;
447
448    /* The initial refcount is 1 */
449    _mesa_reference_vao(ctx, vao, NULL);
450    *vao = _mesa_new_vao(ctx, ~((GLuint)0));
451
452    /*
453     * assert(stride <= ctx->Const.MaxVertexAttribStride);
454     * MaxVertexAttribStride is not set for drivers that does not
455     * expose GL 44 or GLES 31.
456     */
457
458    /* Bind the buffer object at binding point 0 */
459    _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
460                             false);
461
462    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
463     * Note that the position/generic0 aliasing is done in the VAO.
464     */
465    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
466    /* Now set the enable arrays */
467    GLbitfield mask = vao_enabled;
468    while (mask) {
469       const int vao_attr = u_bit_scan(&mask);
470       const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
471       assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
472
473       _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
474                              size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
475       _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
476    }
477    _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
478    assert(vao_enabled == (*vao)->Enabled);
479    assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
480
481    /* Finalize and freeze the VAO */
482    _mesa_set_vao_immutable(ctx, *vao);
483 }
484
485
486 static void
487 realloc_storage(struct gl_context *ctx, int prim_count, int vertex_count)
488 {
489    struct vbo_save_context *save = &vbo_context(ctx)->save;
490    if (vertex_count >= 0) {
491       /* Unmap old store:
492        */
493       vbo_save_unmap_vertex_store(ctx, save->vertex_store);
494
495       /* Release old reference:
496        */
497       free_vertex_store(ctx, save->vertex_store);
498       save->vertex_store = NULL;
499       /* When we have a new vbo, we will for sure need a new vao */
500       for (gl_vertex_processing_mode vpm = 0; vpm < VP_MODE_MAX; ++vpm)
501          _mesa_reference_vao(ctx, &save->VAO[vpm], NULL);
502
503       /* Allocate and map new store:
504        */
505       save->vertex_store = alloc_vertex_store(ctx, vertex_count);
506       save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
507       save->out_of_memory = save->buffer_ptr == NULL;
508    }
509
510    if (prim_count >= 0) {
511       if (--save->prim_store->refcount == 0) {
512          free(save->prim_store->prims);
513          free(save->prim_store);
514       }
515       save->prim_store = alloc_prim_store(prim_count);
516    }
517 }
518
519
520 /**
521  * Insert the active immediate struct onto the display list currently
522  * being built.
523  */
524 static void
525 compile_vertex_list(struct gl_context *ctx)
526 {
527    struct vbo_save_context *save = &vbo_context(ctx)->save;
528    struct vbo_save_vertex_list *node;
529
530    /* Allocate space for this structure in the display list currently
531     * being compiled.
532     */
533    node = (struct vbo_save_vertex_list *)
534       _mesa_dlist_alloc_vertex_list(ctx);
535
536    if (!node)
537       return;
538
539    memset(node, 0, sizeof(struct vbo_save_vertex_list));
540    node->cold = calloc(1, sizeof(*node->cold));
541
542    /* Make sure the pointer is aligned to the size of a pointer */
543    assert((GLintptr) node % sizeof(void *) == 0);
544
545    /* Duplicate our template, increment refcounts to the storage structs:
546     */
547    GLintptr old_offset = 0;
548    if (save->VAO[0]) {
549       old_offset = save->VAO[0]->BufferBinding[0].Offset
550          + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset;
551    }
552    const GLsizei stride = save->vertex_size*sizeof(GLfloat);
553    GLintptr buffer_offset =
554        (save->buffer_map - save->vertex_store->buffer_map) * sizeof(GLfloat);
555    assert(old_offset <= buffer_offset);
556    const GLintptr offset_diff = buffer_offset - old_offset;
557    GLuint start_offset = 0;
558    if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
559       /* The vertex size is an exact multiple of the buffer offset.
560        * This means that we can use zero-based vertex attribute pointers
561        * and specify the start of the primitive with the _mesa_prim::start
562        * field.  This results in issuing several draw calls with identical
563        * vertex attribute information.  This can result in fewer state
564        * changes in drivers.  In particular, the Gallium CSO module will
565        * filter out redundant vertex buffer changes.
566        */
567       /* We cannot immediately update the primitives as some methods below
568        * still need the uncorrected start vertices
569        */
570       start_offset = offset_diff/stride;
571       assert(old_offset == buffer_offset - offset_diff);
572       buffer_offset = old_offset;
573    }
574    GLuint offsets[VBO_ATTRIB_MAX];
575    for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
576       offsets[i] = offset;
577       offset += save->attrsz[i] * sizeof(GLfloat);
578    }
579    node->cold->vertex_count = save->vert_count;
580    node->cold->wrap_count = save->copied.nr;
581    node->cold->prims = save->prims;
582    node->cold->ib.obj = NULL;
583    node->cold->prim_count = save->prim_count;
584    node->cold->prim_store = save->prim_store;
585
586    /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
587     * Note that this may reuse the previous one of possible.
588     */
589    for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
590       /* create or reuse the vao */
591       update_vao(ctx, vpm, &save->VAO[vpm],
592                  save->vertex_store->bufferobj, buffer_offset, stride,
593                  save->enabled, save->attrsz, save->attrtype, offsets);
594       /* Reference the vao in the dlist */
595       node->VAO[vpm] = NULL;
596       _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
597    }
598
599    node->cold->prim_store->refcount++;
600
601    if (save->no_current_update) {
602       node->cold->current_data = NULL;
603    }
604    else {
605       GLuint current_size = save->vertex_size - save->attrsz[0];
606       node->cold->current_data = NULL;
607
608       if (current_size) {
609          node->cold->current_data = malloc(current_size * sizeof(GLfloat));
610          if (node->cold->current_data) {
611             const char *buffer = (const char *)save->buffer_map;
612             unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
613             unsigned vertex_offset = 0;
614
615             if (node->cold->vertex_count)
616                vertex_offset = (node->cold->vertex_count - 1) * stride;
617
618             memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
619                    current_size * sizeof(GLfloat));
620          } else {
621             _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
622          }
623       }
624    }
625
626    assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
627
628    if (save->dangling_attr_ref)
629       ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
630
631    save->vertex_store->used += save->vertex_size * node->cold->vertex_count;
632    save->prim_store->used += node->cold->prim_count;
633
634    /* Copy duplicated vertices
635     */
636    save->copied.nr = copy_vertices(ctx, node, save->buffer_map);
637
638    if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
639       convert_line_loop_to_strip(save, node);
640    }
641
642    merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
643
644    /* Correct the primitive starts, we can only do this here as copy_vertices
645     * and convert_line_loop_to_strip above consume the uncorrected starts.
646     * On the other hand the _vbo_loopback_vertex_list call below needs the
647     * primitves to be corrected already.
648     */
649    for (unsigned i = 0; i < node->cold->prim_count; i++) {
650       node->cold->prims[i].start += start_offset;
651    }
652
653    /* Create an index buffer. */
654    node->cold->min_index = node->cold->max_index = 0;
655    if (save->vert_count == 0 || save->prim_count == 0)
656       goto end;
657
658    /* We won't modify node->prims, so use a const alias to avoid unintended
659     * writes to it. */
660    const struct _mesa_prim *original_prims = node->cold->prims;
661
662    int end = original_prims[node->cold->prim_count - 1].start +
663              original_prims[node->cold->prim_count - 1].count;
664    int total_vert_count = end - original_prims[0].start;
665
666    node->cold->min_index = node->cold->prims[0].start;
667    node->cold->max_index = end - 1;
668
669    /* Estimate for the worst case: all prims are line strips (the +1 is because
670     * wrap_buffers may call use but the last primitive may not be complete) */
671    int max_indices_count = MAX2(total_vert_count * 2 - (node->cold->prim_count * 2) + 1,
672                                 total_vert_count);
673
674    int indices_offset = 0;
675    int available = save->previous_ib ? (save->previous_ib->Size / 4 - save->ib_first_free_index) : 0;
676    if (available >= max_indices_count) {
677       indices_offset = save->ib_first_free_index;
678    }
679    int size = max_indices_count * sizeof(uint32_t);
680    uint32_t* indices = (uint32_t*) malloc(size);
681    struct _mesa_prim *merged_prims = NULL;
682
683    int idx = 0;
684
685    int last_valid_prim = -1;
686    /* Construct indices array. */
687    for (unsigned i = 0; i < node->cold->prim_count; i++) {
688       assert(original_prims[i].basevertex == 0);
689       GLubyte mode = original_prims[i].mode;
690
691       int vertex_count = original_prims[i].count;
692       if (!vertex_count) {
693          continue;
694       }
695
696       /* Line strips may get converted to lines */
697       if (mode == GL_LINE_STRIP)
698          mode = GL_LINES;
699
700       /* If 2 consecutive prims use the same mode => merge them. */
701       bool merge_prims = last_valid_prim >= 0 &&
702                          mode == merged_prims[last_valid_prim].mode &&
703                          mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
704                          mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
705                          mode != GL_PATCHES;
706
707       /* To be able to merge consecutive triangle strips we need to insert
708        * a degenerate triangle.
709        */
710       if (merge_prims &&
711           mode == GL_TRIANGLE_STRIP) {
712          /* Insert a degenerate triangle */
713          assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
714          unsigned tri_count = merged_prims[last_valid_prim].count - 2;
715
716          indices[idx] = indices[idx - 1];
717          indices[idx + 1] = original_prims[i].start;
718          idx += 2;
719          merged_prims[last_valid_prim].count += 2;
720
721          if (tri_count % 2) {
722             /* Add another index to preserve winding order */
723             indices[idx++] = original_prims[i].start;
724             merged_prims[last_valid_prim].count++;
725          }
726       }
727
728       int start = idx;
729
730       /* Convert line strips to lines if it'll allow if the previous
731        * prim mode is GL_LINES (so merge_prims is true) or if the next
732        * primitive mode is GL_LINES or GL_LINE_LOOP.
733        */
734       if (original_prims[i].mode == GL_LINE_STRIP &&
735           (merge_prims ||
736            (i < node->cold->prim_count - 1 &&
737             (original_prims[i + 1].mode == GL_LINE_STRIP ||
738              original_prims[i + 1].mode == GL_LINES)))) {
739          for (unsigned j = 0; j < vertex_count; j++) {
740             indices[idx++] = original_prims[i].start + j;
741             /* Repeat all but the first/last indices. */
742             if (j && j != vertex_count - 1) {
743                indices[idx++] = original_prims[i].start + j;
744             }
745          }
746       } else {
747          /* We didn't convert to LINES, so restore the original mode */
748          mode = original_prims[i].mode;
749
750          for (unsigned j = 0; j < vertex_count; j++) {
751             indices[idx++] = original_prims[i].start + j;
752          }
753       }
754
755       if (merge_prims) {
756          /* Update vertex count. */
757          merged_prims[last_valid_prim].count += idx - start;
758       } else {
759          /* Keep this primitive */
760          last_valid_prim += 1;
761          assert(last_valid_prim <= i);
762          merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
763          merged_prims[last_valid_prim] = original_prims[i];
764          merged_prims[last_valid_prim].start = indices_offset + start;
765          merged_prims[last_valid_prim].count = idx - start;
766       }
767       merged_prims[last_valid_prim].mode = mode;
768    }
769
770    assert(idx > 0 && idx <= max_indices_count);
771
772    unsigned merged_prim_count = last_valid_prim + 1;
773    node->cold->ib.ptr = NULL;
774    node->cold->ib.count = idx;
775    node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
776
777    if (!indices_offset) {
778       /* Allocate a new index buffer */
779       _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
780       save->previous_ib = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
781       bool success = ctx->Driver.BufferData(ctx,
782                                          GL_ELEMENT_ARRAY_BUFFER_ARB,
783                                          MAX2(VBO_SAVE_INDEX_SIZE, idx) * sizeof(uint32_t),
784                                          NULL,
785                                          GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
786                                          save->previous_ib);
787       if (!success) {
788          _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
789          _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
790       }
791    }
792
793    _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->previous_ib);
794
795    if (node->cold->ib.obj) {
796       ctx->Driver.BufferSubData(ctx,
797                                 indices_offset * sizeof(uint32_t),
798                                 idx * sizeof(uint32_t),
799                                 indices,
800                                 node->cold->ib.obj);
801       save->ib_first_free_index = indices_offset + idx;
802    } else {
803       node->cold->vertex_count = 0;
804       node->cold->prim_count = 0;
805    }
806
807    /* Prepare for DrawGallium */
808    memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
809    /* The other info fields will be updated in vbo_save_playback_vertex_list */
810    node->merged.info.index_size = 4;
811    node->merged.info.instance_count = 1;
812    node->merged.info.index.gl_bo = node->cold->ib.obj;
813    if (merged_prim_count == 1) {
814       node->merged.info.mode = merged_prims[0].mode;
815       node->merged.start_count.start = merged_prims[0].start;
816       node->merged.start_count.count = merged_prims[0].count;
817       node->merged.start_count.index_bias = 0;
818       node->merged.mode = NULL;
819    } else {
820       node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
821       node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
822       for (unsigned i = 0; i < merged_prim_count; i++) {
823          node->merged.start_counts[i].start = merged_prims[i].start;
824          node->merged.start_counts[i].count = merged_prims[i].count;
825          node->merged.start_counts[i].index_bias = 0;
826          node->merged.mode[i] = merged_prims[i].mode;
827       }
828    }
829    node->merged.num_draws = merged_prim_count;
830    if (node->merged.num_draws > 1) {
831       bool same_mode = true;
832       for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
833          same_mode = node->merged.mode[i] == node->merged.mode[0];
834       }
835       if (same_mode) {
836          /* All primitives use the same mode, so we can simplify a bit */
837          node->merged.info.mode = node->merged.mode[0];
838          free(node->merged.mode);
839          node->merged.mode = NULL;
840       }
841    }
842
843    free(indices);
844    free(merged_prims);
845
846 end:
847    /* Deal with GL_COMPILE_AND_EXECUTE:
848     */
849    if (ctx->ExecuteFlag) {
850       struct _glapi_table *dispatch = GET_DISPATCH();
851
852       _glapi_set_dispatch(ctx->Exec);
853
854       /* Note that the range of referenced vertices must be mapped already */
855       _vbo_loopback_vertex_list(ctx, node);
856
857       _glapi_set_dispatch(dispatch);
858    }
859
860    /* Decide whether the storage structs are full, or can be used for
861     * the next vertex lists as well.
862     */
863    if (save->vertex_store->used >
864        save->vertex_store->bufferobj->Size / sizeof(float) - 16 * (save->vertex_size + 4)) {
865       realloc_storage(ctx, -1, 0);
866    }
867    else {
868       /* update buffer_ptr for next vertex */
869       save->buffer_ptr = save->vertex_store->buffer_map
870          + save->vertex_store->used;
871    }
872
873    if (save->prim_store->used > save->prim_store->size - 6) {
874       realloc_storage(ctx, 0, -1);
875    }
876
877    /* Reset our structures for the next run of vertices:
878     */
879    reset_counters(ctx);
880 }
881
882
883 /**
884  * This is called when we fill a vertex buffer before we hit a glEnd().
885  * We
886  * TODO -- If no new vertices have been stored, don't bother saving it.
887  */
888 static void
889 wrap_buffers(struct gl_context *ctx)
890 {
891    struct vbo_save_context *save = &vbo_context(ctx)->save;
892    GLint i = save->prim_count - 1;
893    GLenum mode;
894
895    assert(i < (GLint) save->prim_max);
896    assert(i >= 0);
897
898    /* Close off in-progress primitive.
899     */
900    save->prims[i].count = (save->vert_count - save->prims[i].start);
901    mode = save->prims[i].mode;
902
903    /* store the copied vertices, and allocate a new list.
904     */
905    compile_vertex_list(ctx);
906
907    /* Restart interrupted primitive
908     */
909    save->prims[0].mode = mode;
910    save->prims[0].begin = 0;
911    save->prims[0].end = 0;
912    save->prims[0].start = 0;
913    save->prims[0].count = 0;
914    save->prim_count = 1;
915 }
916
917
918 /**
919  * Called only when buffers are wrapped as the result of filling the
920  * vertex_store struct.
921  */
922 static void
923 wrap_filled_vertex(struct gl_context *ctx)
924 {
925    struct vbo_save_context *save = &vbo_context(ctx)->save;
926    unsigned numComponents;
927
928    /* Emit a glEnd to close off the last vertex list.
929     */
930    wrap_buffers(ctx);
931
932    /* Copy stored stored vertices to start of new list.
933     */
934    assert(save->max_vert - save->vert_count > save->copied.nr);
935
936    numComponents = save->copied.nr * save->vertex_size;
937    memcpy(save->buffer_ptr,
938           save->copied.buffer,
939           numComponents * sizeof(fi_type));
940    save->buffer_ptr += numComponents;
941    save->vert_count += save->copied.nr;
942 }
943
944
945 static void
946 copy_to_current(struct gl_context *ctx)
947 {
948    struct vbo_save_context *save = &vbo_context(ctx)->save;
949    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
950
951    while (enabled) {
952       const int i = u_bit_scan64(&enabled);
953       assert(save->attrsz[i]);
954
955       if (save->attrtype[i] == GL_DOUBLE ||
956           save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
957          memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
958       else
959          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
960                                      save->attrptr[i], save->attrtype[i]);
961    }
962 }
963
964
965 static void
966 copy_from_current(struct gl_context *ctx)
967 {
968    struct vbo_save_context *save = &vbo_context(ctx)->save;
969    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
970
971    while (enabled) {
972       const int i = u_bit_scan64(&enabled);
973
974       switch (save->attrsz[i]) {
975       case 4:
976          save->attrptr[i][3] = save->current[i][3];
977          FALLTHROUGH;
978       case 3:
979          save->attrptr[i][2] = save->current[i][2];
980          FALLTHROUGH;
981       case 2:
982          save->attrptr[i][1] = save->current[i][1];
983          FALLTHROUGH;
984       case 1:
985          save->attrptr[i][0] = save->current[i][0];
986          break;
987       case 0:
988          unreachable("Unexpected vertex attribute size");
989       }
990    }
991 }
992
993
994 /**
995  * Called when we increase the size of a vertex attribute.  For example,
996  * if we've seen one or more glTexCoord2f() calls and now we get a
997  * glTexCoord3f() call.
998  * Flush existing data, set new attrib size, replay copied vertices.
999  */
1000 static void
1001 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1002 {
1003    struct vbo_save_context *save = &vbo_context(ctx)->save;
1004    GLuint oldsz;
1005    GLuint i;
1006    fi_type *tmp;
1007
1008    /* Store the current run of vertices, and emit a GL_END.  Emit a
1009     * BEGIN in the new buffer.
1010     */
1011    if (save->vert_count)
1012       wrap_buffers(ctx);
1013    else
1014       assert(save->copied.nr == 0);
1015
1016    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1017     * when the attribute already exists in the vertex and is having
1018     * its size increased.
1019     */
1020    copy_to_current(ctx);
1021
1022    /* Fix up sizes:
1023     */
1024    oldsz = save->attrsz[attr];
1025    save->attrsz[attr] = newsz;
1026    save->enabled |= BITFIELD64_BIT(attr);
1027
1028    save->vertex_size += newsz - oldsz;
1029    save->max_vert = ((save->vertex_store->bufferobj->Size / sizeof(float) -
1030                       save->vertex_store->used) /
1031                      save->vertex_size);
1032    save->vert_count = 0;
1033
1034    /* Recalculate all the attrptr[] values:
1035     */
1036    tmp = save->vertex;
1037    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1038       if (save->attrsz[i]) {
1039          save->attrptr[i] = tmp;
1040          tmp += save->attrsz[i];
1041       }
1042       else {
1043          save->attrptr[i] = NULL;       /* will not be dereferenced. */
1044       }
1045    }
1046
1047    /* Copy from current to repopulate the vertex with correct values.
1048     */
1049    copy_from_current(ctx);
1050
1051    /* Replay stored vertices to translate them to new format here.
1052     *
1053     * If there are copied vertices and the new (upgraded) attribute
1054     * has not been defined before, this list is somewhat degenerate,
1055     * and will need fixup at runtime.
1056     */
1057    if (save->copied.nr) {
1058       const fi_type *data = save->copied.buffer;
1059       fi_type *dest = save->buffer_map;
1060
1061       /* Need to note this and fix up at runtime (or loopback):
1062        */
1063       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1064          assert(oldsz == 0);
1065          save->dangling_attr_ref = GL_TRUE;
1066       }
1067
1068       for (i = 0; i < save->copied.nr; i++) {
1069          GLbitfield64 enabled = save->enabled;
1070          while (enabled) {
1071             const int j = u_bit_scan64(&enabled);
1072             assert(save->attrsz[j]);
1073             if (j == attr) {
1074                if (oldsz) {
1075                   COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
1076                                               save->attrtype[j]);
1077                   data += oldsz;
1078                   dest += newsz;
1079                }
1080                else {
1081                   COPY_SZ_4V(dest, newsz, save->current[attr]);
1082                   dest += newsz;
1083                }
1084             }
1085             else {
1086                GLint sz = save->attrsz[j];
1087                COPY_SZ_4V(dest, sz, data);
1088                data += sz;
1089                dest += sz;
1090             }
1091          }
1092       }
1093
1094       save->buffer_ptr = dest;
1095       save->vert_count += save->copied.nr;
1096    }
1097 }
1098
1099
1100 /**
1101  * This is called when the size of a vertex attribute changes.
1102  * For example, after seeing one or more glTexCoord2f() calls we
1103  * get a glTexCoord4f() or glTexCoord1f() call.
1104  */
1105 static void
1106 fixup_vertex(struct gl_context *ctx, GLuint attr,
1107              GLuint sz, GLenum newType)
1108 {
1109    struct vbo_save_context *save = &vbo_context(ctx)->save;
1110
1111    if (sz > save->attrsz[attr] ||
1112        newType != save->attrtype[attr]) {
1113       /* New size is larger.  Need to flush existing vertices and get
1114        * an enlarged vertex format.
1115        */
1116       upgrade_vertex(ctx, attr, sz);
1117    }
1118    else if (sz < save->active_sz[attr]) {
1119       GLuint i;
1120       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1121
1122       /* New size is equal or smaller - just need to fill in some
1123        * zeros.
1124        */
1125       for (i = sz; i <= save->attrsz[attr]; i++)
1126          save->attrptr[attr][i - 1] = id[i - 1];
1127    }
1128
1129    save->active_sz[attr] = sz;
1130 }
1131
1132
1133 /**
1134  * Reset the current size of all vertex attributes to the default
1135  * value of 0.  This signals that we haven't yet seen any per-vertex
1136  * commands such as glNormal3f() or glTexCoord2f().
1137  */
1138 static void
1139 reset_vertex(struct gl_context *ctx)
1140 {
1141    struct vbo_save_context *save = &vbo_context(ctx)->save;
1142
1143    while (save->enabled) {
1144       const int i = u_bit_scan64(&save->enabled);
1145       assert(save->attrsz[i]);
1146       save->attrsz[i] = 0;
1147       save->active_sz[i] = 0;
1148    }
1149
1150    save->vertex_size = 0;
1151 }
1152
1153
1154 /**
1155  * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1156  * It depends on a few things, including whether we're inside or outside
1157  * of glBegin/glEnd.
1158  */
1159 static inline bool
1160 is_vertex_position(const struct gl_context *ctx, GLuint index)
1161 {
1162    return (index == 0 &&
1163            _mesa_attr_zero_aliases_vertex(ctx) &&
1164            _mesa_inside_dlist_begin_end(ctx));
1165 }
1166
1167
1168
1169 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
1170
1171
1172 /* Only one size for each attribute may be active at once.  Eg. if
1173  * Color3f is installed/active, then Color4f may not be, even if the
1174  * vertex actually contains 4 color coordinates.  This is because the
1175  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1176  * of the chooser function when switching between Color4f and Color3f.
1177  */
1178 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
1179 do {                                                            \
1180    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
1181    int sz = (sizeof(C) / sizeof(GLfloat));                      \
1182                                                                 \
1183    if (save->active_sz[A] != N)                                 \
1184       fixup_vertex(ctx, A, N * sz, T);                          \
1185                                                                 \
1186    {                                                            \
1187       C *dest = (C *)save->attrptr[A];                          \
1188       if (N>0) dest[0] = V0;                                    \
1189       if (N>1) dest[1] = V1;                                    \
1190       if (N>2) dest[2] = V2;                                    \
1191       if (N>3) dest[3] = V3;                                    \
1192       save->attrtype[A] = T;                                    \
1193    }                                                            \
1194                                                                 \
1195    if ((A) == 0) {                                              \
1196       GLuint i;                                                 \
1197                                                                 \
1198       for (i = 0; i < save->vertex_size; i++)                   \
1199          save->buffer_ptr[i] = save->vertex[i];                 \
1200                                                                 \
1201       save->buffer_ptr += save->vertex_size;                    \
1202                                                                 \
1203       if (++save->vert_count >= save->max_vert)                 \
1204          wrap_filled_vertex(ctx);                               \
1205    }                                                            \
1206 } while (0)
1207
1208 #define TAG(x) _save_##x
1209
1210 #include "vbo_attrib_tmp.h"
1211
1212
1213
1214 #define MAT( ATTR, N, face, params )                    \
1215 do {                                                    \
1216    if (face != GL_BACK)                                 \
1217       MAT_ATTR( ATTR, N, params ); /* front */          \
1218    if (face != GL_FRONT)                                \
1219       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
1220 } while (0)
1221
1222
1223 /**
1224  * Save a glMaterial call found between glBegin/End.
1225  * glMaterial calls outside Begin/End are handled in dlist.c.
1226  */
1227 static void GLAPIENTRY
1228 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1229 {
1230    GET_CURRENT_CONTEXT(ctx);
1231
1232    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1233       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1234       return;
1235    }
1236
1237    switch (pname) {
1238    case GL_EMISSION:
1239       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1240       break;
1241    case GL_AMBIENT:
1242       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1243       break;
1244    case GL_DIFFUSE:
1245       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1246       break;
1247    case GL_SPECULAR:
1248       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1249       break;
1250    case GL_SHININESS:
1251       if (*params < 0 || *params > ctx->Const.MaxShininess) {
1252          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1253       }
1254       else {
1255          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1256       }
1257       break;
1258    case GL_COLOR_INDEXES:
1259       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1260       break;
1261    case GL_AMBIENT_AND_DIFFUSE:
1262       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1263       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1264       break;
1265    default:
1266       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1267       return;
1268    }
1269 }
1270
1271
1272 /* Cope with EvalCoord/CallList called within a begin/end object:
1273  *     -- Flush current buffer
1274  *     -- Fallback to opcodes for the rest of the begin/end object.
1275  */
1276 static void
1277 dlist_fallback(struct gl_context *ctx)
1278 {
1279    struct vbo_save_context *save = &vbo_context(ctx)->save;
1280
1281    if (save->vert_count || save->prim_count) {
1282       if (save->prim_count > 0) {
1283          /* Close off in-progress primitive. */
1284          GLint i = save->prim_count - 1;
1285          save->prims[i].count = save->vert_count - save->prims[i].start;
1286       }
1287
1288       /* Need to replay this display list with loopback,
1289        * unfortunately, otherwise this primitive won't be handled
1290        * properly:
1291        */
1292       save->dangling_attr_ref = GL_TRUE;
1293
1294       compile_vertex_list(ctx);
1295    }
1296
1297    copy_to_current(ctx);
1298    reset_vertex(ctx);
1299    reset_counters(ctx);
1300    if (save->out_of_memory) {
1301       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1302    }
1303    else {
1304       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1305    }
1306    ctx->Driver.SaveNeedFlush = GL_FALSE;
1307 }
1308
1309
1310 static void GLAPIENTRY
1311 _save_EvalCoord1f(GLfloat u)
1312 {
1313    GET_CURRENT_CONTEXT(ctx);
1314    dlist_fallback(ctx);
1315    CALL_EvalCoord1f(ctx->Save, (u));
1316 }
1317
1318 static void GLAPIENTRY
1319 _save_EvalCoord1fv(const GLfloat * v)
1320 {
1321    GET_CURRENT_CONTEXT(ctx);
1322    dlist_fallback(ctx);
1323    CALL_EvalCoord1fv(ctx->Save, (v));
1324 }
1325
1326 static void GLAPIENTRY
1327 _save_EvalCoord2f(GLfloat u, GLfloat v)
1328 {
1329    GET_CURRENT_CONTEXT(ctx);
1330    dlist_fallback(ctx);
1331    CALL_EvalCoord2f(ctx->Save, (u, v));
1332 }
1333
1334 static void GLAPIENTRY
1335 _save_EvalCoord2fv(const GLfloat * v)
1336 {
1337    GET_CURRENT_CONTEXT(ctx);
1338    dlist_fallback(ctx);
1339    CALL_EvalCoord2fv(ctx->Save, (v));
1340 }
1341
1342 static void GLAPIENTRY
1343 _save_EvalPoint1(GLint i)
1344 {
1345    GET_CURRENT_CONTEXT(ctx);
1346    dlist_fallback(ctx);
1347    CALL_EvalPoint1(ctx->Save, (i));
1348 }
1349
1350 static void GLAPIENTRY
1351 _save_EvalPoint2(GLint i, GLint j)
1352 {
1353    GET_CURRENT_CONTEXT(ctx);
1354    dlist_fallback(ctx);
1355    CALL_EvalPoint2(ctx->Save, (i, j));
1356 }
1357
1358 static void GLAPIENTRY
1359 _save_CallList(GLuint l)
1360 {
1361    GET_CURRENT_CONTEXT(ctx);
1362    dlist_fallback(ctx);
1363    CALL_CallList(ctx->Save, (l));
1364 }
1365
1366 static void GLAPIENTRY
1367 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1368 {
1369    GET_CURRENT_CONTEXT(ctx);
1370    dlist_fallback(ctx);
1371    CALL_CallLists(ctx->Save, (n, type, v));
1372 }
1373
1374
1375
1376 /**
1377  * Called when a glBegin is getting compiled into a display list.
1378  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1379  */
1380 void
1381 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1382                      bool no_current_update)
1383 {
1384    struct vbo_save_context *save = &vbo_context(ctx)->save;
1385    const GLuint i = save->prim_count++;
1386
1387    ctx->Driver.CurrentSavePrimitive = mode;
1388
1389    assert(i < save->prim_max);
1390    save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1391    save->prims[i].begin = 1;
1392    save->prims[i].end = 0;
1393    save->prims[i].start = save->vert_count;
1394    save->prims[i].count = 0;
1395
1396    save->no_current_update = no_current_update;
1397
1398    if (save->out_of_memory) {
1399       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1400    }
1401    else {
1402       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1403    }
1404
1405    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1406    ctx->Driver.SaveNeedFlush = GL_TRUE;
1407 }
1408
1409
1410 static void GLAPIENTRY
1411 _save_End(void)
1412 {
1413    GET_CURRENT_CONTEXT(ctx);
1414    struct vbo_save_context *save = &vbo_context(ctx)->save;
1415    const GLint i = save->prim_count - 1;
1416
1417    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1418    save->prims[i].end = 1;
1419    save->prims[i].count = (save->vert_count - save->prims[i].start);
1420
1421    if (i == (GLint) save->prim_max - 1) {
1422       compile_vertex_list(ctx);
1423       assert(save->copied.nr == 0);
1424    }
1425
1426    /* Swap out this vertex format while outside begin/end.  Any color,
1427     * etc. received between here and the next begin will be compiled
1428     * as opcodes.
1429     */
1430    if (save->out_of_memory) {
1431       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1432    }
1433    else {
1434       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1435    }
1436 }
1437
1438
1439 static void GLAPIENTRY
1440 _save_Begin(GLenum mode)
1441 {
1442    GET_CURRENT_CONTEXT(ctx);
1443    (void) mode;
1444    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1445 }
1446
1447
1448 static void GLAPIENTRY
1449 _save_PrimitiveRestartNV(void)
1450 {
1451    GET_CURRENT_CONTEXT(ctx);
1452    struct vbo_save_context *save = &vbo_context(ctx)->save;
1453
1454    if (save->prim_count == 0) {
1455       /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1456        * is an error.
1457        */
1458       _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1459                           "glPrimitiveRestartNV called outside glBegin/End");
1460    } else {
1461       /* get current primitive mode */
1462       GLenum curPrim = save->prims[save->prim_count - 1].mode;
1463       bool no_current_update = save->no_current_update;
1464
1465       /* restart primitive */
1466       CALL_End(ctx->CurrentServerDispatch, ());
1467       vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1468    }
1469 }
1470
1471
1472 /* Unlike the functions above, these are to be hooked into the vtxfmt
1473  * maintained in ctx->ListState, active when the list is known or
1474  * suspected to be outside any begin/end primitive.
1475  * Note: OBE = Outside Begin/End
1476  */
1477 static void GLAPIENTRY
1478 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1479 {
1480    GET_CURRENT_CONTEXT(ctx);
1481    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1482
1483    vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1484    CALL_Vertex2f(dispatch, (x1, y1));
1485    CALL_Vertex2f(dispatch, (x2, y1));
1486    CALL_Vertex2f(dispatch, (x2, y2));
1487    CALL_Vertex2f(dispatch, (x1, y2));
1488    CALL_End(dispatch, ());
1489 }
1490
1491
1492 static void GLAPIENTRY
1493 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1494 {
1495    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1496 }
1497
1498 static void GLAPIENTRY
1499 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1500 {
1501    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1502 }
1503
1504 static void GLAPIENTRY
1505 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1506 {
1507    _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1508 }
1509
1510 static void GLAPIENTRY
1511 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1512 {
1513    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1514 }
1515
1516 static void GLAPIENTRY
1517 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1518 {
1519    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1520 }
1521
1522 static void GLAPIENTRY
1523 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1524 {
1525    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1526 }
1527
1528 static void GLAPIENTRY
1529 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1530 {
1531    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1532 }
1533
1534 static void
1535 _ensure_draws_fits_in_storage(struct gl_context *ctx, int primcount, int vertcount)
1536 {
1537    struct vbo_save_context *save = &vbo_context(ctx)->save;
1538
1539    bool realloc_prim = save->prim_count + primcount > save->prim_max;
1540    bool realloc_vert = save->vertex_size && (save->vert_count + vertcount >= save->max_vert);
1541
1542    if (realloc_prim || realloc_vert) {
1543       if (save->vert_count || save->prim_count)
1544          compile_vertex_list(ctx);
1545       realloc_storage(ctx, realloc_prim ? primcount : -1, realloc_vert ? vertcount : -1);
1546       reset_counters(ctx);
1547       assert(save->prim_max);
1548    }
1549 }
1550
1551
1552 static void GLAPIENTRY
1553 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1554 {
1555    GET_CURRENT_CONTEXT(ctx);
1556    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1557    struct vbo_save_context *save = &vbo_context(ctx)->save;
1558    GLint i;
1559
1560    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1561       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1562       return;
1563    }
1564    if (count < 0) {
1565       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1566       return;
1567    }
1568
1569    if (save->out_of_memory)
1570       return;
1571
1572    _ensure_draws_fits_in_storage(ctx, 1, count);
1573
1574    /* Make sure to process any VBO binding changes */
1575    _mesa_update_state(ctx);
1576
1577    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1578
1579    vbo_save_NotifyBegin(ctx, mode, true);
1580
1581    for (i = 0; i < count; i++)
1582       _mesa_array_element(ctx, start + i);
1583    CALL_End(ctx->CurrentServerDispatch, ());
1584
1585    _mesa_vao_unmap_arrays(ctx, vao);
1586 }
1587
1588
1589 static void GLAPIENTRY
1590 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1591                           const GLsizei *count, GLsizei primcount)
1592 {
1593    GET_CURRENT_CONTEXT(ctx);
1594    GLint i;
1595
1596    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1597       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1598       return;
1599    }
1600
1601    if (primcount < 0) {
1602       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1603                           "glMultiDrawArrays(primcount<0)");
1604       return;
1605    }
1606
1607    unsigned vertcount = 0;
1608    for (i = 0; i < primcount; i++) {
1609       if (count[i] < 0) {
1610          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1611                              "glMultiDrawArrays(count[i]<0)");
1612          return;
1613       }
1614       vertcount += count[i];
1615    }
1616
1617    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1618
1619    for (i = 0; i < primcount; i++) {
1620       if (count[i] > 0) {
1621          _save_OBE_DrawArrays(mode, first[i], count[i]);
1622       }
1623    }
1624 }
1625
1626
1627 static void
1628 array_element(struct gl_context *ctx,
1629               GLint basevertex, GLuint elt, unsigned index_size_shift)
1630 {
1631    /* Section 10.3.5 Primitive Restart:
1632     * [...]
1633     *    When one of the *BaseVertex drawing commands specified in section 10.5
1634     * is used, the primitive restart comparison occurs before the basevertex
1635     * offset is added to the array index.
1636     */
1637    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1638     * then we call PrimitiveRestartNV and return.
1639     */
1640    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1641        elt == ctx->Array._RestartIndex[index_size_shift]) {
1642       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1643       return;
1644    }
1645
1646    _mesa_array_element(ctx, basevertex + elt);
1647 }
1648
1649
1650 /* Could do better by copying the arrays and element list intact and
1651  * then emitting an indexed prim at runtime.
1652  */
1653 static void GLAPIENTRY
1654 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1655                                  const GLvoid * indices, GLint basevertex)
1656 {
1657    GET_CURRENT_CONTEXT(ctx);
1658    struct vbo_save_context *save = &vbo_context(ctx)->save;
1659    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1660    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1661    GLint i;
1662
1663    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1664       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1665       return;
1666    }
1667    if (count < 0) {
1668       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1669       return;
1670    }
1671    if (type != GL_UNSIGNED_BYTE &&
1672        type != GL_UNSIGNED_SHORT &&
1673        type != GL_UNSIGNED_INT) {
1674       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1675       return;
1676    }
1677
1678    if (save->out_of_memory)
1679       return;
1680
1681    _ensure_draws_fits_in_storage(ctx, 1, count);
1682
1683    /* Make sure to process any VBO binding changes */
1684    _mesa_update_state(ctx);
1685
1686    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1687
1688    if (indexbuf)
1689       indices =
1690          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1691
1692    vbo_save_NotifyBegin(ctx, mode, true);
1693
1694    switch (type) {
1695    case GL_UNSIGNED_BYTE:
1696       for (i = 0; i < count; i++)
1697          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1698       break;
1699    case GL_UNSIGNED_SHORT:
1700       for (i = 0; i < count; i++)
1701          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1702       break;
1703    case GL_UNSIGNED_INT:
1704       for (i = 0; i < count; i++)
1705          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1706       break;
1707    default:
1708       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1709       break;
1710    }
1711
1712    CALL_End(ctx->CurrentServerDispatch, ());
1713
1714    _mesa_vao_unmap(ctx, vao);
1715 }
1716
1717 static void GLAPIENTRY
1718 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1719                        const GLvoid * indices)
1720 {
1721    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1722 }
1723
1724
1725 static void GLAPIENTRY
1726 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1727                             GLsizei count, GLenum type,
1728                             const GLvoid * indices)
1729 {
1730    GET_CURRENT_CONTEXT(ctx);
1731    struct vbo_save_context *save = &vbo_context(ctx)->save;
1732
1733    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1734       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1735       return;
1736    }
1737    if (count < 0) {
1738       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1739                           "glDrawRangeElements(count<0)");
1740       return;
1741    }
1742    if (type != GL_UNSIGNED_BYTE &&
1743        type != GL_UNSIGNED_SHORT &&
1744        type != GL_UNSIGNED_INT) {
1745       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1746       return;
1747    }
1748    if (end < start) {
1749       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1750                           "glDrawRangeElements(end < start)");
1751       return;
1752    }
1753
1754    if (save->out_of_memory)
1755       return;
1756
1757    _save_OBE_DrawElements(mode, count, type, indices);
1758 }
1759
1760
1761 static void GLAPIENTRY
1762 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1763                             const GLvoid * const *indices, GLsizei primcount)
1764 {
1765    GET_CURRENT_CONTEXT(ctx);
1766    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1767    GLsizei i;
1768
1769    int vertcount = 0;
1770    for (i = 0; i < primcount; i++) {
1771       vertcount += count[i];
1772    }
1773    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1774
1775    for (i = 0; i < primcount; i++) {
1776       if (count[i] > 0) {
1777          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1778       }
1779    }
1780 }
1781
1782
1783 static void GLAPIENTRY
1784 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1785                                       GLenum type,
1786                                       const GLvoid * const *indices,
1787                                       GLsizei primcount,
1788                                       const GLint *basevertex)
1789 {
1790    GET_CURRENT_CONTEXT(ctx);
1791    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1792    GLsizei i;
1793
1794    int vertcount = 0;
1795    for (i = 0; i < primcount; i++) {
1796       vertcount += count[i];
1797    }
1798    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1799
1800    for (i = 0; i < primcount; i++) {
1801       if (count[i] > 0) {
1802          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1803                                                       indices[i],
1804                                                       basevertex[i]));
1805       }
1806    }
1807 }
1808
1809
1810 static void
1811 vtxfmt_init(struct gl_context *ctx)
1812 {
1813    struct vbo_save_context *save = &vbo_context(ctx)->save;
1814    GLvertexformat *vfmt = &save->vtxfmt;
1815
1816 #define NAME_AE(x) _ae_##x
1817 #define NAME_CALLLIST(x) _save_##x
1818 #define NAME(x) _save_##x
1819 #define NAME_ES(x) _save_##x##ARB
1820
1821 #include "vbo_init_tmp.h"
1822 }
1823
1824
1825 /**
1826  * Initialize the dispatch table with the VBO functions for display
1827  * list compilation.
1828  */
1829 void
1830 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1831                              struct _glapi_table *exec)
1832 {
1833    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1834    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1835    SET_DrawElements(exec, _save_OBE_DrawElements);
1836    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1837    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1838    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1839    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1840    SET_Rectf(exec, _save_OBE_Rectf);
1841    SET_Rectd(exec, _save_OBE_Rectd);
1842    SET_Rectdv(exec, _save_OBE_Rectdv);
1843    SET_Rectfv(exec, _save_OBE_Rectfv);
1844    SET_Recti(exec, _save_OBE_Recti);
1845    SET_Rectiv(exec, _save_OBE_Rectiv);
1846    SET_Rects(exec, _save_OBE_Rects);
1847    SET_Rectsv(exec, _save_OBE_Rectsv);
1848
1849    /* Note: other glDraw functins aren't compiled into display lists */
1850 }
1851
1852
1853
1854 void
1855 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1856 {
1857    struct vbo_save_context *save = &vbo_context(ctx)->save;
1858
1859    /* Noop when we are actually active:
1860     */
1861    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1862       return;
1863
1864    if (save->vert_count || save->prim_count)
1865       compile_vertex_list(ctx);
1866
1867    copy_to_current(ctx);
1868    reset_vertex(ctx);
1869    reset_counters(ctx);
1870    ctx->Driver.SaveNeedFlush = GL_FALSE;
1871 }
1872
1873
1874 /**
1875  * Called from glNewList when we're starting to compile a display list.
1876  */
1877 void
1878 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1879 {
1880    struct vbo_save_context *save = &vbo_context(ctx)->save;
1881
1882    (void) list;
1883    (void) mode;
1884
1885    if (!save->prim_store)
1886       save->prim_store = alloc_prim_store(0);
1887
1888    if (!save->vertex_store)
1889       save->vertex_store = alloc_vertex_store(ctx, 0);
1890
1891    save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1892
1893    reset_vertex(ctx);
1894    reset_counters(ctx);
1895    ctx->Driver.SaveNeedFlush = GL_FALSE;
1896 }
1897
1898
1899 /**
1900  * Called from glEndList when we're finished compiling a display list.
1901  */
1902 void
1903 vbo_save_EndList(struct gl_context *ctx)
1904 {
1905    struct vbo_save_context *save = &vbo_context(ctx)->save;
1906
1907    /* EndList called inside a (saved) Begin/End pair?
1908     */
1909    if (_mesa_inside_dlist_begin_end(ctx)) {
1910       if (save->prim_count > 0) {
1911          GLint i = save->prim_count - 1;
1912          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1913          save->prims[i].end = 0;
1914          save->prims[i].count = save->vert_count - save->prims[i].start;
1915       }
1916
1917       /* Make sure this vertex list gets replayed by the "loopback"
1918        * mechanism:
1919        */
1920       save->dangling_attr_ref = GL_TRUE;
1921       vbo_save_SaveFlushVertices(ctx);
1922
1923       /* Swap out this vertex format while outside begin/end.  Any color,
1924        * etc. received between here and the next begin will be compiled
1925        * as opcodes.
1926        */
1927       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1928    }
1929
1930    vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1931
1932    assert(save->vertex_size == 0);
1933 }
1934
1935
1936 /**
1937  * Called from the display list code when we're about to execute a
1938  * display list.
1939  */
1940 void
1941 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1942 {
1943    struct vbo_save_context *save = &vbo_context(ctx)->save;
1944    save->replay_flags |= dlist->Flags;
1945 }
1946
1947
1948 /**
1949  * Called from the display list code when we're finished executing a
1950  * display list.
1951  */
1952 void
1953 vbo_save_EndCallList(struct gl_context *ctx)
1954 {
1955    struct vbo_save_context *save = &vbo_context(ctx)->save;
1956
1957    if (ctx->ListState.CallDepth == 1)
1958       save->replay_flags = 0;
1959 }
1960
1961
1962 /**
1963  * Called during context creation/init.
1964  */
1965 static void
1966 current_init(struct gl_context *ctx)
1967 {
1968    struct vbo_save_context *save = &vbo_context(ctx)->save;
1969    GLint i;
1970
1971    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1972       const GLuint j = i - VBO_ATTRIB_POS;
1973       assert(j < VERT_ATTRIB_MAX);
1974       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1975       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1976    }
1977
1978    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1979       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1980       assert(j < MAT_ATTRIB_MAX);
1981       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1982       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1983    }
1984 }
1985
1986
1987 /**
1988  * Initialize the display list compiler.  Called during context creation.
1989  */
1990 void
1991 vbo_save_api_init(struct vbo_save_context *save)
1992 {
1993    struct gl_context *ctx = gl_context_from_vbo_save(save);
1994
1995    vtxfmt_init(ctx);
1996    current_init(ctx);
1997    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop);
1998 }