vbo/dlist: remove vbo_save_context::buffer_map
[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->vertex_store->used = 0;
192
193    if (save->vertex_size)
194       save->max_vert = save->vertex_store->buffer_in_ram_size / (sizeof(float) * save->vertex_size);
195    else
196       save->max_vert = 0;
197
198    save->prim_store->used = 0;
199    save->vert_count = 0;
200    save->dangling_attr_ref = GL_FALSE;
201 }
202
203 /**
204  * For a list of prims, try merging prims that can just be extensions of the
205  * previous prim.
206  */
207 static void
208 merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
209             GLuint *prim_count)
210 {
211    GLuint i;
212    struct _mesa_prim *prev_prim = prim_list;
213
214    for (i = 1; i < *prim_count; i++) {
215       struct _mesa_prim *this_prim = prim_list + i;
216
217       vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
218
219       if (vbo_merge_draws(ctx, true,
220                           prev_prim->mode, this_prim->mode,
221                           prev_prim->start, this_prim->start,
222                           &prev_prim->count, this_prim->count,
223                           prev_prim->basevertex, this_prim->basevertex,
224                           &prev_prim->end,
225                           this_prim->begin, this_prim->end)) {
226          /* We've found a prim that just extend the previous one.  Tack it
227           * onto the previous one, and let this primitive struct get dropped.
228           */
229          continue;
230       }
231
232       /* If any previous primitives have been dropped, then we need to copy
233        * this later one into the next available slot.
234        */
235       prev_prim++;
236       if (prev_prim != this_prim)
237          *prev_prim = *this_prim;
238    }
239
240    *prim_count = prev_prim - prim_list + 1;
241 }
242
243
244 /**
245  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
246  * don't have to worry about handling the _mesa_prim::begin/end flags.
247  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
248  */
249 static void
250 convert_line_loop_to_strip(struct vbo_save_context *save,
251                            struct vbo_save_vertex_list *node)
252 {
253    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
254
255    assert(prim->mode == GL_LINE_LOOP);
256
257    if (prim->end) {
258       /* Copy the 0th vertex to end of the buffer and extend the
259        * vertex count by one to finish the line loop.
260        */
261       const GLuint sz = save->vertex_size;
262       /* 0th vertex: */
263       const fi_type *src = save->vertex_store->buffer_in_ram + prim->start * sz;
264       /* end of buffer: */
265       fi_type *dst = save->vertex_store->buffer_in_ram + (prim->start + prim->count) * sz;
266
267       memcpy(dst, src, sz * sizeof(float));
268
269       prim->count++;
270       node->cold->vertex_count++;
271       save->vert_count++;
272       save->vertex_store->used += sz;
273    }
274
275    if (!prim->begin) {
276       /* Drawing the second or later section of a long line loop.
277        * Skip the 0th vertex.
278        */
279       prim->start++;
280       prim->count--;
281    }
282
283    prim->mode = GL_LINE_STRIP;
284 }
285
286
287 /* Compare the present vao if it has the same setup. */
288 static bool
289 compare_vao(gl_vertex_processing_mode mode,
290             const struct gl_vertex_array_object *vao,
291             const struct gl_buffer_object *bo, GLintptr buffer_offset,
292             GLuint stride, GLbitfield64 vao_enabled,
293             const GLubyte size[VBO_ATTRIB_MAX],
294             const GLenum16 type[VBO_ATTRIB_MAX],
295             const GLuint offset[VBO_ATTRIB_MAX])
296 {
297    if (!vao)
298       return false;
299
300    /* If the enabled arrays are not the same we are not equal. */
301    if (vao_enabled != vao->Enabled)
302       return false;
303
304    /* Check the buffer binding at 0 */
305    if (vao->BufferBinding[0].BufferObj != bo)
306       return false;
307    /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
308    if (vao->BufferBinding[0].Stride != stride)
309       return false;
310    assert(vao->BufferBinding[0].InstanceDivisor == 0);
311
312    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
313    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
314
315    /* Now check the enabled arrays */
316    GLbitfield mask = vao_enabled;
317    while (mask) {
318       const int attr = u_bit_scan(&mask);
319       const unsigned char vbo_attr = vao_to_vbo_map[attr];
320       const GLenum16 tp = type[vbo_attr];
321       const GLintptr off = offset[vbo_attr] + buffer_offset;
322       const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
323       if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
324          return false;
325       if (attrib->Format.Type != tp)
326          return false;
327       if (attrib->Format.Size != size[vbo_attr])
328          return false;
329       assert(attrib->Format.Format == GL_RGBA);
330       assert(attrib->Format.Normalized == GL_FALSE);
331       assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
332       assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
333       assert(attrib->BufferBindingIndex == 0);
334    }
335
336    return true;
337 }
338
339
340 /* Create or reuse the vao for the vertex processing mode. */
341 static void
342 update_vao(struct gl_context *ctx,
343            gl_vertex_processing_mode mode,
344            struct gl_vertex_array_object **vao,
345            struct gl_buffer_object *bo, GLintptr buffer_offset,
346            GLuint stride, GLbitfield64 vbo_enabled,
347            const GLubyte size[VBO_ATTRIB_MAX],
348            const GLenum16 type[VBO_ATTRIB_MAX],
349            const GLuint offset[VBO_ATTRIB_MAX])
350 {
351    /* Compute the bitmasks of vao_enabled arrays */
352    GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
353
354    /*
355     * Check if we can possibly reuse the exisiting one.
356     * In the long term we should reset them when something changes.
357     */
358    if (compare_vao(mode, *vao, bo, buffer_offset, stride,
359                    vao_enabled, size, type, offset))
360       return;
361
362    /* The initial refcount is 1 */
363    _mesa_reference_vao(ctx, vao, NULL);
364    *vao = _mesa_new_vao(ctx, ~((GLuint)0));
365
366    /*
367     * assert(stride <= ctx->Const.MaxVertexAttribStride);
368     * MaxVertexAttribStride is not set for drivers that does not
369     * expose GL 44 or GLES 31.
370     */
371
372    /* Bind the buffer object at binding point 0 */
373    _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
374                             false);
375
376    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
377     * Note that the position/generic0 aliasing is done in the VAO.
378     */
379    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
380    /* Now set the enable arrays */
381    GLbitfield mask = vao_enabled;
382    while (mask) {
383       const int vao_attr = u_bit_scan(&mask);
384       const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
385       assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
386
387       _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
388                              size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
389       _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
390    }
391    _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
392    assert(vao_enabled == (*vao)->Enabled);
393    assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
394
395    /* Finalize and freeze the VAO */
396    _mesa_set_vao_immutable(ctx, *vao);
397 }
398
399
400 static void
401 realloc_storage(struct gl_context *ctx, int prim_count, int vertex_count)
402 {
403    struct vbo_save_context *save = &vbo_context(ctx)->save;
404    if (vertex_count >= 0) {
405       /* Release old reference:
406        */
407       free_vertex_store(ctx, save->vertex_store);
408       save->vertex_store = NULL;
409       /* When we have a new vbo, we will for sure need a new vao */
410       for (gl_vertex_processing_mode vpm = 0; vpm < VP_MODE_MAX; ++vpm)
411          _mesa_reference_vao(ctx, &save->VAO[vpm], NULL);
412
413       /* Allocate and map new store:
414        */
415       save->vertex_store = alloc_vertex_store(ctx, vertex_count);
416    }
417
418    if (prim_count >= 0)
419       save->prim_store = realloc_prim_store(save->prim_store, prim_count);
420 }
421
422 struct vertex_key {
423    unsigned vertex_size;
424    fi_type *vertex_attributes;
425 };
426
427 static uint32_t _hash_vertex_key(const void *key)
428 {
429    struct vertex_key *k = (struct vertex_key*)key;
430    unsigned sz = k->vertex_size;
431    assert(sz);
432    return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float));
433 }
434
435 static bool _compare_vertex_key(const void *key1, const void *key2)
436 {
437    struct vertex_key *k1 = (struct vertex_key*)key1;
438    struct vertex_key *k2 = (struct vertex_key*)key2;
439    /* All the compared vertices are going to be drawn with the same VAO,
440     * so we can compare the attributes. */
441    assert (k1->vertex_size == k2->vertex_size);
442    return memcmp(k1->vertex_attributes,
443                  k2->vertex_attributes,
444                  k1->vertex_size * sizeof(float)) == 0;
445 }
446
447 static void _free_entry(struct hash_entry *entry)
448 {
449    free((void*)entry->key);
450 }
451
452 /* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate
453  * of an existing vertex, return the original index instead.
454  */
455 static uint32_t
456 add_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index,
457            uint32_t index, fi_type *new_buffer, uint32_t *max_index)
458 {
459    /* If vertex deduplication is disabled return the original index. */
460    if (!hash_to_index)
461       return index;
462
463    fi_type *vert = save->vertex_store->buffer_in_ram + save->vertex_size * index;
464
465    struct vertex_key *key = malloc(sizeof(struct vertex_key));
466    key->vertex_size = save->vertex_size;
467    key->vertex_attributes = vert;
468
469    struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key);
470    if (entry) {
471       free(key);
472       /* We found an existing vertex with the same hash, return its index. */
473       return (uintptr_t) entry->data;
474    } else {
475       /* This is a new vertex. Determine a new index and copy its attributes to the vertex
476        * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices
477        * starting at index 0.
478        */
479       uint32_t n = _mesa_hash_table_num_entries(hash_to_index);
480       *max_index = MAX2(n, *max_index);
481
482       memcpy(&new_buffer[save->vertex_size * n],
483              vert,
484              save->vertex_size * sizeof(fi_type));
485
486       _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n));
487
488       /* The index buffer is shared between list compilations, so add the base index to get
489        * the final index.
490        */
491       return n;
492    }
493 }
494
495
496 /**
497  * Insert the active immediate struct onto the display list currently
498  * being built.
499  */
500 static void
501 compile_vertex_list(struct gl_context *ctx)
502 {
503    struct vbo_save_context *save = &vbo_context(ctx)->save;
504    struct vbo_save_vertex_list *node;
505
506    /* Allocate space for this structure in the display list currently
507     * being compiled.
508     */
509    node = (struct vbo_save_vertex_list *)
510       _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update);
511
512    if (!node)
513       return;
514
515    memset(node, 0, sizeof(struct vbo_save_vertex_list));
516    node->cold = calloc(1, sizeof(*node->cold));
517
518    /* Make sure the pointer is aligned to the size of a pointer */
519    assert((GLintptr) node % sizeof(void *) == 0);
520
521    const GLsizei stride = save->vertex_size*sizeof(GLfloat);
522
523    node->cold->vertex_count = save->vert_count;
524    node->cold->wrap_count = save->copied.nr;
525    node->cold->prims = malloc(sizeof(struct _mesa_prim) * save->prim_store->used);
526    memcpy(node->cold->prims, save->prim_store->prims, sizeof(struct _mesa_prim) * save->prim_store->used);
527    node->cold->ib.obj = NULL;
528    node->cold->prim_count = save->prim_store->used;
529
530    if (save->no_current_update) {
531       node->cold->current_data = NULL;
532    }
533    else {
534       GLuint current_size = save->vertex_size - save->attrsz[0];
535       node->cold->current_data = NULL;
536
537       if (current_size) {
538          node->cold->current_data = malloc(current_size * sizeof(GLfloat));
539          if (node->cold->current_data) {
540             const char *buffer = (const char *)save->vertex_store->buffer_in_ram;
541             unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
542             unsigned vertex_offset = 0;
543
544             if (node->cold->vertex_count)
545                vertex_offset = (node->cold->vertex_count - 1) * stride;
546
547             memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
548                    current_size * sizeof(GLfloat));
549          } else {
550             _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
551          }
552       }
553    }
554
555    assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
556
557    if (save->dangling_attr_ref)
558       ctx->ListState.Current.UseLoopback = true;
559
560    /* Copy duplicated vertices
561     */
562    save->copied.nr = copy_vertices(ctx, node, save->vertex_store->buffer_in_ram);
563
564    if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
565       convert_line_loop_to_strip(save, node);
566    }
567
568    merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
569
570    GLintptr buffer_offset = 0;
571    GLuint start_offset = 0;
572
573    /* Create an index buffer. */
574    node->cold->min_index = node->cold->max_index = 0;
575    if (save->vert_count == 0 || node->cold->prim_count == 0)
576       goto end;
577
578    /* We won't modify node->prims, so use a const alias to avoid unintended
579     * writes to it. */
580    const struct _mesa_prim *original_prims = node->cold->prims;
581
582    int end = original_prims[node->cold->prim_count - 1].start +
583              original_prims[node->cold->prim_count - 1].count;
584    int total_vert_count = end - original_prims[0].start;
585
586    node->cold->min_index = node->cold->prims[0].start;
587    node->cold->max_index = end - 1;
588
589    /* Estimate for the worst case: all prims are line strips (the +1 is because
590     * wrap_buffers may call use but the last primitive may not be complete) */
591    int max_indices_count = MAX2(total_vert_count * 2 - (node->cold->prim_count * 2) + 1,
592                                 total_vert_count);
593
594    int size = max_indices_count * sizeof(uint32_t);
595    uint32_t* indices = (uint32_t*) malloc(size);
596    struct _mesa_prim *merged_prims = NULL;
597
598    int idx = 0;
599    struct hash_table *vertex_to_index = NULL;
600    fi_type *temp_vertices_buffer = NULL;
601
602    /* The loopback replay code doesn't use the index buffer, so we can't
603     * dedup vertices in this case.
604     */
605    if (!ctx->ListState.Current.UseLoopback) {
606       vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
607       temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
608    }
609
610    uint32_t max_index = 0;
611
612    int last_valid_prim = -1;
613    /* Construct indices array. */
614    for (unsigned i = 0; i < node->cold->prim_count; i++) {
615       assert(original_prims[i].basevertex == 0);
616       GLubyte mode = original_prims[i].mode;
617
618       int vertex_count = original_prims[i].count;
619       if (!vertex_count) {
620          continue;
621       }
622
623       /* Line strips may get converted to lines */
624       if (mode == GL_LINE_STRIP)
625          mode = GL_LINES;
626
627       /* If 2 consecutive prims use the same mode => merge them. */
628       bool merge_prims = last_valid_prim >= 0 &&
629                          mode == merged_prims[last_valid_prim].mode &&
630                          mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
631                          mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
632                          mode != GL_PATCHES;
633
634       /* To be able to merge consecutive triangle strips we need to insert
635        * a degenerate triangle.
636        */
637       if (merge_prims &&
638           mode == GL_TRIANGLE_STRIP) {
639          /* Insert a degenerate triangle */
640          assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
641          unsigned tri_count = merged_prims[last_valid_prim].count - 2;
642
643          indices[idx] = indices[idx - 1];
644          indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start,
645                                        temp_vertices_buffer, &max_index);
646          idx += 2;
647          merged_prims[last_valid_prim].count += 2;
648
649          if (tri_count % 2) {
650             /* Add another index to preserve winding order */
651             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start,
652                                         temp_vertices_buffer, &max_index);
653             merged_prims[last_valid_prim].count++;
654          }
655       }
656
657       int start = idx;
658
659       /* Convert line strips to lines if it'll allow if the previous
660        * prim mode is GL_LINES (so merge_prims is true) or if the next
661        * primitive mode is GL_LINES or GL_LINE_LOOP.
662        */
663       if (original_prims[i].mode == GL_LINE_STRIP &&
664           (merge_prims ||
665            (i < node->cold->prim_count - 1 &&
666             (original_prims[i + 1].mode == GL_LINE_STRIP ||
667              original_prims[i + 1].mode == GL_LINES)))) {
668          for (unsigned j = 0; j < vertex_count; j++) {
669             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
670                                         temp_vertices_buffer, &max_index);
671             /* Repeat all but the first/last indices. */
672             if (j && j != vertex_count - 1) {
673                indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
674                                            temp_vertices_buffer, &max_index);
675             }
676          }
677       } else {
678          /* We didn't convert to LINES, so restore the original mode */
679          mode = original_prims[i].mode;
680
681          for (unsigned j = 0; j < vertex_count; j++) {
682             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
683                                         temp_vertices_buffer, &max_index);
684          }
685       }
686
687       if (merge_prims) {
688          /* Update vertex count. */
689          merged_prims[last_valid_prim].count += idx - start;
690       } else {
691          /* Keep this primitive */
692          last_valid_prim += 1;
693          assert(last_valid_prim <= i);
694          merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
695          merged_prims[last_valid_prim] = original_prims[i];
696          merged_prims[last_valid_prim].start = start;
697          merged_prims[last_valid_prim].count = idx - start;
698       }
699       merged_prims[last_valid_prim].mode = mode;
700    }
701
702    assert(idx > 0 && idx <= max_indices_count);
703
704    unsigned merged_prim_count = last_valid_prim + 1;
705    node->cold->ib.ptr = NULL;
706    node->cold->ib.count = idx;
707    node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
708
709    /* How many bytes do we need to store the indices and the vertices */
710    total_vert_count = vertex_to_index ? (max_index + 1) : idx;
711    unsigned total_bytes_needed = idx * sizeof(uint32_t) +
712                                  total_vert_count * save->vertex_size * sizeof(fi_type);
713
714    const GLintptr old_offset = save->VAO[0] ?
715       save->VAO[0]->BufferBinding[0].Offset + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset : 0;
716    if (old_offset != save->current_bo_bytes_used && stride > 0) {
717       GLintptr offset_diff = save->current_bo_bytes_used - old_offset;
718       while (offset_diff > 0 &&
719              save->current_bo_bytes_used < save->current_bo->Size &&
720              offset_diff % stride != 0) {
721          save->current_bo_bytes_used++;
722          offset_diff = save->current_bo_bytes_used - old_offset;
723       }
724    }
725    buffer_offset = save->current_bo_bytes_used;
726
727    /* Can we reuse the previous bo or should we allocate a new one? */
728    int available_bytes = save->current_bo ? save->current_bo->Size - save->current_bo_bytes_used : 0;
729    if (total_bytes_needed > available_bytes) {
730       if (save->current_bo)
731          _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
732       save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
733       bool success = ctx->Driver.BufferData(ctx,
734                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
735                                             MAX2(total_bytes_needed, VBO_SAVE_BUFFER_SIZE * sizeof(uint32_t)),
736                                             NULL,
737                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
738                                             save->current_bo);
739       if (!success) {
740          _mesa_reference_buffer_object(ctx, &save->current_bo, NULL);
741          _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
742       } else {
743          save->current_bo_bytes_used = 0;
744          available_bytes = save->current_bo->Size;
745       }
746       buffer_offset = 0;
747    } else {
748       assert(old_offset <= buffer_offset);
749       const GLintptr offset_diff = buffer_offset - old_offset;
750       if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
751          /* The vertex size is an exact multiple of the buffer offset.
752           * This means that we can use zero-based vertex attribute pointers
753           * and specify the start of the primitive with the _mesa_prim::start
754           * field.  This results in issuing several draw calls with identical
755           * vertex attribute information.  This can result in fewer state
756           * changes in drivers.  In particular, the Gallium CSO module will
757           * filter out redundant vertex buffer changes.
758           */
759          /* We cannot immediately update the primitives as some methods below
760           * still need the uncorrected start vertices
761           */
762          start_offset = offset_diff/stride;
763          assert(old_offset == buffer_offset - offset_diff);
764          buffer_offset = old_offset;
765       }
766
767       /* Correct the primitive starts, we can only do this here as copy_vertices
768        * and convert_line_loop_to_strip above consume the uncorrected starts.
769        * On the other hand the _vbo_loopback_vertex_list call below needs the
770        * primitives to be corrected already.
771        */
772       for (unsigned i = 0; i < node->cold->prim_count; i++) {
773          node->cold->prims[i].start += start_offset;
774       }
775       /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have
776        * to apply this transformation to all indices and max_index.
777        */
778       for (unsigned i = 0; i < idx; i++)
779          indices[i] += start_offset;
780       max_index += start_offset;
781    }
782
783    _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->current_bo);
784
785    /* Upload the vertices first (see buffer_offset) */
786    ctx->Driver.BufferSubData(ctx,
787                              save->current_bo_bytes_used,
788                              total_vert_count * save->vertex_size * sizeof(fi_type),
789                              vertex_to_index ? temp_vertices_buffer : save->vertex_store->buffer_in_ram,
790                              node->cold->ib.obj);
791    save->current_bo_bytes_used += total_vert_count * save->vertex_size * sizeof(fi_type);
792
793   if (vertex_to_index) {
794       _mesa_hash_table_destroy(vertex_to_index, _free_entry);
795       free(temp_vertices_buffer);
796    }
797
798    /* Since we're append the indices to an existing buffer, we need to adjust the start value of each
799     * primitive (not the indices themselves). */
800    save->current_bo_bytes_used += align(save->current_bo_bytes_used, 4) - save->current_bo_bytes_used;
801    int indices_offset = save->current_bo_bytes_used / 4;
802    for (int i = 0; i < merged_prim_count; i++) {
803       merged_prims[i].start += indices_offset;
804    }
805
806    /* Then upload the indices. */
807    if (node->cold->ib.obj) {
808       ctx->Driver.BufferSubData(ctx,
809                                 save->current_bo_bytes_used,
810                                 idx * sizeof(uint32_t),
811                                 indices,
812                                 node->cold->ib.obj);
813       save->current_bo_bytes_used += idx * sizeof(uint32_t);
814    } else {
815       node->cold->vertex_count = 0;
816       node->cold->prim_count = 0;
817    }
818
819    /* Prepare for DrawGallium */
820    memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
821    /* The other info fields will be updated in vbo_save_playback_vertex_list */
822    node->merged.info.index_size = 4;
823    node->merged.info.instance_count = 1;
824    node->merged.info.index.gl_bo = node->cold->ib.obj;
825    if (merged_prim_count == 1) {
826       node->merged.info.mode = merged_prims[0].mode;
827       node->merged.start_count.start = merged_prims[0].start;
828       node->merged.start_count.count = merged_prims[0].count;
829       node->merged.start_count.index_bias = 0;
830       node->merged.mode = NULL;
831    } else {
832       node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
833       node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
834       for (unsigned i = 0; i < merged_prim_count; i++) {
835          node->merged.start_counts[i].start = merged_prims[i].start;
836          node->merged.start_counts[i].count = merged_prims[i].count;
837          node->merged.start_counts[i].index_bias = 0;
838          node->merged.mode[i] = merged_prims[i].mode;
839       }
840    }
841    node->merged.num_draws = merged_prim_count;
842    if (node->merged.num_draws > 1) {
843       bool same_mode = true;
844       for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
845          same_mode = node->merged.mode[i] == node->merged.mode[0];
846       }
847       if (same_mode) {
848          /* All primitives use the same mode, so we can simplify a bit */
849          node->merged.info.mode = node->merged.mode[0];
850          free(node->merged.mode);
851          node->merged.mode = NULL;
852       }
853    }
854
855    free(indices);
856    free(merged_prims);
857
858 end:
859
860    if (!save->current_bo) {
861       save->current_bo = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
862       bool success = ctx->Driver.BufferData(ctx,
863                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
864                                             VBO_SAVE_BUFFER_SIZE * sizeof(uint32_t),
865                                             NULL,
866                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
867                                             save->current_bo);
868    }
869
870    GLuint offsets[VBO_ATTRIB_MAX];
871    for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
872       offsets[i] = offset;
873       offset += save->attrsz[i] * sizeof(GLfloat);
874    }
875    /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
876     * Note that this may reuse the previous one of possible.
877     */
878    for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
879       /* create or reuse the vao */
880       update_vao(ctx, vpm, &save->VAO[vpm],
881                  save->current_bo, buffer_offset, stride,
882                  save->enabled, save->attrsz, save->attrtype, offsets);
883       /* Reference the vao in the dlist */
884       node->VAO[vpm] = NULL;
885       _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
886    }
887
888
889    /* Deal with GL_COMPILE_AND_EXECUTE:
890     */
891    if (ctx->ExecuteFlag) {
892       struct _glapi_table *dispatch = GET_DISPATCH();
893
894       _glapi_set_dispatch(ctx->Exec);
895
896       /* _vbo_loopback_vertex_list doesn't use the index buffer, so we have to
897        * use buffer_in_ram instead of current_bo which contains all vertices instead
898        * of the deduplicated vertices only in the !UseLoopback case.
899        *
900        * The problem is that the VAO offset is based on current_bo's layout,
901        * so we have to use a temp value.
902        */
903       struct gl_vertex_array_object *vao = node->VAO[VP_MODE_SHADER];
904       GLintptr original = vao->BufferBinding[0].Offset;
905       if (!ctx->ListState.Current.UseLoopback) {
906          GLintptr new_offset = 0;
907          /* 'start_offset' has been added to all primitives 'start', so undo it here. */
908          new_offset -= start_offset * stride;
909          vao->BufferBinding[0].Offset = new_offset;
910       }
911       _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
912       vao->BufferBinding[0].Offset = original;
913
914       _glapi_set_dispatch(dispatch);
915    }
916
917    /* Decide whether the storage structs are full, or can be used for
918     * the next vertex lists as well.
919     */
920    if (save->vertex_store->used >
921        save->vertex_store->buffer_in_ram_size / sizeof(float) - 16 * (save->vertex_size + 4)) {
922       realloc_storage(ctx, -1, 0);
923    }
924
925    /* Reset our structures for the next run of vertices:
926     */
927    reset_counters(ctx);
928 }
929
930
931 /**
932  * This is called when we fill a vertex buffer before we hit a glEnd().
933  * We
934  * TODO -- If no new vertices have been stored, don't bother saving it.
935  */
936 static void
937 wrap_buffers(struct gl_context *ctx)
938 {
939    struct vbo_save_context *save = &vbo_context(ctx)->save;
940    GLint i = save->prim_store->used - 1;
941    GLenum mode;
942
943    assert(i < (GLint) save->prim_store->size);
944    assert(i >= 0);
945
946    /* Close off in-progress primitive.
947     */
948    save->prim_store->prims[i].count = (save->vert_count - save->prim_store->prims[i].start);
949    mode = save->prim_store->prims[i].mode;
950
951    /* store the copied vertices, and allocate a new list.
952     */
953    compile_vertex_list(ctx);
954
955    /* Restart interrupted primitive
956     */
957    save->prim_store->prims[0].mode = mode;
958    save->prim_store->prims[0].begin = 0;
959    save->prim_store->prims[0].end = 0;
960    save->prim_store->prims[0].start = 0;
961    save->prim_store->prims[0].count = 0;
962    save->prim_store->used = 1;
963 }
964
965
966 /**
967  * Called only when buffers are wrapped as the result of filling the
968  * vertex_store struct.
969  */
970 static void
971 wrap_filled_vertex(struct gl_context *ctx)
972 {
973    struct vbo_save_context *save = &vbo_context(ctx)->save;
974    unsigned numComponents;
975
976    /* Emit a glEnd to close off the last vertex list.
977     */
978    wrap_buffers(ctx);
979
980    /* Copy stored stored vertices to start of new list.
981     */
982    assert(save->max_vert - save->vert_count > save->copied.nr);
983
984    numComponents = save->copied.nr * save->vertex_size;
985
986    fi_type *buffer_ptr = save->vertex_store->buffer_in_ram;
987    memcpy(buffer_ptr,
988           save->copied.buffer,
989           numComponents * sizeof(fi_type));
990    assert(save->vertex_store->used == 0 && save->vert_count == 0);
991    save->vert_count = save->copied.nr;
992    save->vertex_store->used = numComponents;
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->vertex_store->buffer_in_ram;
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    if (save->out_of_memory) {
1351       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1352    }
1353    else {
1354       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1355    }
1356    ctx->Driver.SaveNeedFlush = GL_FALSE;
1357 }
1358
1359
1360 static void GLAPIENTRY
1361 _save_EvalCoord1f(GLfloat u)
1362 {
1363    GET_CURRENT_CONTEXT(ctx);
1364    dlist_fallback(ctx);
1365    CALL_EvalCoord1f(ctx->Save, (u));
1366 }
1367
1368 static void GLAPIENTRY
1369 _save_EvalCoord1fv(const GLfloat * v)
1370 {
1371    GET_CURRENT_CONTEXT(ctx);
1372    dlist_fallback(ctx);
1373    CALL_EvalCoord1fv(ctx->Save, (v));
1374 }
1375
1376 static void GLAPIENTRY
1377 _save_EvalCoord2f(GLfloat u, GLfloat v)
1378 {
1379    GET_CURRENT_CONTEXT(ctx);
1380    dlist_fallback(ctx);
1381    CALL_EvalCoord2f(ctx->Save, (u, v));
1382 }
1383
1384 static void GLAPIENTRY
1385 _save_EvalCoord2fv(const GLfloat * v)
1386 {
1387    GET_CURRENT_CONTEXT(ctx);
1388    dlist_fallback(ctx);
1389    CALL_EvalCoord2fv(ctx->Save, (v));
1390 }
1391
1392 static void GLAPIENTRY
1393 _save_EvalPoint1(GLint i)
1394 {
1395    GET_CURRENT_CONTEXT(ctx);
1396    dlist_fallback(ctx);
1397    CALL_EvalPoint1(ctx->Save, (i));
1398 }
1399
1400 static void GLAPIENTRY
1401 _save_EvalPoint2(GLint i, GLint j)
1402 {
1403    GET_CURRENT_CONTEXT(ctx);
1404    dlist_fallback(ctx);
1405    CALL_EvalPoint2(ctx->Save, (i, j));
1406 }
1407
1408 static void GLAPIENTRY
1409 _save_CallList(GLuint l)
1410 {
1411    GET_CURRENT_CONTEXT(ctx);
1412    dlist_fallback(ctx);
1413    CALL_CallList(ctx->Save, (l));
1414 }
1415
1416 static void GLAPIENTRY
1417 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1418 {
1419    GET_CURRENT_CONTEXT(ctx);
1420    dlist_fallback(ctx);
1421    CALL_CallLists(ctx->Save, (n, type, v));
1422 }
1423
1424
1425
1426 /**
1427  * Called when a glBegin is getting compiled into a display list.
1428  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1429  */
1430 void
1431 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1432                      bool no_current_update)
1433 {
1434    struct vbo_save_context *save = &vbo_context(ctx)->save;
1435    const GLuint i = save->prim_store->used++;
1436
1437    ctx->Driver.CurrentSavePrimitive = mode;
1438
1439    assert(i < save->prim_store->size);
1440    save->prim_store->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1441    save->prim_store->prims[i].begin = 1;
1442    save->prim_store->prims[i].end = 0;
1443    save->prim_store->prims[i].start = save->vert_count;
1444    save->prim_store->prims[i].count = 0;
1445
1446    save->no_current_update = no_current_update;
1447
1448    if (save->out_of_memory) {
1449       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1450    }
1451    else {
1452       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1453    }
1454
1455    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1456    ctx->Driver.SaveNeedFlush = GL_TRUE;
1457 }
1458
1459
1460 static void GLAPIENTRY
1461 _save_End(void)
1462 {
1463    GET_CURRENT_CONTEXT(ctx);
1464    struct vbo_save_context *save = &vbo_context(ctx)->save;
1465    const GLint i = save->prim_store->used - 1;
1466
1467    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1468    save->prim_store->prims[i].end = 1;
1469    save->prim_store->prims[i].count = (save->vert_count - save->prim_store->prims[i].start);
1470
1471    if (i == (GLint) save->prim_store->size - 1) {
1472       compile_vertex_list(ctx);
1473       assert(save->copied.nr == 0);
1474    }
1475
1476    /* Swap out this vertex format while outside begin/end.  Any color,
1477     * etc. received between here and the next begin will be compiled
1478     * as opcodes.
1479     */
1480    if (save->out_of_memory) {
1481       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1482    }
1483    else {
1484       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1485    }
1486 }
1487
1488
1489 static void GLAPIENTRY
1490 _save_Begin(GLenum mode)
1491 {
1492    GET_CURRENT_CONTEXT(ctx);
1493    (void) mode;
1494    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1495 }
1496
1497
1498 static void GLAPIENTRY
1499 _save_PrimitiveRestartNV(void)
1500 {
1501    GET_CURRENT_CONTEXT(ctx);
1502    struct vbo_save_context *save = &vbo_context(ctx)->save;
1503
1504    if (save->prim_store->used == 0) {
1505       /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1506        * is an error.
1507        */
1508       _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1509                           "glPrimitiveRestartNV called outside glBegin/End");
1510    } else {
1511       /* get current primitive mode */
1512       GLenum curPrim = save->prim_store->prims[save->prim_store->used - 1].mode;
1513       bool no_current_update = save->no_current_update;
1514
1515       /* restart primitive */
1516       CALL_End(ctx->CurrentServerDispatch, ());
1517       vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1518    }
1519 }
1520
1521
1522 /* Unlike the functions above, these are to be hooked into the vtxfmt
1523  * maintained in ctx->ListState, active when the list is known or
1524  * suspected to be outside any begin/end primitive.
1525  * Note: OBE = Outside Begin/End
1526  */
1527 static void GLAPIENTRY
1528 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1529 {
1530    GET_CURRENT_CONTEXT(ctx);
1531    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1532
1533    vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1534    CALL_Vertex2f(dispatch, (x1, y1));
1535    CALL_Vertex2f(dispatch, (x2, y1));
1536    CALL_Vertex2f(dispatch, (x2, y2));
1537    CALL_Vertex2f(dispatch, (x1, y2));
1538    CALL_End(dispatch, ());
1539 }
1540
1541
1542 static void GLAPIENTRY
1543 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1544 {
1545    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1546 }
1547
1548 static void GLAPIENTRY
1549 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1550 {
1551    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1552 }
1553
1554 static void GLAPIENTRY
1555 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1556 {
1557    _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1558 }
1559
1560 static void GLAPIENTRY
1561 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1562 {
1563    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1564 }
1565
1566 static void GLAPIENTRY
1567 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1568 {
1569    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1570 }
1571
1572 static void GLAPIENTRY
1573 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1574 {
1575    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1576 }
1577
1578 static void GLAPIENTRY
1579 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1580 {
1581    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1582 }
1583
1584 static void
1585 _ensure_draws_fits_in_storage(struct gl_context *ctx, int primcount, int vertcount)
1586 {
1587    struct vbo_save_context *save = &vbo_context(ctx)->save;
1588
1589    bool realloc_prim = save->prim_store->used + primcount > save->prim_store->size;
1590    bool realloc_vert = save->vertex_size && (save->vert_count + vertcount >= save->max_vert);
1591
1592    if (realloc_prim || realloc_vert) {
1593       if (realloc_vert && (save->vert_count || save->prim_store->used)) {
1594          /* TODO: this really isn't needed. We should realloc only the CPU-side memory. */
1595          compile_vertex_list(ctx);
1596       }
1597       realloc_storage(ctx, realloc_prim ? primcount : -1, realloc_vert ? vertcount : -1);
1598    }
1599 }
1600
1601
1602 static void GLAPIENTRY
1603 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1604 {
1605    GET_CURRENT_CONTEXT(ctx);
1606    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1607    struct vbo_save_context *save = &vbo_context(ctx)->save;
1608    GLint i;
1609
1610    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1611       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1612       return;
1613    }
1614    if (count < 0) {
1615       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1616       return;
1617    }
1618
1619    if (save->out_of_memory)
1620       return;
1621
1622    _ensure_draws_fits_in_storage(ctx, 1, count);
1623
1624    /* Make sure to process any VBO binding changes */
1625    _mesa_update_state(ctx);
1626
1627    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1628
1629    vbo_save_NotifyBegin(ctx, mode, true);
1630
1631    for (i = 0; i < count; i++)
1632       _mesa_array_element(ctx, start + i);
1633    CALL_End(ctx->CurrentServerDispatch, ());
1634
1635    _mesa_vao_unmap_arrays(ctx, vao);
1636 }
1637
1638
1639 static void GLAPIENTRY
1640 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1641                           const GLsizei *count, GLsizei primcount)
1642 {
1643    GET_CURRENT_CONTEXT(ctx);
1644    GLint i;
1645
1646    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1647       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1648       return;
1649    }
1650
1651    if (primcount < 0) {
1652       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1653                           "glMultiDrawArrays(primcount<0)");
1654       return;
1655    }
1656
1657    unsigned vertcount = 0;
1658    for (i = 0; i < primcount; i++) {
1659       if (count[i] < 0) {
1660          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1661                              "glMultiDrawArrays(count[i]<0)");
1662          return;
1663       }
1664       vertcount += count[i];
1665    }
1666
1667    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1668
1669    for (i = 0; i < primcount; i++) {
1670       if (count[i] > 0) {
1671          _save_OBE_DrawArrays(mode, first[i], count[i]);
1672       }
1673    }
1674 }
1675
1676
1677 static void
1678 array_element(struct gl_context *ctx,
1679               GLint basevertex, GLuint elt, unsigned index_size_shift)
1680 {
1681    /* Section 10.3.5 Primitive Restart:
1682     * [...]
1683     *    When one of the *BaseVertex drawing commands specified in section 10.5
1684     * is used, the primitive restart comparison occurs before the basevertex
1685     * offset is added to the array index.
1686     */
1687    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1688     * then we call PrimitiveRestartNV and return.
1689     */
1690    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1691        elt == ctx->Array._RestartIndex[index_size_shift]) {
1692       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1693       return;
1694    }
1695
1696    _mesa_array_element(ctx, basevertex + elt);
1697 }
1698
1699
1700 /* Could do better by copying the arrays and element list intact and
1701  * then emitting an indexed prim at runtime.
1702  */
1703 static void GLAPIENTRY
1704 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1705                                  const GLvoid * indices, GLint basevertex)
1706 {
1707    GET_CURRENT_CONTEXT(ctx);
1708    struct vbo_save_context *save = &vbo_context(ctx)->save;
1709    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1710    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1711    GLint i;
1712
1713    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1714       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1715       return;
1716    }
1717    if (count < 0) {
1718       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1719       return;
1720    }
1721    if (type != GL_UNSIGNED_BYTE &&
1722        type != GL_UNSIGNED_SHORT &&
1723        type != GL_UNSIGNED_INT) {
1724       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1725       return;
1726    }
1727
1728    if (save->out_of_memory)
1729       return;
1730
1731    _ensure_draws_fits_in_storage(ctx, 1, count);
1732
1733    /* Make sure to process any VBO binding changes */
1734    _mesa_update_state(ctx);
1735
1736    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1737
1738    if (indexbuf)
1739       indices =
1740          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1741
1742    vbo_save_NotifyBegin(ctx, mode, true);
1743
1744    switch (type) {
1745    case GL_UNSIGNED_BYTE:
1746       for (i = 0; i < count; i++)
1747          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1748       break;
1749    case GL_UNSIGNED_SHORT:
1750       for (i = 0; i < count; i++)
1751          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1752       break;
1753    case GL_UNSIGNED_INT:
1754       for (i = 0; i < count; i++)
1755          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1756       break;
1757    default:
1758       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1759       break;
1760    }
1761
1762    CALL_End(ctx->CurrentServerDispatch, ());
1763
1764    _mesa_vao_unmap(ctx, vao);
1765 }
1766
1767 static void GLAPIENTRY
1768 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1769                        const GLvoid * indices)
1770 {
1771    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1772 }
1773
1774
1775 static void GLAPIENTRY
1776 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1777                             GLsizei count, GLenum type,
1778                             const GLvoid * indices)
1779 {
1780    GET_CURRENT_CONTEXT(ctx);
1781    struct vbo_save_context *save = &vbo_context(ctx)->save;
1782
1783    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1784       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1785       return;
1786    }
1787    if (count < 0) {
1788       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1789                           "glDrawRangeElements(count<0)");
1790       return;
1791    }
1792    if (type != GL_UNSIGNED_BYTE &&
1793        type != GL_UNSIGNED_SHORT &&
1794        type != GL_UNSIGNED_INT) {
1795       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1796       return;
1797    }
1798    if (end < start) {
1799       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1800                           "glDrawRangeElements(end < start)");
1801       return;
1802    }
1803
1804    if (save->out_of_memory)
1805       return;
1806
1807    _save_OBE_DrawElements(mode, count, type, indices);
1808 }
1809
1810
1811 static void GLAPIENTRY
1812 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1813                             const GLvoid * const *indices, GLsizei primcount)
1814 {
1815    GET_CURRENT_CONTEXT(ctx);
1816    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1817    GLsizei i;
1818
1819    int vertcount = 0;
1820    for (i = 0; i < primcount; i++) {
1821       vertcount += count[i];
1822    }
1823    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1824
1825    for (i = 0; i < primcount; i++) {
1826       if (count[i] > 0) {
1827          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1828       }
1829    }
1830 }
1831
1832
1833 static void GLAPIENTRY
1834 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1835                                       GLenum type,
1836                                       const GLvoid * const *indices,
1837                                       GLsizei primcount,
1838                                       const GLint *basevertex)
1839 {
1840    GET_CURRENT_CONTEXT(ctx);
1841    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1842    GLsizei i;
1843
1844    int vertcount = 0;
1845    for (i = 0; i < primcount; i++) {
1846       vertcount += count[i];
1847    }
1848    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1849
1850    for (i = 0; i < primcount; i++) {
1851       if (count[i] > 0) {
1852          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1853                                                       indices[i],
1854                                                       basevertex[i]));
1855       }
1856    }
1857 }
1858
1859
1860 static void
1861 vtxfmt_init(struct gl_context *ctx)
1862 {
1863    struct vbo_save_context *save = &vbo_context(ctx)->save;
1864    GLvertexformat *vfmt = &save->vtxfmt;
1865
1866 #define NAME_AE(x) _ae_##x
1867 #define NAME_CALLLIST(x) _save_##x
1868 #define NAME(x) _save_##x
1869 #define NAME_ES(x) _save_##x##ARB
1870
1871 #include "vbo_init_tmp.h"
1872 }
1873
1874
1875 /**
1876  * Initialize the dispatch table with the VBO functions for display
1877  * list compilation.
1878  */
1879 void
1880 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1881                              struct _glapi_table *exec)
1882 {
1883    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1884    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1885    SET_DrawElements(exec, _save_OBE_DrawElements);
1886    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1887    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1888    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1889    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1890    SET_Rectf(exec, _save_OBE_Rectf);
1891    SET_Rectd(exec, _save_OBE_Rectd);
1892    SET_Rectdv(exec, _save_OBE_Rectdv);
1893    SET_Rectfv(exec, _save_OBE_Rectfv);
1894    SET_Recti(exec, _save_OBE_Recti);
1895    SET_Rectiv(exec, _save_OBE_Rectiv);
1896    SET_Rects(exec, _save_OBE_Rects);
1897    SET_Rectsv(exec, _save_OBE_Rectsv);
1898
1899    /* Note: other glDraw functins aren't compiled into display lists */
1900 }
1901
1902
1903
1904 void
1905 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1906 {
1907    struct vbo_save_context *save = &vbo_context(ctx)->save;
1908
1909    /* Noop when we are actually active:
1910     */
1911    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1912       return;
1913
1914    if (save->vert_count || save->prim_store->used)
1915       compile_vertex_list(ctx);
1916
1917    copy_to_current(ctx);
1918    reset_vertex(ctx);
1919    ctx->Driver.SaveNeedFlush = GL_FALSE;
1920 }
1921
1922
1923 /**
1924  * Called from glNewList when we're starting to compile a display list.
1925  */
1926 void
1927 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1928 {
1929    struct vbo_save_context *save = &vbo_context(ctx)->save;
1930
1931    (void) list;
1932    (void) mode;
1933
1934    if (!save->prim_store)
1935       save->prim_store = realloc_prim_store(NULL, 8);
1936
1937    if (!save->vertex_store)
1938       save->vertex_store = alloc_vertex_store(ctx, 0);
1939
1940    reset_vertex(ctx);
1941    ctx->Driver.SaveNeedFlush = GL_FALSE;
1942 }
1943
1944
1945 /**
1946  * Called from glEndList when we're finished compiling a display list.
1947  */
1948 void
1949 vbo_save_EndList(struct gl_context *ctx)
1950 {
1951    struct vbo_save_context *save = &vbo_context(ctx)->save;
1952
1953    /* EndList called inside a (saved) Begin/End pair?
1954     */
1955    if (_mesa_inside_dlist_begin_end(ctx)) {
1956       if (save->prim_store->used > 0) {
1957          GLint i = save->prim_store->used - 1;
1958          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1959          save->prim_store->prims[i].end = 0;
1960          save->prim_store->prims[i].count = save->vert_count - save->prim_store->prims[i].start;
1961       }
1962
1963       /* Make sure this vertex list gets replayed by the "loopback"
1964        * mechanism:
1965        */
1966       save->dangling_attr_ref = GL_TRUE;
1967       vbo_save_SaveFlushVertices(ctx);
1968
1969       /* Swap out this vertex format while outside begin/end.  Any color,
1970        * etc. received between here and the next begin will be compiled
1971        * as opcodes.
1972        */
1973       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1974    }
1975
1976    assert(save->vertex_size == 0);
1977 }
1978
1979 /**
1980  * Called during context creation/init.
1981  */
1982 static void
1983 current_init(struct gl_context *ctx)
1984 {
1985    struct vbo_save_context *save = &vbo_context(ctx)->save;
1986    GLint i;
1987
1988    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
1989       const GLuint j = i - VBO_ATTRIB_POS;
1990       assert(j < VERT_ATTRIB_MAX);
1991       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1992       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1993    }
1994
1995    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1996       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1997       assert(j < MAT_ATTRIB_MAX);
1998       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1999       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2000    }
2001 }
2002
2003
2004 /**
2005  * Initialize the display list compiler.  Called during context creation.
2006  */
2007 void
2008 vbo_save_api_init(struct vbo_save_context *save)
2009 {
2010    struct gl_context *ctx = gl_context_from_vbo_save(save);
2011
2012    vtxfmt_init(ctx);
2013    current_init(ctx);
2014    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop);
2015 }