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