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