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