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