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