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