vbo/dlist: don't force list compilation if out of vertex space
[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    /* Reset our structures for the next run of vertices:
898     */
899    reset_counters(ctx);
900 }
901
902
903 /**
904  * This is called when we fill a vertex buffer before we hit a glEnd().
905  * We
906  * TODO -- If no new vertices have been stored, don't bother saving it.
907  */
908 static void
909 wrap_buffers(struct gl_context *ctx)
910 {
911    struct vbo_save_context *save = &vbo_context(ctx)->save;
912    GLint i = save->prim_store->used - 1;
913    GLenum mode;
914
915    assert(i < (GLint) save->prim_store->size);
916    assert(i >= 0);
917
918    /* Close off in-progress primitive.
919     */
920    save->prim_store->prims[i].count = (save->vert_count - save->prim_store->prims[i].start);
921    mode = save->prim_store->prims[i].mode;
922
923    /* store the copied vertices, and allocate a new list.
924     */
925    compile_vertex_list(ctx);
926
927    /* Restart interrupted primitive
928     */
929    save->prim_store->prims[0].mode = mode;
930    save->prim_store->prims[0].begin = 0;
931    save->prim_store->prims[0].end = 0;
932    save->prim_store->prims[0].start = 0;
933    save->prim_store->prims[0].count = 0;
934    save->prim_store->used = 1;
935 }
936
937
938 /**
939  * Called only when buffers are wrapped as the result of filling the
940  * vertex_store struct.
941  */
942 static void
943 wrap_filled_vertex(struct gl_context *ctx)
944 {
945    struct vbo_save_context *save = &vbo_context(ctx)->save;
946    unsigned numComponents;
947    ASSERTED uint32_t max_vert = save->vertex_size ?
948       save->vertex_store->buffer_in_ram_size / (sizeof(float) * save->vertex_size) : 0;
949
950    /* Emit a glEnd to close off the last vertex list.
951     */
952    wrap_buffers(ctx);
953
954    /* Copy stored stored vertices to start of new list.
955     */
956    assert(max_vert - save->vert_count > save->copied.nr);
957
958    numComponents = save->copied.nr * save->vertex_size;
959
960    fi_type *buffer_ptr = save->vertex_store->buffer_in_ram;
961    memcpy(buffer_ptr,
962           save->copied.buffer,
963           numComponents * sizeof(fi_type));
964    assert(save->vertex_store->used == 0 && save->vert_count == 0);
965    save->vert_count = save->copied.nr;
966    save->vertex_store->used = numComponents;
967 }
968
969
970 static void
971 copy_to_current(struct gl_context *ctx)
972 {
973    struct vbo_save_context *save = &vbo_context(ctx)->save;
974    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
975
976    while (enabled) {
977       const int i = u_bit_scan64(&enabled);
978       assert(save->attrsz[i]);
979
980       if (save->attrtype[i] == GL_DOUBLE ||
981           save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
982          memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
983       else
984          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
985                                      save->attrptr[i], save->attrtype[i]);
986    }
987 }
988
989
990 static void
991 copy_from_current(struct gl_context *ctx)
992 {
993    struct vbo_save_context *save = &vbo_context(ctx)->save;
994    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
995
996    while (enabled) {
997       const int i = u_bit_scan64(&enabled);
998
999       switch (save->attrsz[i]) {
1000       case 4:
1001          save->attrptr[i][3] = save->current[i][3];
1002          FALLTHROUGH;
1003       case 3:
1004          save->attrptr[i][2] = save->current[i][2];
1005          FALLTHROUGH;
1006       case 2:
1007          save->attrptr[i][1] = save->current[i][1];
1008          FALLTHROUGH;
1009       case 1:
1010          save->attrptr[i][0] = save->current[i][0];
1011          break;
1012       case 0:
1013          unreachable("Unexpected vertex attribute size");
1014       }
1015    }
1016 }
1017
1018
1019 /**
1020  * Called when we increase the size of a vertex attribute.  For example,
1021  * if we've seen one or more glTexCoord2f() calls and now we get a
1022  * glTexCoord3f() call.
1023  * Flush existing data, set new attrib size, replay copied vertices.
1024  */
1025 static void
1026 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1027 {
1028    struct vbo_save_context *save = &vbo_context(ctx)->save;
1029    GLuint oldsz;
1030    GLuint i;
1031    fi_type *tmp;
1032
1033    /* Store the current run of vertices, and emit a GL_END.  Emit a
1034     * BEGIN in the new buffer.
1035     */
1036    if (save->vert_count)
1037       wrap_buffers(ctx);
1038    else
1039       assert(save->copied.nr == 0);
1040
1041    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1042     * when the attribute already exists in the vertex and is having
1043     * its size increased.
1044     */
1045    copy_to_current(ctx);
1046
1047    /* Fix up sizes:
1048     */
1049    oldsz = save->attrsz[attr];
1050    save->attrsz[attr] = newsz;
1051    save->enabled |= BITFIELD64_BIT(attr);
1052
1053    save->vertex_size += newsz - oldsz;
1054    save->vert_count = 0;
1055
1056    /* Recalculate all the attrptr[] values:
1057     */
1058    tmp = save->vertex;
1059    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1060       if (save->attrsz[i]) {
1061          save->attrptr[i] = tmp;
1062          tmp += save->attrsz[i];
1063       }
1064       else {
1065          save->attrptr[i] = NULL;       /* will not be dereferenced. */
1066       }
1067    }
1068
1069    /* Copy from current to repopulate the vertex with correct values.
1070     */
1071    copy_from_current(ctx);
1072
1073    /* Replay stored vertices to translate them to new format here.
1074     *
1075     * If there are copied vertices and the new (upgraded) attribute
1076     * has not been defined before, this list is somewhat degenerate,
1077     * and will need fixup at runtime.
1078     */
1079    if (save->copied.nr) {
1080       const fi_type *data = save->copied.buffer;
1081       fi_type *dest = save->vertex_store->buffer_in_ram;
1082
1083       /* Need to note this and fix up at runtime (or loopback):
1084        */
1085       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1086          assert(oldsz == 0);
1087          save->dangling_attr_ref = GL_TRUE;
1088       }
1089
1090       for (i = 0; i < save->copied.nr; i++) {
1091          GLbitfield64 enabled = save->enabled;
1092          while (enabled) {
1093             const int j = u_bit_scan64(&enabled);
1094             assert(save->attrsz[j]);
1095             if (j == attr) {
1096                if (oldsz) {
1097                   COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
1098                                               save->attrtype[j]);
1099                   data += oldsz;
1100                   dest += newsz;
1101                }
1102                else {
1103                   COPY_SZ_4V(dest, newsz, save->current[attr]);
1104                   dest += newsz;
1105                }
1106             }
1107             else {
1108                GLint sz = save->attrsz[j];
1109                COPY_SZ_4V(dest, sz, data);
1110                data += sz;
1111                dest += sz;
1112             }
1113          }
1114       }
1115
1116       save->vert_count += save->copied.nr;
1117       save->vertex_store->used += save->vertex_size * save->copied.nr;
1118    }
1119 }
1120
1121
1122 /**
1123  * This is called when the size of a vertex attribute changes.
1124  * For example, after seeing one or more glTexCoord2f() calls we
1125  * get a glTexCoord4f() or glTexCoord1f() call.
1126  */
1127 static void
1128 fixup_vertex(struct gl_context *ctx, GLuint attr,
1129              GLuint sz, GLenum newType)
1130 {
1131    struct vbo_save_context *save = &vbo_context(ctx)->save;
1132
1133    if (sz > save->attrsz[attr] ||
1134        newType != save->attrtype[attr]) {
1135       /* New size is larger.  Need to flush existing vertices and get
1136        * an enlarged vertex format.
1137        */
1138       upgrade_vertex(ctx, attr, sz);
1139    }
1140    else if (sz < save->active_sz[attr]) {
1141       GLuint i;
1142       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1143
1144       /* New size is equal or smaller - just need to fill in some
1145        * zeros.
1146        */
1147       for (i = sz; i <= save->attrsz[attr]; i++)
1148          save->attrptr[attr][i - 1] = id[i - 1];
1149    }
1150
1151    save->active_sz[attr] = sz;
1152 }
1153
1154
1155 /**
1156  * Reset the current size of all vertex attributes to the default
1157  * value of 0.  This signals that we haven't yet seen any per-vertex
1158  * commands such as glNormal3f() or glTexCoord2f().
1159  */
1160 static void
1161 reset_vertex(struct gl_context *ctx)
1162 {
1163    struct vbo_save_context *save = &vbo_context(ctx)->save;
1164
1165    while (save->enabled) {
1166       const int i = u_bit_scan64(&save->enabled);
1167       assert(save->attrsz[i]);
1168       save->attrsz[i] = 0;
1169       save->active_sz[i] = 0;
1170    }
1171
1172    save->vertex_size = 0;
1173 }
1174
1175
1176 /**
1177  * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1178  * It depends on a few things, including whether we're inside or outside
1179  * of glBegin/glEnd.
1180  */
1181 static inline bool
1182 is_vertex_position(const struct gl_context *ctx, GLuint index)
1183 {
1184    return (index == 0 &&
1185            _mesa_attr_zero_aliases_vertex(ctx) &&
1186            _mesa_inside_dlist_begin_end(ctx));
1187 }
1188
1189
1190
1191 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
1192
1193
1194 /* Only one size for each attribute may be active at once.  Eg. if
1195  * Color3f is installed/active, then Color4f may not be, even if the
1196  * vertex actually contains 4 color coordinates.  This is because the
1197  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1198  * of the chooser function when switching between Color4f and Color3f.
1199  */
1200 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
1201 do {                                                            \
1202    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
1203    int sz = (sizeof(C) / sizeof(GLfloat));                      \
1204                                                                 \
1205    if (save->active_sz[A] != N)                                 \
1206       fixup_vertex(ctx, A, N * sz, T);                          \
1207                                                                 \
1208    {                                                            \
1209       C *dest = (C *)save->attrptr[A];                          \
1210       if (N>0) dest[0] = V0;                                    \
1211       if (N>1) dest[1] = V1;                                    \
1212       if (N>2) dest[2] = V2;                                    \
1213       if (N>3) dest[3] = V3;                                    \
1214       save->attrtype[A] = T;                                    \
1215    }                                                            \
1216                                                                 \
1217    if ((A) == 0) {                                              \
1218       GLuint i;                                                 \
1219       uint32_t max_vert = save->vertex_size ? \
1220          save->vertex_store->buffer_in_ram_size / (sizeof(float) * save->vertex_size) : 0; \
1221       fi_type *buffer_ptr = save->vertex_store->buffer_in_ram + save->vertex_store->used; \
1222                                                                 \
1223       for (i = 0; i < save->vertex_size; i++)                   \
1224              buffer_ptr[i] = save->vertex[i];                   \
1225                                                                 \
1226       save->vertex_store->used += save->vertex_size; \
1227       if (++save->vert_count >= max_vert)                       \
1228          realloc_storage(ctx, -1, max_vert * 2);                                \
1229    }                                                            \
1230 } while (0)
1231
1232 #define TAG(x) _save_##x
1233
1234 #include "vbo_attrib_tmp.h"
1235
1236
1237
1238 #define MAT( ATTR, N, face, params )                    \
1239 do {                                                    \
1240    if (face != GL_BACK)                                 \
1241       MAT_ATTR( ATTR, N, params ); /* front */          \
1242    if (face != GL_FRONT)                                \
1243       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
1244 } while (0)
1245
1246
1247 /**
1248  * Save a glMaterial call found between glBegin/End.
1249  * glMaterial calls outside Begin/End are handled in dlist.c.
1250  */
1251 static void GLAPIENTRY
1252 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1253 {
1254    GET_CURRENT_CONTEXT(ctx);
1255
1256    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1257       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1258       return;
1259    }
1260
1261    switch (pname) {
1262    case GL_EMISSION:
1263       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1264       break;
1265    case GL_AMBIENT:
1266       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1267       break;
1268    case GL_DIFFUSE:
1269       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1270       break;
1271    case GL_SPECULAR:
1272       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1273       break;
1274    case GL_SHININESS:
1275       if (*params < 0 || *params > ctx->Const.MaxShininess) {
1276          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1277       }
1278       else {
1279          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1280       }
1281       break;
1282    case GL_COLOR_INDEXES:
1283       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1284       break;
1285    case GL_AMBIENT_AND_DIFFUSE:
1286       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1287       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1288       break;
1289    default:
1290       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1291       return;
1292    }
1293 }
1294
1295
1296 /* Cope with EvalCoord/CallList called within a begin/end object:
1297  *     -- Flush current buffer
1298  *     -- Fallback to opcodes for the rest of the begin/end object.
1299  */
1300 static void
1301 dlist_fallback(struct gl_context *ctx)
1302 {
1303    struct vbo_save_context *save = &vbo_context(ctx)->save;
1304
1305    if (save->vert_count || save->prim_store->used) {
1306       if (save->prim_store->used > 0) {
1307          /* Close off in-progress primitive. */
1308          GLint i = save->prim_store->used - 1;
1309          save->prim_store->prims[i].count = save->vert_count - save->prim_store->prims[i].start;
1310       }
1311
1312       /* Need to replay this display list with loopback,
1313        * unfortunately, otherwise this primitive won't be handled
1314        * properly:
1315        */
1316       save->dangling_attr_ref = GL_TRUE;
1317
1318       compile_vertex_list(ctx);
1319    }
1320
1321    copy_to_current(ctx);
1322    reset_vertex(ctx);
1323    if (save->out_of_memory) {
1324       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1325    }
1326    else {
1327       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1328    }
1329    ctx->Driver.SaveNeedFlush = GL_FALSE;
1330 }
1331
1332
1333 static void GLAPIENTRY
1334 _save_EvalCoord1f(GLfloat u)
1335 {
1336    GET_CURRENT_CONTEXT(ctx);
1337    dlist_fallback(ctx);
1338    CALL_EvalCoord1f(ctx->Save, (u));
1339 }
1340
1341 static void GLAPIENTRY
1342 _save_EvalCoord1fv(const GLfloat * v)
1343 {
1344    GET_CURRENT_CONTEXT(ctx);
1345    dlist_fallback(ctx);
1346    CALL_EvalCoord1fv(ctx->Save, (v));
1347 }
1348
1349 static void GLAPIENTRY
1350 _save_EvalCoord2f(GLfloat u, GLfloat v)
1351 {
1352    GET_CURRENT_CONTEXT(ctx);
1353    dlist_fallback(ctx);
1354    CALL_EvalCoord2f(ctx->Save, (u, v));
1355 }
1356
1357 static void GLAPIENTRY
1358 _save_EvalCoord2fv(const GLfloat * v)
1359 {
1360    GET_CURRENT_CONTEXT(ctx);
1361    dlist_fallback(ctx);
1362    CALL_EvalCoord2fv(ctx->Save, (v));
1363 }
1364
1365 static void GLAPIENTRY
1366 _save_EvalPoint1(GLint i)
1367 {
1368    GET_CURRENT_CONTEXT(ctx);
1369    dlist_fallback(ctx);
1370    CALL_EvalPoint1(ctx->Save, (i));
1371 }
1372
1373 static void GLAPIENTRY
1374 _save_EvalPoint2(GLint i, GLint j)
1375 {
1376    GET_CURRENT_CONTEXT(ctx);
1377    dlist_fallback(ctx);
1378    CALL_EvalPoint2(ctx->Save, (i, j));
1379 }
1380
1381 static void GLAPIENTRY
1382 _save_CallList(GLuint l)
1383 {
1384    GET_CURRENT_CONTEXT(ctx);
1385    dlist_fallback(ctx);
1386    CALL_CallList(ctx->Save, (l));
1387 }
1388
1389 static void GLAPIENTRY
1390 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1391 {
1392    GET_CURRENT_CONTEXT(ctx);
1393    dlist_fallback(ctx);
1394    CALL_CallLists(ctx->Save, (n, type, v));
1395 }
1396
1397
1398
1399 /**
1400  * Called when a glBegin is getting compiled into a display list.
1401  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1402  */
1403 void
1404 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1405                      bool no_current_update)
1406 {
1407    struct vbo_save_context *save = &vbo_context(ctx)->save;
1408    const GLuint i = save->prim_store->used++;
1409
1410    ctx->Driver.CurrentSavePrimitive = mode;
1411
1412    assert(i < save->prim_store->size);
1413    save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1414    save->prim_store->prims[i].begin = 1;
1415    save->prim_store->prims[i].end = 0;
1416    save->prim_store->prims[i].start = save->vert_count;
1417    save->prim_store->prims[i].count = 0;
1418
1419    save->no_current_update = no_current_update;
1420
1421    if (save->out_of_memory) {
1422       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1423    }
1424    else {
1425       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1426    }
1427
1428    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1429    ctx->Driver.SaveNeedFlush = GL_TRUE;
1430 }
1431
1432
1433 static void GLAPIENTRY
1434 _save_End(void)
1435 {
1436    GET_CURRENT_CONTEXT(ctx);
1437    struct vbo_save_context *save = &vbo_context(ctx)->save;
1438    const GLint i = save->prim_store->used - 1;
1439
1440    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1441    save->prim_store->prims[i].end = 1;
1442    save->prim_store->prims[i].count = (save->vert_count - save->prim_store->prims[i].start);
1443
1444    if (i == (GLint) save->prim_store->size - 1) {
1445       compile_vertex_list(ctx);
1446       assert(save->copied.nr == 0);
1447    }
1448
1449    /* Swap out this vertex format while outside begin/end.  Any color,
1450     * etc. received between here and the next begin will be compiled
1451     * as opcodes.
1452     */
1453    if (save->out_of_memory) {
1454       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1455    }
1456    else {
1457       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1458    }
1459 }
1460
1461
1462 static void GLAPIENTRY
1463 _save_Begin(GLenum mode)
1464 {
1465    GET_CURRENT_CONTEXT(ctx);
1466    (void) mode;
1467    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1468 }
1469
1470
1471 static void GLAPIENTRY
1472 _save_PrimitiveRestartNV(void)
1473 {
1474    GET_CURRENT_CONTEXT(ctx);
1475    struct vbo_save_context *save = &vbo_context(ctx)->save;
1476
1477    if (save->prim_store->used == 0) {
1478       /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1479        * is an error.
1480        */
1481       _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1482                           "glPrimitiveRestartNV called outside glBegin/End");
1483    } else {
1484       /* get current primitive mode */
1485       GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode;
1486       bool no_current_update = save->no_current_update;
1487
1488       /* restart primitive */
1489       CALL_End(ctx->CurrentServerDispatch, ());
1490       vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1491    }
1492 }
1493
1494
1495 /* Unlike the functions above, these are to be hooked into the vtxfmt
1496  * maintained in ctx->ListState, active when the list is known or
1497  * suspected to be outside any begin/end primitive.
1498  * Note: OBE = Outside Begin/End
1499  */
1500 static void GLAPIENTRY
1501 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1502 {
1503    GET_CURRENT_CONTEXT(ctx);
1504    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1505
1506    vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1507    CALL_Vertex2f(dispatch, (x1, y1));
1508    CALL_Vertex2f(dispatch, (x2, y1));
1509    CALL_Vertex2f(dispatch, (x2, y2));
1510    CALL_Vertex2f(dispatch, (x1, y2));
1511    CALL_End(dispatch, ());
1512 }
1513
1514
1515 static void GLAPIENTRY
1516 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1517 {
1518    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1519 }
1520
1521 static void GLAPIENTRY
1522 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1523 {
1524    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1525 }
1526
1527 static void GLAPIENTRY
1528 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1529 {
1530    _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1531 }
1532
1533 static void GLAPIENTRY
1534 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1535 {
1536    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1537 }
1538
1539 static void GLAPIENTRY
1540 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1541 {
1542    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1543 }
1544
1545 static void GLAPIENTRY
1546 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1547 {
1548    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1549 }
1550
1551 static void GLAPIENTRY
1552 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1553 {
1554    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1555 }
1556
1557 static void
1558 _ensure_draws_fits_in_storage(struct gl_context *ctx, int primcount, int vertcount)
1559 {
1560    struct vbo_save_context *save = &vbo_context(ctx)->save;
1561    uint32_t max_vert = save->vertex_size ?
1562       save->vertex_store->buffer_in_ram_size / (sizeof(float) * save->vertex_size) : 0;
1563
1564    bool realloc_prim = save->prim_store->used + primcount > save->prim_store->size;
1565    bool realloc_vert = save->vertex_size && (save->vert_count + vertcount >= max_vert);
1566
1567    if (realloc_prim || realloc_vert)
1568       realloc_storage(ctx, realloc_prim ? primcount : -1, realloc_vert ? vertcount : -1);
1569 }
1570
1571
1572 static void GLAPIENTRY
1573 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1574 {
1575    GET_CURRENT_CONTEXT(ctx);
1576    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1577    struct vbo_save_context *save = &vbo_context(ctx)->save;
1578    GLint i;
1579
1580    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1581       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1582       return;
1583    }
1584    if (count < 0) {
1585       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1586       return;
1587    }
1588
1589    if (save->out_of_memory)
1590       return;
1591
1592    _ensure_draws_fits_in_storage(ctx, 1, count);
1593
1594    /* Make sure to process any VBO binding changes */
1595    _mesa_update_state(ctx);
1596
1597    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1598
1599    vbo_save_NotifyBegin(ctx, mode, true);
1600
1601    for (i = 0; i < count; i++)
1602       _mesa_array_element(ctx, start + i);
1603    CALL_End(ctx->CurrentServerDispatch, ());
1604
1605    _mesa_vao_unmap_arrays(ctx, vao);
1606 }
1607
1608
1609 static void GLAPIENTRY
1610 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1611                           const GLsizei *count, GLsizei primcount)
1612 {
1613    GET_CURRENT_CONTEXT(ctx);
1614    GLint i;
1615
1616    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1617       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1618       return;
1619    }
1620
1621    if (primcount < 0) {
1622       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1623                           "glMultiDrawArrays(primcount<0)");
1624       return;
1625    }
1626
1627    unsigned vertcount = 0;
1628    for (i = 0; i < primcount; i++) {
1629       if (count[i] < 0) {
1630          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1631                              "glMultiDrawArrays(count[i]<0)");
1632          return;
1633       }
1634       vertcount += count[i];
1635    }
1636
1637    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1638
1639    for (i = 0; i < primcount; i++) {
1640       if (count[i] > 0) {
1641          _save_OBE_DrawArrays(mode, first[i], count[i]);
1642       }
1643    }
1644 }
1645
1646
1647 static void
1648 array_element(struct gl_context *ctx,
1649               GLint basevertex, GLuint elt, unsigned index_size_shift)
1650 {
1651    /* Section 10.3.5 Primitive Restart:
1652     * [...]
1653     *    When one of the *BaseVertex drawing commands specified in section 10.5
1654     * is used, the primitive restart comparison occurs before the basevertex
1655     * offset is added to the array index.
1656     */
1657    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1658     * then we call PrimitiveRestartNV and return.
1659     */
1660    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1661        elt == ctx->Array._RestartIndex[index_size_shift]) {
1662       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1663       return;
1664    }
1665
1666    _mesa_array_element(ctx, basevertex + elt);
1667 }
1668
1669
1670 /* Could do better by copying the arrays and element list intact and
1671  * then emitting an indexed prim at runtime.
1672  */
1673 static void GLAPIENTRY
1674 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1675                                  const GLvoid * indices, GLint basevertex)
1676 {
1677    GET_CURRENT_CONTEXT(ctx);
1678    struct vbo_save_context *save = &vbo_context(ctx)->save;
1679    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1680    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1681    GLint i;
1682
1683    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1684       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1685       return;
1686    }
1687    if (count < 0) {
1688       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1689       return;
1690    }
1691    if (type != GL_UNSIGNED_BYTE &&
1692        type != GL_UNSIGNED_SHORT &&
1693        type != GL_UNSIGNED_INT) {
1694       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1695       return;
1696    }
1697
1698    if (save->out_of_memory)
1699       return;
1700
1701    _ensure_draws_fits_in_storage(ctx, 1, count);
1702
1703    /* Make sure to process any VBO binding changes */
1704    _mesa_update_state(ctx);
1705
1706    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1707
1708    if (indexbuf)
1709       indices =
1710          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1711
1712    vbo_save_NotifyBegin(ctx, mode, true);
1713
1714    switch (type) {
1715    case GL_UNSIGNED_BYTE:
1716       for (i = 0; i < count; i++)
1717          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1718       break;
1719    case GL_UNSIGNED_SHORT:
1720       for (i = 0; i < count; i++)
1721          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1722       break;
1723    case GL_UNSIGNED_INT:
1724       for (i = 0; i < count; i++)
1725          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1726       break;
1727    default:
1728       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1729       break;
1730    }
1731
1732    CALL_End(ctx->CurrentServerDispatch, ());
1733
1734    _mesa_vao_unmap(ctx, vao);
1735 }
1736
1737 static void GLAPIENTRY
1738 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1739                        const GLvoid * indices)
1740 {
1741    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1742 }
1743
1744
1745 static void GLAPIENTRY
1746 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1747                             GLsizei count, GLenum type,
1748                             const GLvoid * indices)
1749 {
1750    GET_CURRENT_CONTEXT(ctx);
1751    struct vbo_save_context *save = &vbo_context(ctx)->save;
1752
1753    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1754       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1755       return;
1756    }
1757    if (count < 0) {
1758       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1759                           "glDrawRangeElements(count<0)");
1760       return;
1761    }
1762    if (type != GL_UNSIGNED_BYTE &&
1763        type != GL_UNSIGNED_SHORT &&
1764        type != GL_UNSIGNED_INT) {
1765       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1766       return;
1767    }
1768    if (end < start) {
1769       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1770                           "glDrawRangeElements(end < start)");
1771       return;
1772    }
1773
1774    if (save->out_of_memory)
1775       return;
1776
1777    _save_OBE_DrawElements(mode, count, type, indices);
1778 }
1779
1780
1781 static void GLAPIENTRY
1782 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1783                             const GLvoid * const *indices, GLsizei primcount)
1784 {
1785    GET_CURRENT_CONTEXT(ctx);
1786    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1787    GLsizei i;
1788
1789    int vertcount = 0;
1790    for (i = 0; i < primcount; i++) {
1791       vertcount += count[i];
1792    }
1793    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1794
1795    for (i = 0; i < primcount; i++) {
1796       if (count[i] > 0) {
1797          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1798       }
1799    }
1800 }
1801
1802
1803 static void GLAPIENTRY
1804 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1805                                       GLenum type,
1806                                       const GLvoid * const *indices,
1807                                       GLsizei primcount,
1808                                       const GLint *basevertex)
1809 {
1810    GET_CURRENT_CONTEXT(ctx);
1811    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1812    GLsizei i;
1813
1814    int vertcount = 0;
1815    for (i = 0; i < primcount; i++) {
1816       vertcount += count[i];
1817    }
1818    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1819
1820    for (i = 0; i < primcount; i++) {
1821       if (count[i] > 0) {
1822          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1823                                                       indices[i],
1824                                                       basevertex[i]));
1825       }
1826    }
1827 }
1828
1829
1830 static void
1831 vtxfmt_init(struct gl_context *ctx)
1832 {
1833    struct vbo_save_context *save = &vbo_context(ctx)->save;
1834    GLvertexformat *vfmt = &save->vtxfmt;
1835
1836 #define NAME_AE(x) _ae_##x
1837 #define NAME_CALLLIST(x) _save_##x
1838 #define NAME(x) _save_##x
1839 #define NAME_ES(x) _save_##x##ARB
1840
1841 #include "vbo_init_tmp.h"
1842 }
1843
1844
1845 /**
1846  * Initialize the dispatch table with the VBO functions for display
1847  * list compilation.
1848  */
1849 void
1850 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1851                              struct _glapi_table *exec)
1852 {
1853    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1854    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1855    SET_DrawElements(exec, _save_OBE_DrawElements);
1856    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1857    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1858    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1859    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1860    SET_Rectf(exec, _save_OBE_Rectf);
1861    SET_Rectd(exec, _save_OBE_Rectd);
1862    SET_Rectdv(exec, _save_OBE_Rectdv);
1863    SET_Rectfv(exec, _save_OBE_Rectfv);
1864    SET_Recti(exec, _save_OBE_Recti);
1865    SET_Rectiv(exec, _save_OBE_Rectiv);
1866    SET_Rects(exec, _save_OBE_Rects);
1867    SET_Rectsv(exec, _save_OBE_Rectsv);
1868
1869    /* Note: other glDraw functins aren't compiled into display lists */
1870 }
1871
1872
1873
1874 void
1875 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1876 {
1877    struct vbo_save_context *save = &vbo_context(ctx)->save;
1878
1879    /* Noop when we are actually active:
1880     */
1881    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1882       return;
1883
1884    if (save->vert_count || save->prim_store->used)
1885       compile_vertex_list(ctx);
1886
1887    copy_to_current(ctx);
1888    reset_vertex(ctx);
1889    ctx->Driver.SaveNeedFlush = GL_FALSE;
1890 }
1891
1892
1893 /**
1894  * Called from glNewList when we're starting to compile a display list.
1895  */
1896 void
1897 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1898 {
1899    struct vbo_save_context *save = &vbo_context(ctx)->save;
1900
1901    (void) list;
1902    (void) mode;
1903
1904    if (!save->prim_store)
1905       save->prim_store = realloc_prim_store(NULL, 8);
1906
1907    if (!save->vertex_store)
1908       save->vertex_store = realloc_vertex_store(NULL, save->vertex_size, 8);
1909
1910    reset_vertex(ctx);
1911    ctx->Driver.SaveNeedFlush = GL_FALSE;
1912 }
1913
1914
1915 /**
1916  * Called from glEndList when we're finished compiling a display list.
1917  */
1918 void
1919 vbo_save_EndList(struct gl_context *ctx)
1920 {
1921    struct vbo_save_context *save = &vbo_context(ctx)->save;
1922
1923    /* EndList called inside a (saved) Begin/End pair?
1924     */
1925    if (_mesa_inside_dlist_begin_end(ctx)) {
1926       if (save->prim_store->used > 0) {
1927          GLint i = save->prim_store->used - 1;
1928          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1929          save->prim_store->prims[i].end = 0;
1930          save->prim_store->prims[i].count = save->vert_count - save->prim_store->prims[i].start;
1931       }
1932
1933       /* Make sure this vertex list gets replayed by the "loopback"
1934        * mechanism:
1935        */
1936       save->dangling_attr_ref = GL_TRUE;
1937       vbo_save_SaveFlushVertices(ctx);
1938
1939       /* Swap out this vertex format while outside begin/end.  Any color,
1940        * etc. received between here and the next begin will be compiled
1941        * as opcodes.
1942        */
1943       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1944    }
1945
1946    assert(save->vertex_size == 0);
1947 }
1948
1949 /**
1950  * Called during context creation/init.
1951  */
1952 static void
1953 current_init(struct gl_context *ctx)
1954 {
1955    struct vbo_save_context *save = &vbo_context(ctx)->save;
1956    GLint i;
1957
1958    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
1959       const GLuint j = i - VBO_ATTRIB_POS;
1960       assert(j < VERT_ATTRIB_MAX);
1961       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1962       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1963    }
1964
1965    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1966       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1967       assert(j < MAT_ATTRIB_MAX);
1968       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1969       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1970    }
1971 }
1972
1973
1974 /**
1975  * Initialize the display list compiler.  Called during context creation.
1976  */
1977 void
1978 vbo_save_api_init(struct vbo_save_context *save)
1979 {
1980    struct gl_context *ctx = gl_context_from_vbo_save(save);
1981
1982    vtxfmt_init(ctx);
1983    current_init(ctx);
1984    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop);
1985 }