vbo/dlist: use DrawGallium(Complex)
[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->prims[node->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->prims[node->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->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
541    /* Make sure the pointer is aligned to the size of a pointer */
542    assert((GLintptr) node % sizeof(void *) == 0);
543
544    /* Duplicate our template, increment refcounts to the storage structs:
545     */
546    GLintptr old_offset = 0;
547    if (save->VAO[0]) {
548       old_offset = save->VAO[0]->BufferBinding[0].Offset
549          + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset;
550    }
551    const GLsizei stride = save->vertex_size*sizeof(GLfloat);
552    GLintptr buffer_offset =
553        (save->buffer_map - save->vertex_store->buffer_map) * sizeof(GLfloat);
554    assert(old_offset <= buffer_offset);
555    const GLintptr offset_diff = buffer_offset - old_offset;
556    GLuint start_offset = 0;
557    if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
558       /* The vertex size is an exact multiple of the buffer offset.
559        * This means that we can use zero-based vertex attribute pointers
560        * and specify the start of the primitive with the _mesa_prim::start
561        * field.  This results in issuing several draw calls with identical
562        * vertex attribute information.  This can result in fewer state
563        * changes in drivers.  In particular, the Gallium CSO module will
564        * filter out redundant vertex buffer changes.
565        */
566       /* We cannot immediately update the primitives as some methods below
567        * still need the uncorrected start vertices
568        */
569       start_offset = offset_diff/stride;
570       assert(old_offset == buffer_offset - offset_diff);
571       buffer_offset = old_offset;
572    }
573    GLuint offsets[VBO_ATTRIB_MAX];
574    for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
575       offsets[i] = offset;
576       offset += save->attrsz[i] * sizeof(GLfloat);
577    }
578    node->vertex_count = save->vert_count;
579    node->wrap_count = save->copied.nr;
580    node->prims = save->prims;
581    node->merged.ib.obj = NULL;
582    node->prim_count = save->prim_count;
583    node->prim_store = save->prim_store;
584
585    /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
586     * Note that this may reuse the previous one of possible.
587     */
588    for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
589       /* create or reuse the vao */
590       update_vao(ctx, vpm, &save->VAO[vpm],
591                  save->vertex_store->bufferobj, buffer_offset, stride,
592                  save->enabled, save->attrsz, save->attrtype, offsets);
593       /* Reference the vao in the dlist */
594       node->VAO[vpm] = NULL;
595       _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
596    }
597
598    node->prim_store->refcount++;
599
600    if (save->no_current_update) {
601       node->current_data = NULL;
602    }
603    else {
604       GLuint current_size = save->vertex_size - save->attrsz[0];
605       node->current_data = NULL;
606
607       if (current_size) {
608          node->current_data = malloc(current_size * sizeof(GLfloat));
609          if (node->current_data) {
610             const char *buffer = (const char *)save->buffer_map;
611             unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
612             unsigned vertex_offset = 0;
613
614             if (node->vertex_count)
615                vertex_offset = (node->vertex_count - 1) * stride;
616
617             memcpy(node->current_data, buffer + vertex_offset + attr_offset,
618                    current_size * sizeof(GLfloat));
619          } else {
620             _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
621          }
622       }
623    }
624
625    assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->vertex_count == 0);
626
627    if (save->dangling_attr_ref)
628       ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
629
630    save->vertex_store->used += save->vertex_size * node->vertex_count;
631    save->prim_store->used += node->prim_count;
632
633    /* Copy duplicated vertices
634     */
635    save->copied.nr = copy_vertices(ctx, node, save->buffer_map);
636
637    if (node->prims[node->prim_count - 1].mode == GL_LINE_LOOP) {
638       convert_line_loop_to_strip(save, node);
639    }
640
641    merge_prims(ctx, node->prims, &node->prim_count);
642
643    /* Correct the primitive starts, we can only do this here as copy_vertices
644     * and convert_line_loop_to_strip above consume the uncorrected starts.
645     * On the other hand the _vbo_loopback_vertex_list call below needs the
646     * primitves to be corrected already.
647     */
648    for (unsigned i = 0; i < node->prim_count; i++) {
649       node->prims[i].start += start_offset;
650    }
651
652    /* Create an index buffer. */
653    node->min_index = node->max_index = 0;
654    if (save->vert_count && node->prim_count) {
655       /* We won't modify node->prims, so use a const alias to avoid unintended
656        * writes to it. */
657       const struct _mesa_prim *original_prims = node->prims;
658
659       int end = original_prims[node->prim_count - 1].start +
660                 original_prims[node->prim_count - 1].count;
661       int total_vert_count = end - original_prims[0].start;
662
663       node->min_index = node->prims[0].start;
664       node->max_index = end - 1;
665
666       /* Estimate for the worst case: all prims are line strips (the +1 is because
667        * wrap_buffers may call use but the last primitive may not be complete) */
668       int max_indices_count = MAX2(total_vert_count * 2 - (node->prim_count * 2) + 1,
669                                    total_vert_count);
670
671       int indices_offset = 0;
672       int available = save->previous_ib ? (save->previous_ib->Size / 4 - save->ib_first_free_index) : 0;
673       if (available >= max_indices_count) {
674          indices_offset = save->ib_first_free_index;
675       }
676       int size = max_indices_count * sizeof(uint32_t);
677       uint32_t* indices = (uint32_t*) malloc(size);
678       struct _mesa_prim *merged_prims = NULL;
679
680       int idx = 0;
681
682       int last_valid_prim = -1;
683       /* Construct indices array. */
684       for (unsigned i = 0; i < node->prim_count; i++) {
685          assert(original_prims[i].basevertex == 0);
686          GLubyte mode = original_prims[i].mode;
687
688          int vertex_count = original_prims[i].count;
689          if (!vertex_count) {
690             continue;
691          }
692
693          /* Line strips may get converted to lines */
694          if (mode == GL_LINE_STRIP)
695             mode = GL_LINES;
696
697          /* If 2 consecutive prims use the same mode => merge them. */
698          bool merge_prims = last_valid_prim >= 0 &&
699                             mode == merged_prims[last_valid_prim].mode &&
700                             mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
701                             mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
702                             mode != GL_PATCHES;
703
704          /* To be able to merge consecutive triangle strips we need to insert
705           * a degenerate triangle.
706           */
707          if (merge_prims &&
708              mode == GL_TRIANGLE_STRIP) {
709             /* Insert a degenerate triangle */
710             assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
711             unsigned tri_count = merged_prims[last_valid_prim].count - 2;
712
713             indices[idx] = indices[idx - 1];
714             indices[idx + 1] = original_prims[i].start;
715             idx += 2;
716             merged_prims[last_valid_prim].count += 2;
717
718             if (tri_count % 2) {
719                /* Add another index to preserve winding order */
720                indices[idx++] = original_prims[i].start;
721                merged_prims[last_valid_prim].count++;
722             }
723          }
724
725          int start = idx;
726
727          /* Convert line strips to lines if it'll allow if the previous
728           * prim mode is GL_LINES (so merge_prims is true) or if the next
729           * primitive mode is GL_LINES or GL_LINE_LOOP.
730           */
731          if (original_prims[i].mode == GL_LINE_STRIP &&
732              (merge_prims ||
733               (i < node->prim_count - 1 &&
734                (original_prims[i + 1].mode == GL_LINE_STRIP ||
735                 original_prims[i + 1].mode == GL_LINES)))) {
736             for (unsigned j = 0; j < vertex_count; j++) {
737                indices[idx++] = original_prims[i].start + j;
738                /* Repeat all but the first/last indices. */
739                if (j && j != vertex_count - 1) {
740                   indices[idx++] = original_prims[i].start + j;
741                }
742             }
743          } else {
744             /* We didn't convert to LINES, so restore the original mode */
745             mode = original_prims[i].mode;
746
747             for (unsigned j = 0; j < vertex_count; j++) {
748                indices[idx++] = original_prims[i].start + j;
749             }
750          }
751
752          if (merge_prims) {
753             /* Update vertex count. */
754             merged_prims[last_valid_prim].count += idx - start;
755          } else {
756             /* Keep this primitive */
757             last_valid_prim += 1;
758             assert(last_valid_prim <= i);
759             merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
760             merged_prims[last_valid_prim] = original_prims[i];
761             merged_prims[last_valid_prim].start = indices_offset + start;
762             merged_prims[last_valid_prim].count = idx - start;
763          }
764          merged_prims[last_valid_prim].mode = mode;
765       }
766
767       assert(idx > 0 && idx <= max_indices_count);
768
769       unsigned merged_prim_count = last_valid_prim + 1;
770       node->merged.ib.ptr = NULL;
771       node->merged.ib.count = idx;
772       node->merged.ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
773
774       if (!indices_offset) {
775          /* Allocate a new index buffer */
776          _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
777          save->previous_ib = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
778          bool success = ctx->Driver.BufferData(ctx,
779                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
780                                             MAX2(VBO_SAVE_INDEX_SIZE, idx) * sizeof(uint32_t),
781                                             NULL,
782                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
783                                             save->previous_ib);
784          if (!success) {
785             _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
786             _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
787          }
788       }
789
790       _mesa_reference_buffer_object(ctx, &node->merged.ib.obj, save->previous_ib);
791
792       if (node->merged.ib.obj) {
793          ctx->Driver.BufferSubData(ctx,
794                                    indices_offset * sizeof(uint32_t),
795                                    idx * sizeof(uint32_t),
796                                    indices,
797                                    node->merged.ib.obj);
798          save->ib_first_free_index = indices_offset + idx;
799       } else {
800          node->vertex_count = 0;
801          node->prim_count = 0;
802       }
803
804       /* Prepare for DrawGallium */
805       memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
806       /* The other info fields will be updated in vbo_save_playback_vertex_list */
807       node->merged.info.index_size = 4;
808       node->merged.info.instance_count = 1;
809       node->merged.info.index.gl_bo = node->merged.ib.obj;
810       node->merged.start_count = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count));
811       if (merged_prim_count == 1) {
812          node->merged.info.mode = merged_prims[0].mode;
813          node->merged.mode = NULL;
814       } else {
815          node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
816       }
817
818       for (unsigned i = 0; i < merged_prim_count; i++) {
819          node->merged.start_count[i].start = merged_prims[i].start;
820          node->merged.start_count[i].count = merged_prims[i].count;
821          if (merged_prim_count > 1)
822             node->merged.mode[i] = merged_prims[i].mode;
823       }
824       node->merged.num_draws = merged_prim_count;
825       if (node->merged.num_draws > 1) {
826          bool same_mode = true;
827          for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
828             same_mode = node->merged.mode[i] == node->merged.mode[0];
829          }
830          if (same_mode) {
831             /* All primitives use the same mode, so we can simplify a bit */
832             node->merged.info.mode = node->merged.mode[0];
833             free(node->merged.mode);
834             node->merged.mode = NULL;
835          }
836       }
837
838       free(indices);
839       free(merged_prims);
840    }
841
842    /* Deal with GL_COMPILE_AND_EXECUTE:
843     */
844    if (ctx->ExecuteFlag) {
845       struct _glapi_table *dispatch = GET_DISPATCH();
846
847       _glapi_set_dispatch(ctx->Exec);
848
849       /* Note that the range of referenced vertices must be mapped already */
850       _vbo_loopback_vertex_list(ctx, node);
851
852       _glapi_set_dispatch(dispatch);
853    }
854
855    /* Decide whether the storage structs are full, or can be used for
856     * the next vertex lists as well.
857     */
858    if (save->vertex_store->used >
859        save->vertex_store->bufferobj->Size / sizeof(float) - 16 * (save->vertex_size + 4)) {
860       realloc_storage(ctx, -1, 0);
861    }
862    else {
863       /* update buffer_ptr for next vertex */
864       save->buffer_ptr = save->vertex_store->buffer_map
865          + save->vertex_store->used;
866    }
867
868    if (save->prim_store->used > save->prim_store->size - 6) {
869       realloc_storage(ctx, 0, -1);
870    }
871
872    /* Reset our structures for the next run of vertices:
873     */
874    reset_counters(ctx);
875 }
876
877
878 /**
879  * This is called when we fill a vertex buffer before we hit a glEnd().
880  * We
881  * TODO -- If no new vertices have been stored, don't bother saving it.
882  */
883 static void
884 wrap_buffers(struct gl_context *ctx)
885 {
886    struct vbo_save_context *save = &vbo_context(ctx)->save;
887    GLint i = save->prim_count - 1;
888    GLenum mode;
889
890    assert(i < (GLint) save->prim_max);
891    assert(i >= 0);
892
893    /* Close off in-progress primitive.
894     */
895    save->prims[i].count = (save->vert_count - save->prims[i].start);
896    mode = save->prims[i].mode;
897
898    /* store the copied vertices, and allocate a new list.
899     */
900    compile_vertex_list(ctx);
901
902    /* Restart interrupted primitive
903     */
904    save->prims[0].mode = mode;
905    save->prims[0].begin = 0;
906    save->prims[0].end = 0;
907    save->prims[0].start = 0;
908    save->prims[0].count = 0;
909    save->prim_count = 1;
910 }
911
912
913 /**
914  * Called only when buffers are wrapped as the result of filling the
915  * vertex_store struct.
916  */
917 static void
918 wrap_filled_vertex(struct gl_context *ctx)
919 {
920    struct vbo_save_context *save = &vbo_context(ctx)->save;
921    unsigned numComponents;
922
923    /* Emit a glEnd to close off the last vertex list.
924     */
925    wrap_buffers(ctx);
926
927    /* Copy stored stored vertices to start of new list.
928     */
929    assert(save->max_vert - save->vert_count > save->copied.nr);
930
931    numComponents = save->copied.nr * save->vertex_size;
932    memcpy(save->buffer_ptr,
933           save->copied.buffer,
934           numComponents * sizeof(fi_type));
935    save->buffer_ptr += numComponents;
936    save->vert_count += save->copied.nr;
937 }
938
939
940 static void
941 copy_to_current(struct gl_context *ctx)
942 {
943    struct vbo_save_context *save = &vbo_context(ctx)->save;
944    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
945
946    while (enabled) {
947       const int i = u_bit_scan64(&enabled);
948       assert(save->attrsz[i]);
949
950       if (save->attrtype[i] == GL_DOUBLE ||
951           save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
952          memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
953       else
954          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
955                                      save->attrptr[i], save->attrtype[i]);
956    }
957 }
958
959
960 static void
961 copy_from_current(struct gl_context *ctx)
962 {
963    struct vbo_save_context *save = &vbo_context(ctx)->save;
964    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
965
966    while (enabled) {
967       const int i = u_bit_scan64(&enabled);
968
969       switch (save->attrsz[i]) {
970       case 4:
971          save->attrptr[i][3] = save->current[i][3];
972          FALLTHROUGH;
973       case 3:
974          save->attrptr[i][2] = save->current[i][2];
975          FALLTHROUGH;
976       case 2:
977          save->attrptr[i][1] = save->current[i][1];
978          FALLTHROUGH;
979       case 1:
980          save->attrptr[i][0] = save->current[i][0];
981          break;
982       case 0:
983          unreachable("Unexpected vertex attribute size");
984       }
985    }
986 }
987
988
989 /**
990  * Called when we increase the size of a vertex attribute.  For example,
991  * if we've seen one or more glTexCoord2f() calls and now we get a
992  * glTexCoord3f() call.
993  * Flush existing data, set new attrib size, replay copied vertices.
994  */
995 static void
996 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
997 {
998    struct vbo_save_context *save = &vbo_context(ctx)->save;
999    GLuint oldsz;
1000    GLuint i;
1001    fi_type *tmp;
1002
1003    /* Store the current run of vertices, and emit a GL_END.  Emit a
1004     * BEGIN in the new buffer.
1005     */
1006    if (save->vert_count)
1007       wrap_buffers(ctx);
1008    else
1009       assert(save->copied.nr == 0);
1010
1011    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1012     * when the attribute already exists in the vertex and is having
1013     * its size increased.
1014     */
1015    copy_to_current(ctx);
1016
1017    /* Fix up sizes:
1018     */
1019    oldsz = save->attrsz[attr];
1020    save->attrsz[attr] = newsz;
1021    save->enabled |= BITFIELD64_BIT(attr);
1022
1023    save->vertex_size += newsz - oldsz;
1024    save->max_vert = ((save->vertex_store->bufferobj->Size / sizeof(float) -
1025                       save->vertex_store->used) /
1026                      save->vertex_size);
1027    save->vert_count = 0;
1028
1029    /* Recalculate all the attrptr[] values:
1030     */
1031    tmp = save->vertex;
1032    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1033       if (save->attrsz[i]) {
1034          save->attrptr[i] = tmp;
1035          tmp += save->attrsz[i];
1036       }
1037       else {
1038          save->attrptr[i] = NULL;       /* will not be dereferenced. */
1039       }
1040    }
1041
1042    /* Copy from current to repopulate the vertex with correct values.
1043     */
1044    copy_from_current(ctx);
1045
1046    /* Replay stored vertices to translate them to new format here.
1047     *
1048     * If there are copied vertices and the new (upgraded) attribute
1049     * has not been defined before, this list is somewhat degenerate,
1050     * and will need fixup at runtime.
1051     */
1052    if (save->copied.nr) {
1053       const fi_type *data = save->copied.buffer;
1054       fi_type *dest = save->buffer_map;
1055
1056       /* Need to note this and fix up at runtime (or loopback):
1057        */
1058       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1059          assert(oldsz == 0);
1060          save->dangling_attr_ref = GL_TRUE;
1061       }
1062
1063       for (i = 0; i < save->copied.nr; i++) {
1064          GLbitfield64 enabled = save->enabled;
1065          while (enabled) {
1066             const int j = u_bit_scan64(&enabled);
1067             assert(save->attrsz[j]);
1068             if (j == attr) {
1069                if (oldsz) {
1070                   COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
1071                                               save->attrtype[j]);
1072                   data += oldsz;
1073                   dest += newsz;
1074                }
1075                else {
1076                   COPY_SZ_4V(dest, newsz, save->current[attr]);
1077                   dest += newsz;
1078                }
1079             }
1080             else {
1081                GLint sz = save->attrsz[j];
1082                COPY_SZ_4V(dest, sz, data);
1083                data += sz;
1084                dest += sz;
1085             }
1086          }
1087       }
1088
1089       save->buffer_ptr = dest;
1090       save->vert_count += save->copied.nr;
1091    }
1092 }
1093
1094
1095 /**
1096  * This is called when the size of a vertex attribute changes.
1097  * For example, after seeing one or more glTexCoord2f() calls we
1098  * get a glTexCoord4f() or glTexCoord1f() call.
1099  */
1100 static void
1101 fixup_vertex(struct gl_context *ctx, GLuint attr,
1102              GLuint sz, GLenum newType)
1103 {
1104    struct vbo_save_context *save = &vbo_context(ctx)->save;
1105
1106    if (sz > save->attrsz[attr] ||
1107        newType != save->attrtype[attr]) {
1108       /* New size is larger.  Need to flush existing vertices and get
1109        * an enlarged vertex format.
1110        */
1111       upgrade_vertex(ctx, attr, sz);
1112    }
1113    else if (sz < save->active_sz[attr]) {
1114       GLuint i;
1115       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1116
1117       /* New size is equal or smaller - just need to fill in some
1118        * zeros.
1119        */
1120       for (i = sz; i <= save->attrsz[attr]; i++)
1121          save->attrptr[attr][i - 1] = id[i - 1];
1122    }
1123
1124    save->active_sz[attr] = sz;
1125 }
1126
1127
1128 /**
1129  * Reset the current size of all vertex attributes to the default
1130  * value of 0.  This signals that we haven't yet seen any per-vertex
1131  * commands such as glNormal3f() or glTexCoord2f().
1132  */
1133 static void
1134 reset_vertex(struct gl_context *ctx)
1135 {
1136    struct vbo_save_context *save = &vbo_context(ctx)->save;
1137
1138    while (save->enabled) {
1139       const int i = u_bit_scan64(&save->enabled);
1140       assert(save->attrsz[i]);
1141       save->attrsz[i] = 0;
1142       save->active_sz[i] = 0;
1143    }
1144
1145    save->vertex_size = 0;
1146 }
1147
1148
1149 /**
1150  * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1151  * It depends on a few things, including whether we're inside or outside
1152  * of glBegin/glEnd.
1153  */
1154 static inline bool
1155 is_vertex_position(const struct gl_context *ctx, GLuint index)
1156 {
1157    return (index == 0 &&
1158            _mesa_attr_zero_aliases_vertex(ctx) &&
1159            _mesa_inside_dlist_begin_end(ctx));
1160 }
1161
1162
1163
1164 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
1165
1166
1167 /* Only one size for each attribute may be active at once.  Eg. if
1168  * Color3f is installed/active, then Color4f may not be, even if the
1169  * vertex actually contains 4 color coordinates.  This is because the
1170  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1171  * of the chooser function when switching between Color4f and Color3f.
1172  */
1173 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
1174 do {                                                            \
1175    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
1176    int sz = (sizeof(C) / sizeof(GLfloat));                      \
1177                                                                 \
1178    if (save->active_sz[A] != N)                                 \
1179       fixup_vertex(ctx, A, N * sz, T);                          \
1180                                                                 \
1181    {                                                            \
1182       C *dest = (C *)save->attrptr[A];                          \
1183       if (N>0) dest[0] = V0;                                    \
1184       if (N>1) dest[1] = V1;                                    \
1185       if (N>2) dest[2] = V2;                                    \
1186       if (N>3) dest[3] = V3;                                    \
1187       save->attrtype[A] = T;                                    \
1188    }                                                            \
1189                                                                 \
1190    if ((A) == 0) {                                              \
1191       GLuint i;                                                 \
1192                                                                 \
1193       for (i = 0; i < save->vertex_size; i++)                   \
1194          save->buffer_ptr[i] = save->vertex[i];                 \
1195                                                                 \
1196       save->buffer_ptr += save->vertex_size;                    \
1197                                                                 \
1198       if (++save->vert_count >= save->max_vert)                 \
1199          wrap_filled_vertex(ctx);                               \
1200    }                                                            \
1201 } while (0)
1202
1203 #define TAG(x) _save_##x
1204
1205 #include "vbo_attrib_tmp.h"
1206
1207
1208
1209 #define MAT( ATTR, N, face, params )                    \
1210 do {                                                    \
1211    if (face != GL_BACK)                                 \
1212       MAT_ATTR( ATTR, N, params ); /* front */          \
1213    if (face != GL_FRONT)                                \
1214       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
1215 } while (0)
1216
1217
1218 /**
1219  * Save a glMaterial call found between glBegin/End.
1220  * glMaterial calls outside Begin/End are handled in dlist.c.
1221  */
1222 static void GLAPIENTRY
1223 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1224 {
1225    GET_CURRENT_CONTEXT(ctx);
1226
1227    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1228       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1229       return;
1230    }
1231
1232    switch (pname) {
1233    case GL_EMISSION:
1234       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1235       break;
1236    case GL_AMBIENT:
1237       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1238       break;
1239    case GL_DIFFUSE:
1240       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1241       break;
1242    case GL_SPECULAR:
1243       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1244       break;
1245    case GL_SHININESS:
1246       if (*params < 0 || *params > ctx->Const.MaxShininess) {
1247          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1248       }
1249       else {
1250          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1251       }
1252       break;
1253    case GL_COLOR_INDEXES:
1254       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1255       break;
1256    case GL_AMBIENT_AND_DIFFUSE:
1257       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1258       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1259       break;
1260    default:
1261       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1262       return;
1263    }
1264 }
1265
1266
1267 /* Cope with EvalCoord/CallList called within a begin/end object:
1268  *     -- Flush current buffer
1269  *     -- Fallback to opcodes for the rest of the begin/end object.
1270  */
1271 static void
1272 dlist_fallback(struct gl_context *ctx)
1273 {
1274    struct vbo_save_context *save = &vbo_context(ctx)->save;
1275
1276    if (save->vert_count || save->prim_count) {
1277       if (save->prim_count > 0) {
1278          /* Close off in-progress primitive. */
1279          GLint i = save->prim_count - 1;
1280          save->prims[i].count = save->vert_count - save->prims[i].start;
1281       }
1282
1283       /* Need to replay this display list with loopback,
1284        * unfortunately, otherwise this primitive won't be handled
1285        * properly:
1286        */
1287       save->dangling_attr_ref = GL_TRUE;
1288
1289       compile_vertex_list(ctx);
1290    }
1291
1292    copy_to_current(ctx);
1293    reset_vertex(ctx);
1294    reset_counters(ctx);
1295    if (save->out_of_memory) {
1296       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1297    }
1298    else {
1299       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1300    }
1301    ctx->Driver.SaveNeedFlush = GL_FALSE;
1302 }
1303
1304
1305 static void GLAPIENTRY
1306 _save_EvalCoord1f(GLfloat u)
1307 {
1308    GET_CURRENT_CONTEXT(ctx);
1309    dlist_fallback(ctx);
1310    CALL_EvalCoord1f(ctx->Save, (u));
1311 }
1312
1313 static void GLAPIENTRY
1314 _save_EvalCoord1fv(const GLfloat * v)
1315 {
1316    GET_CURRENT_CONTEXT(ctx);
1317    dlist_fallback(ctx);
1318    CALL_EvalCoord1fv(ctx->Save, (v));
1319 }
1320
1321 static void GLAPIENTRY
1322 _save_EvalCoord2f(GLfloat u, GLfloat v)
1323 {
1324    GET_CURRENT_CONTEXT(ctx);
1325    dlist_fallback(ctx);
1326    CALL_EvalCoord2f(ctx->Save, (u, v));
1327 }
1328
1329 static void GLAPIENTRY
1330 _save_EvalCoord2fv(const GLfloat * v)
1331 {
1332    GET_CURRENT_CONTEXT(ctx);
1333    dlist_fallback(ctx);
1334    CALL_EvalCoord2fv(ctx->Save, (v));
1335 }
1336
1337 static void GLAPIENTRY
1338 _save_EvalPoint1(GLint i)
1339 {
1340    GET_CURRENT_CONTEXT(ctx);
1341    dlist_fallback(ctx);
1342    CALL_EvalPoint1(ctx->Save, (i));
1343 }
1344
1345 static void GLAPIENTRY
1346 _save_EvalPoint2(GLint i, GLint j)
1347 {
1348    GET_CURRENT_CONTEXT(ctx);
1349    dlist_fallback(ctx);
1350    CALL_EvalPoint2(ctx->Save, (i, j));
1351 }
1352
1353 static void GLAPIENTRY
1354 _save_CallList(GLuint l)
1355 {
1356    GET_CURRENT_CONTEXT(ctx);
1357    dlist_fallback(ctx);
1358    CALL_CallList(ctx->Save, (l));
1359 }
1360
1361 static void GLAPIENTRY
1362 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1363 {
1364    GET_CURRENT_CONTEXT(ctx);
1365    dlist_fallback(ctx);
1366    CALL_CallLists(ctx->Save, (n, type, v));
1367 }
1368
1369
1370
1371 /**
1372  * Called when a glBegin is getting compiled into a display list.
1373  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1374  */
1375 void
1376 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1377                      bool no_current_update)
1378 {
1379    struct vbo_save_context *save = &vbo_context(ctx)->save;
1380    const GLuint i = save->prim_count++;
1381
1382    ctx->Driver.CurrentSavePrimitive = mode;
1383
1384    assert(i < save->prim_max);
1385    save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1386    save->prims[i].begin = 1;
1387    save->prims[i].end = 0;
1388    save->prims[i].start = save->vert_count;
1389    save->prims[i].count = 0;
1390
1391    save->no_current_update = no_current_update;
1392
1393    if (save->out_of_memory) {
1394       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1395    }
1396    else {
1397       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1398    }
1399
1400    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1401    ctx->Driver.SaveNeedFlush = GL_TRUE;
1402 }
1403
1404
1405 static void GLAPIENTRY
1406 _save_End(void)
1407 {
1408    GET_CURRENT_CONTEXT(ctx);
1409    struct vbo_save_context *save = &vbo_context(ctx)->save;
1410    const GLint i = save->prim_count - 1;
1411
1412    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1413    save->prims[i].end = 1;
1414    save->prims[i].count = (save->vert_count - save->prims[i].start);
1415
1416    if (i == (GLint) save->prim_max - 1) {
1417       compile_vertex_list(ctx);
1418       assert(save->copied.nr == 0);
1419    }
1420
1421    /* Swap out this vertex format while outside begin/end.  Any color,
1422     * etc. received between here and the next begin will be compiled
1423     * as opcodes.
1424     */
1425    if (save->out_of_memory) {
1426       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1427    }
1428    else {
1429       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1430    }
1431 }
1432
1433
1434 static void GLAPIENTRY
1435 _save_Begin(GLenum mode)
1436 {
1437    GET_CURRENT_CONTEXT(ctx);
1438    (void) mode;
1439    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1440 }
1441
1442
1443 static void GLAPIENTRY
1444 _save_PrimitiveRestartNV(void)
1445 {
1446    GET_CURRENT_CONTEXT(ctx);
1447    struct vbo_save_context *save = &vbo_context(ctx)->save;
1448
1449    if (save->prim_count == 0) {
1450       /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1451        * is an error.
1452        */
1453       _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1454                           "glPrimitiveRestartNV called outside glBegin/End");
1455    } else {
1456       /* get current primitive mode */
1457       GLenum curPrim = save->prims[save->prim_count - 1].mode;
1458       bool no_current_update = save->no_current_update;
1459
1460       /* restart primitive */
1461       CALL_End(ctx->CurrentServerDispatch, ());
1462       vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1463    }
1464 }
1465
1466
1467 /* Unlike the functions above, these are to be hooked into the vtxfmt
1468  * maintained in ctx->ListState, active when the list is known or
1469  * suspected to be outside any begin/end primitive.
1470  * Note: OBE = Outside Begin/End
1471  */
1472 static void GLAPIENTRY
1473 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1474 {
1475    GET_CURRENT_CONTEXT(ctx);
1476    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1477
1478    vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1479    CALL_Vertex2f(dispatch, (x1, y1));
1480    CALL_Vertex2f(dispatch, (x2, y1));
1481    CALL_Vertex2f(dispatch, (x2, y2));
1482    CALL_Vertex2f(dispatch, (x1, y2));
1483    CALL_End(dispatch, ());
1484 }
1485
1486
1487 static void GLAPIENTRY
1488 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1489 {
1490    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1491 }
1492
1493 static void GLAPIENTRY
1494 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1495 {
1496    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1497 }
1498
1499 static void GLAPIENTRY
1500 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1501 {
1502    _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1503 }
1504
1505 static void GLAPIENTRY
1506 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1507 {
1508    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1509 }
1510
1511 static void GLAPIENTRY
1512 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1513 {
1514    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1515 }
1516
1517 static void GLAPIENTRY
1518 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1519 {
1520    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1521 }
1522
1523 static void GLAPIENTRY
1524 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1525 {
1526    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1527 }
1528
1529 static void
1530 _ensure_draws_fits_in_storage(struct gl_context *ctx, int primcount, int vertcount)
1531 {
1532    struct vbo_save_context *save = &vbo_context(ctx)->save;
1533
1534    bool realloc_prim = save->prim_count + primcount > save->prim_max;
1535    bool realloc_vert = save->vertex_size && (save->vert_count + vertcount >= save->max_vert);
1536
1537    if (realloc_prim || realloc_vert) {
1538       if (save->vert_count || save->prim_count)
1539          compile_vertex_list(ctx);
1540       realloc_storage(ctx, realloc_prim ? primcount : -1, realloc_vert ? vertcount : -1);
1541       reset_counters(ctx);
1542       assert(save->prim_max);
1543    }
1544 }
1545
1546
1547 static void GLAPIENTRY
1548 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1549 {
1550    GET_CURRENT_CONTEXT(ctx);
1551    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1552    struct vbo_save_context *save = &vbo_context(ctx)->save;
1553    GLint i;
1554
1555    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1556       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1557       return;
1558    }
1559    if (count < 0) {
1560       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1561       return;
1562    }
1563
1564    if (save->out_of_memory)
1565       return;
1566
1567    _ensure_draws_fits_in_storage(ctx, 1, count);
1568
1569    /* Make sure to process any VBO binding changes */
1570    _mesa_update_state(ctx);
1571
1572    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1573
1574    vbo_save_NotifyBegin(ctx, mode, true);
1575
1576    for (i = 0; i < count; i++)
1577       _mesa_array_element(ctx, start + i);
1578    CALL_End(ctx->CurrentServerDispatch, ());
1579
1580    _mesa_vao_unmap_arrays(ctx, vao);
1581 }
1582
1583
1584 static void GLAPIENTRY
1585 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1586                           const GLsizei *count, GLsizei primcount)
1587 {
1588    GET_CURRENT_CONTEXT(ctx);
1589    GLint i;
1590
1591    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1592       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1593       return;
1594    }
1595
1596    if (primcount < 0) {
1597       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1598                           "glMultiDrawArrays(primcount<0)");
1599       return;
1600    }
1601
1602    unsigned vertcount = 0;
1603    for (i = 0; i < primcount; i++) {
1604       if (count[i] < 0) {
1605          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1606                              "glMultiDrawArrays(count[i]<0)");
1607          return;
1608       }
1609       vertcount += count[i];
1610    }
1611
1612    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1613
1614    for (i = 0; i < primcount; i++) {
1615       if (count[i] > 0) {
1616          _save_OBE_DrawArrays(mode, first[i], count[i]);
1617       }
1618    }
1619 }
1620
1621
1622 static void
1623 array_element(struct gl_context *ctx,
1624               GLint basevertex, GLuint elt, unsigned index_size_shift)
1625 {
1626    /* Section 10.3.5 Primitive Restart:
1627     * [...]
1628     *    When one of the *BaseVertex drawing commands specified in section 10.5
1629     * is used, the primitive restart comparison occurs before the basevertex
1630     * offset is added to the array index.
1631     */
1632    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1633     * then we call PrimitiveRestartNV and return.
1634     */
1635    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1636        elt == ctx->Array._RestartIndex[index_size_shift]) {
1637       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1638       return;
1639    }
1640
1641    _mesa_array_element(ctx, basevertex + elt);
1642 }
1643
1644
1645 /* Could do better by copying the arrays and element list intact and
1646  * then emitting an indexed prim at runtime.
1647  */
1648 static void GLAPIENTRY
1649 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1650                                  const GLvoid * indices, GLint basevertex)
1651 {
1652    GET_CURRENT_CONTEXT(ctx);
1653    struct vbo_save_context *save = &vbo_context(ctx)->save;
1654    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1655    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1656    GLint i;
1657
1658    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1659       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1660       return;
1661    }
1662    if (count < 0) {
1663       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1664       return;
1665    }
1666    if (type != GL_UNSIGNED_BYTE &&
1667        type != GL_UNSIGNED_SHORT &&
1668        type != GL_UNSIGNED_INT) {
1669       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1670       return;
1671    }
1672
1673    if (save->out_of_memory)
1674       return;
1675
1676    _ensure_draws_fits_in_storage(ctx, 1, count);
1677
1678    /* Make sure to process any VBO binding changes */
1679    _mesa_update_state(ctx);
1680
1681    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1682
1683    if (indexbuf)
1684       indices =
1685          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1686
1687    vbo_save_NotifyBegin(ctx, mode, true);
1688
1689    switch (type) {
1690    case GL_UNSIGNED_BYTE:
1691       for (i = 0; i < count; i++)
1692          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1693       break;
1694    case GL_UNSIGNED_SHORT:
1695       for (i = 0; i < count; i++)
1696          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1697       break;
1698    case GL_UNSIGNED_INT:
1699       for (i = 0; i < count; i++)
1700          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1701       break;
1702    default:
1703       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1704       break;
1705    }
1706
1707    CALL_End(ctx->CurrentServerDispatch, ());
1708
1709    _mesa_vao_unmap(ctx, vao);
1710 }
1711
1712 static void GLAPIENTRY
1713 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1714                        const GLvoid * indices)
1715 {
1716    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1717 }
1718
1719
1720 static void GLAPIENTRY
1721 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1722                             GLsizei count, GLenum type,
1723                             const GLvoid * indices)
1724 {
1725    GET_CURRENT_CONTEXT(ctx);
1726    struct vbo_save_context *save = &vbo_context(ctx)->save;
1727
1728    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1729       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1730       return;
1731    }
1732    if (count < 0) {
1733       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1734                           "glDrawRangeElements(count<0)");
1735       return;
1736    }
1737    if (type != GL_UNSIGNED_BYTE &&
1738        type != GL_UNSIGNED_SHORT &&
1739        type != GL_UNSIGNED_INT) {
1740       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1741       return;
1742    }
1743    if (end < start) {
1744       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1745                           "glDrawRangeElements(end < start)");
1746       return;
1747    }
1748
1749    if (save->out_of_memory)
1750       return;
1751
1752    _save_OBE_DrawElements(mode, count, type, indices);
1753 }
1754
1755
1756 static void GLAPIENTRY
1757 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1758                             const GLvoid * const *indices, GLsizei primcount)
1759 {
1760    GET_CURRENT_CONTEXT(ctx);
1761    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1762    GLsizei i;
1763
1764    int vertcount = 0;
1765    for (i = 0; i < primcount; i++) {
1766       vertcount += count[i];
1767    }
1768    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1769
1770    for (i = 0; i < primcount; i++) {
1771       if (count[i] > 0) {
1772          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1773       }
1774    }
1775 }
1776
1777
1778 static void GLAPIENTRY
1779 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1780                                       GLenum type,
1781                                       const GLvoid * const *indices,
1782                                       GLsizei primcount,
1783                                       const GLint *basevertex)
1784 {
1785    GET_CURRENT_CONTEXT(ctx);
1786    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1787    GLsizei i;
1788
1789    int vertcount = 0;
1790    for (i = 0; i < primcount; i++) {
1791       vertcount += count[i];
1792    }
1793    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1794
1795    for (i = 0; i < primcount; i++) {
1796       if (count[i] > 0) {
1797          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1798                                                       indices[i],
1799                                                       basevertex[i]));
1800       }
1801    }
1802 }
1803
1804
1805 static void
1806 vtxfmt_init(struct gl_context *ctx)
1807 {
1808    struct vbo_save_context *save = &vbo_context(ctx)->save;
1809    GLvertexformat *vfmt = &save->vtxfmt;
1810
1811 #define NAME_AE(x) _ae_##x
1812 #define NAME_CALLLIST(x) _save_##x
1813 #define NAME(x) _save_##x
1814 #define NAME_ES(x) _save_##x##ARB
1815
1816 #include "vbo_init_tmp.h"
1817 }
1818
1819
1820 /**
1821  * Initialize the dispatch table with the VBO functions for display
1822  * list compilation.
1823  */
1824 void
1825 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1826                              struct _glapi_table *exec)
1827 {
1828    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1829    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1830    SET_DrawElements(exec, _save_OBE_DrawElements);
1831    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1832    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1833    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1834    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1835    SET_Rectf(exec, _save_OBE_Rectf);
1836    SET_Rectd(exec, _save_OBE_Rectd);
1837    SET_Rectdv(exec, _save_OBE_Rectdv);
1838    SET_Rectfv(exec, _save_OBE_Rectfv);
1839    SET_Recti(exec, _save_OBE_Recti);
1840    SET_Rectiv(exec, _save_OBE_Rectiv);
1841    SET_Rects(exec, _save_OBE_Rects);
1842    SET_Rectsv(exec, _save_OBE_Rectsv);
1843
1844    /* Note: other glDraw functins aren't compiled into display lists */
1845 }
1846
1847
1848
1849 void
1850 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1851 {
1852    struct vbo_save_context *save = &vbo_context(ctx)->save;
1853
1854    /* Noop when we are actually active:
1855     */
1856    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1857       return;
1858
1859    if (save->vert_count || save->prim_count)
1860       compile_vertex_list(ctx);
1861
1862    copy_to_current(ctx);
1863    reset_vertex(ctx);
1864    reset_counters(ctx);
1865    ctx->Driver.SaveNeedFlush = GL_FALSE;
1866 }
1867
1868
1869 /**
1870  * Called from glNewList when we're starting to compile a display list.
1871  */
1872 void
1873 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1874 {
1875    struct vbo_save_context *save = &vbo_context(ctx)->save;
1876
1877    (void) list;
1878    (void) mode;
1879
1880    if (!save->prim_store)
1881       save->prim_store = alloc_prim_store(0);
1882
1883    if (!save->vertex_store)
1884       save->vertex_store = alloc_vertex_store(ctx, 0);
1885
1886    save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1887
1888    reset_vertex(ctx);
1889    reset_counters(ctx);
1890    ctx->Driver.SaveNeedFlush = GL_FALSE;
1891 }
1892
1893
1894 /**
1895  * Called from glEndList when we're finished compiling a display list.
1896  */
1897 void
1898 vbo_save_EndList(struct gl_context *ctx)
1899 {
1900    struct vbo_save_context *save = &vbo_context(ctx)->save;
1901
1902    /* EndList called inside a (saved) Begin/End pair?
1903     */
1904    if (_mesa_inside_dlist_begin_end(ctx)) {
1905       if (save->prim_count > 0) {
1906          GLint i = save->prim_count - 1;
1907          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1908          save->prims[i].end = 0;
1909          save->prims[i].count = save->vert_count - save->prims[i].start;
1910       }
1911
1912       /* Make sure this vertex list gets replayed by the "loopback"
1913        * mechanism:
1914        */
1915       save->dangling_attr_ref = GL_TRUE;
1916       vbo_save_SaveFlushVertices(ctx);
1917
1918       /* Swap out this vertex format while outside begin/end.  Any color,
1919        * etc. received between here and the next begin will be compiled
1920        * as opcodes.
1921        */
1922       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1923    }
1924
1925    vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1926
1927    assert(save->vertex_size == 0);
1928 }
1929
1930
1931 /**
1932  * Called from the display list code when we're about to execute a
1933  * display list.
1934  */
1935 void
1936 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1937 {
1938    struct vbo_save_context *save = &vbo_context(ctx)->save;
1939    save->replay_flags |= dlist->Flags;
1940 }
1941
1942
1943 /**
1944  * Called from the display list code when we're finished executing a
1945  * display list.
1946  */
1947 void
1948 vbo_save_EndCallList(struct gl_context *ctx)
1949 {
1950    struct vbo_save_context *save = &vbo_context(ctx)->save;
1951
1952    if (ctx->ListState.CallDepth == 1)
1953       save->replay_flags = 0;
1954 }
1955
1956
1957 /**
1958  * Called during context creation/init.
1959  */
1960 static void
1961 current_init(struct gl_context *ctx)
1962 {
1963    struct vbo_save_context *save = &vbo_context(ctx)->save;
1964    GLint i;
1965
1966    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1967       const GLuint j = i - VBO_ATTRIB_POS;
1968       assert(j < VERT_ATTRIB_MAX);
1969       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1970       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1971    }
1972
1973    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1974       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1975       assert(j < MAT_ATTRIB_MAX);
1976       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1977       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1978    }
1979 }
1980
1981
1982 /**
1983  * Initialize the display list compiler.  Called during context creation.
1984  */
1985 void
1986 vbo_save_api_init(struct vbo_save_context *save)
1987 {
1988    struct gl_context *ctx = gl_context_from_vbo_save(save);
1989
1990    vtxfmt_init(ctx);
1991    current_init(ctx);
1992    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop);
1993 }