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