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