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