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