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