vbo/dlist: apply start_offset after indices construction
[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    /* Duplicate our template, increment refcounts to the storage structs:
552     */
553    GLintptr old_offset = 0;
554    if (save->VAO[0]) {
555       old_offset = save->VAO[0]->BufferBinding[0].Offset
556          + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset;
557    }
558    const GLsizei stride = save->vertex_size*sizeof(GLfloat);
559    GLintptr buffer_offset =
560        (save->buffer_map - save->vertex_store->buffer_in_ram) * sizeof(GLfloat);
561    const GLintptr original_buffer_offset = buffer_offset;
562    assert(old_offset <= buffer_offset);
563    const GLintptr offset_diff = buffer_offset - old_offset;
564    GLuint start_offset = 0;
565    if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
566       /* The vertex size is an exact multiple of the buffer offset.
567        * This means that we can use zero-based vertex attribute pointers
568        * and specify the start of the primitive with the _mesa_prim::start
569        * field.  This results in issuing several draw calls with identical
570        * vertex attribute information.  This can result in fewer state
571        * changes in drivers.  In particular, the Gallium CSO module will
572        * filter out redundant vertex buffer changes.
573        */
574       /* We cannot immediately update the primitives as some methods below
575        * still need the uncorrected start vertices
576        */
577       start_offset = offset_diff/stride;
578       assert(old_offset == buffer_offset - offset_diff);
579       buffer_offset = old_offset;
580    }
581    GLuint offsets[VBO_ATTRIB_MAX];
582    for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
583       offsets[i] = offset;
584       offset += save->attrsz[i] * sizeof(GLfloat);
585    }
586    node->cold->vertex_count = save->vert_count;
587    node->cold->wrap_count = save->copied.nr;
588    node->cold->prims = save->prims;
589    node->cold->ib.obj = NULL;
590    node->cold->prim_count = save->prim_count;
591    node->cold->prim_store = save->prim_store;
592
593    /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
594     * Note that this may reuse the previous one of possible.
595     */
596    for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
597       /* create or reuse the vao */
598       update_vao(ctx, vpm, &save->VAO[vpm],
599                  save->vertex_store->bufferobj, buffer_offset, stride,
600                  save->enabled, save->attrsz, save->attrtype, offsets);
601       /* Reference the vao in the dlist */
602       node->VAO[vpm] = NULL;
603       _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
604    }
605
606    node->cold->prim_store->refcount++;
607
608    if (save->no_current_update) {
609       node->cold->current_data = NULL;
610    }
611    else {
612       GLuint current_size = save->vertex_size - save->attrsz[0];
613       node->cold->current_data = NULL;
614
615       if (current_size) {
616          node->cold->current_data = malloc(current_size * sizeof(GLfloat));
617          if (node->cold->current_data) {
618             const char *buffer = (const char *)save->buffer_map;
619             unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
620             unsigned vertex_offset = 0;
621
622             if (node->cold->vertex_count)
623                vertex_offset = (node->cold->vertex_count - 1) * stride;
624
625             memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
626                    current_size * sizeof(GLfloat));
627          } else {
628             _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
629          }
630       }
631    }
632
633    assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
634
635    if (save->dangling_attr_ref)
636       ctx->ListState.Current.UseLoopback = true;
637
638    save->vertex_store->used += save->vertex_size * node->cold->vertex_count;
639    save->prim_store->used += node->cold->prim_count;
640
641    /* Copy duplicated vertices
642     */
643    save->copied.nr = copy_vertices(ctx, node, save->buffer_map);
644
645    if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
646       convert_line_loop_to_strip(save, node);
647    }
648
649    merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
650
651    /* Create an index buffer. */
652    node->cold->min_index = node->cold->max_index = 0;
653    if (save->vert_count == 0 || save->prim_count == 0)
654       goto end;
655
656    /* We won't modify node->prims, so use a const alias to avoid unintended
657     * writes to it. */
658    const struct _mesa_prim *original_prims = node->cold->prims;
659
660    int end = original_prims[node->cold->prim_count - 1].start +
661              original_prims[node->cold->prim_count - 1].count;
662    int total_vert_count = end - original_prims[0].start;
663
664    node->cold->min_index = node->cold->prims[0].start;
665    node->cold->max_index = end - 1;
666
667    /* Estimate for the worst case: all prims are line strips (the +1 is because
668     * wrap_buffers may call use but the last primitive may not be complete) */
669    int max_indices_count = MAX2(total_vert_count * 2 - (node->cold->prim_count * 2) + 1,
670                                 total_vert_count);
671
672    int indices_offset = 0;
673    int available = save->previous_ib ? (save->previous_ib->Size / 4 - save->ib_first_free_index) : 0;
674    if (available >= max_indices_count) {
675       indices_offset = save->ib_first_free_index;
676    }
677    int size = max_indices_count * sizeof(uint32_t);
678    uint32_t* indices = (uint32_t*) malloc(size);
679    struct _mesa_prim *merged_prims = NULL;
680
681    int idx = 0;
682    struct hash_table *vertex_to_index = NULL;
683    fi_type *temp_vertices_buffer = NULL;
684
685    /* The loopback replay code doesn't use the index buffer, so we can't
686     * dedup vertices in this case.
687     */
688    if (!ctx->ListState.Current.UseLoopback) {
689       vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
690       temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
691    }
692
693    uint32_t max_index = 0;
694
695    int last_valid_prim = -1;
696    /* Construct indices array. */
697    for (unsigned i = 0; i < node->cold->prim_count; i++) {
698       assert(original_prims[i].basevertex == 0);
699       GLubyte mode = original_prims[i].mode;
700
701       int vertex_count = original_prims[i].count;
702       if (!vertex_count) {
703          continue;
704       }
705
706       /* Line strips may get converted to lines */
707       if (mode == GL_LINE_STRIP)
708          mode = GL_LINES;
709
710       /* If 2 consecutive prims use the same mode => merge them. */
711       bool merge_prims = last_valid_prim >= 0 &&
712                          mode == merged_prims[last_valid_prim].mode &&
713                          mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
714                          mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
715                          mode != GL_PATCHES;
716
717       /* To be able to merge consecutive triangle strips we need to insert
718        * a degenerate triangle.
719        */
720       if (merge_prims &&
721           mode == GL_TRIANGLE_STRIP) {
722          /* Insert a degenerate triangle */
723          assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
724          unsigned tri_count = merged_prims[last_valid_prim].count - 2;
725
726          indices[idx] = indices[idx - 1];
727          indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start,
728                                        temp_vertices_buffer, &max_index);
729          idx += 2;
730          merged_prims[last_valid_prim].count += 2;
731
732          if (tri_count % 2) {
733             /* Add another index to preserve winding order */
734             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start,
735                                         temp_vertices_buffer, &max_index);
736             merged_prims[last_valid_prim].count++;
737          }
738       }
739
740       int start = idx;
741
742       /* Convert line strips to lines if it'll allow if the previous
743        * prim mode is GL_LINES (so merge_prims is true) or if the next
744        * primitive mode is GL_LINES or GL_LINE_LOOP.
745        */
746       if (original_prims[i].mode == GL_LINE_STRIP &&
747           (merge_prims ||
748            (i < node->cold->prim_count - 1 &&
749             (original_prims[i + 1].mode == GL_LINE_STRIP ||
750              original_prims[i + 1].mode == GL_LINES)))) {
751          for (unsigned j = 0; j < vertex_count; j++) {
752             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
753                                         temp_vertices_buffer, &max_index);
754             /* Repeat all but the first/last indices. */
755             if (j && j != vertex_count - 1) {
756                indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
757                                            temp_vertices_buffer, &max_index);
758             }
759          }
760       } else {
761          /* We didn't convert to LINES, so restore the original mode */
762          mode = original_prims[i].mode;
763
764          for (unsigned j = 0; j < vertex_count; j++) {
765             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
766                                         temp_vertices_buffer, &max_index);
767          }
768       }
769
770       if (merge_prims) {
771          /* Update vertex count. */
772          merged_prims[last_valid_prim].count += idx - start;
773       } else {
774          /* Keep this primitive */
775          last_valid_prim += 1;
776          assert(last_valid_prim <= i);
777          merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
778          merged_prims[last_valid_prim] = original_prims[i];
779          merged_prims[last_valid_prim].start = indices_offset + start;
780          merged_prims[last_valid_prim].count = idx - start;
781       }
782       merged_prims[last_valid_prim].mode = mode;
783    }
784
785    assert(idx > 0 && idx <= max_indices_count);
786
787    unsigned merged_prim_count = last_valid_prim + 1;
788    node->cold->ib.ptr = NULL;
789    node->cold->ib.count = idx;
790    node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
791
792    /* Correct the primitive starts, we can only do this here as copy_vertices
793     * and convert_line_loop_to_strip above consume the uncorrected starts.
794     * On the other hand the _vbo_loopback_vertex_list call below needs the
795     * primitives to be corrected already.
796     */
797    for (unsigned i = 0; i < node->cold->prim_count; i++) {
798       node->cold->prims[i].start += start_offset;
799    }
800    /* start_offset shifts vertices (so v[0] becomes v[start_offset]), so we have
801     * to apply this transformation to all indices and max_index.
802     */
803    for (unsigned i = 0; i < idx; i++)
804       indices[i] += start_offset;
805    max_index += start_offset;
806
807    if (!indices_offset) {
808       /* Allocate a new index buffer */
809       _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
810       save->previous_ib = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
811       bool success = ctx->Driver.BufferData(ctx,
812                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
813                                             MAX2(VBO_SAVE_INDEX_SIZE, idx) * sizeof(uint32_t),
814                                             NULL,
815                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
816                                             save->previous_ib);
817       if (!success) {
818          _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
819          _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
820       }
821    }
822
823    _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->previous_ib);
824
825    if (node->cold->ib.obj) {
826       ctx->Driver.BufferSubData(ctx,
827                                 indices_offset * sizeof(uint32_t),
828                                 idx * sizeof(uint32_t),
829                                 indices,
830                                 node->cold->ib.obj);
831       save->ib_first_free_index = indices_offset + idx;
832    } else {
833       node->cold->vertex_count = 0;
834       node->cold->prim_count = 0;
835    }
836
837
838   if (vertex_to_index) {
839       ctx->Driver.BufferSubData(ctx,
840                                 original_buffer_offset,
841                                 (max_index - start_offset + 1) * save->vertex_size * sizeof(fi_type),
842                                 temp_vertices_buffer,
843                                 save->vertex_store->bufferobj);
844
845       _mesa_hash_table_destroy(vertex_to_index, _free_entry);
846       free(temp_vertices_buffer);
847    } else {
848       ctx->Driver.BufferSubData(ctx,
849                                 original_buffer_offset,
850                                 idx * save->vertex_size * sizeof(fi_type),
851                                 &save->vertex_store->buffer_in_ram[original_buffer_offset / sizeof(float)],
852                                 save->vertex_store->bufferobj);
853    }
854
855    /* Prepare for DrawGallium */
856    memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
857    /* The other info fields will be updated in vbo_save_playback_vertex_list */
858    node->merged.info.index_size = 4;
859    node->merged.info.instance_count = 1;
860    node->merged.info.index.gl_bo = node->cold->ib.obj;
861    if (merged_prim_count == 1) {
862       node->merged.info.mode = merged_prims[0].mode;
863       node->merged.start_count.start = merged_prims[0].start;
864       node->merged.start_count.count = merged_prims[0].count;
865       node->merged.start_count.index_bias = 0;
866       node->merged.mode = NULL;
867    } else {
868       node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
869       node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
870       for (unsigned i = 0; i < merged_prim_count; i++) {
871          node->merged.start_counts[i].start = merged_prims[i].start;
872          node->merged.start_counts[i].count = merged_prims[i].count;
873          node->merged.start_counts[i].index_bias = 0;
874          node->merged.mode[i] = merged_prims[i].mode;
875       }
876    }
877    node->merged.num_draws = merged_prim_count;
878    if (node->merged.num_draws > 1) {
879       bool same_mode = true;
880       for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
881          same_mode = node->merged.mode[i] == node->merged.mode[0];
882       }
883       if (same_mode) {
884          /* All primitives use the same mode, so we can simplify a bit */
885          node->merged.info.mode = node->merged.mode[0];
886          free(node->merged.mode);
887          node->merged.mode = NULL;
888       }
889    }
890
891    free(indices);
892    free(merged_prims);
893
894 end:
895    /* Deal with GL_COMPILE_AND_EXECUTE:
896     */
897    if (ctx->ExecuteFlag) {
898       struct _glapi_table *dispatch = GET_DISPATCH();
899
900       _glapi_set_dispatch(ctx->Exec);
901
902       /* Note that the range of referenced vertices must be mapped already */
903       _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
904
905       _glapi_set_dispatch(dispatch);
906    }
907
908    /* Decide whether the storage structs are full, or can be used for
909     * the next vertex lists as well.
910     */
911    if (save->vertex_store->used >
912        save->vertex_store->bufferobj->Size / sizeof(float) - 16 * (save->vertex_size + 4)) {
913       realloc_storage(ctx, -1, 0);
914    }
915    else {
916       /* update buffer_ptr for next vertex */
917       save->buffer_ptr = save->vertex_store->buffer_in_ram
918          + save->vertex_store->used;
919    }
920
921    if (save->prim_store->used > save->prim_store->size - 6) {
922       realloc_storage(ctx, 0, -1);
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_count - 1;
941    GLenum mode;
942
943    assert(i < (GLint) save->prim_max);
944    assert(i >= 0);
945
946    /* Close off in-progress primitive.
947     */
948    save->prims[i].count = (save->vert_count - save->prims[i].start);
949    mode = save->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->prims[0].mode = mode;
958    save->prims[0].begin = 0;
959    save->prims[0].end = 0;
960    save->prims[0].start = 0;
961    save->prims[0].count = 0;
962    save->prim_count = 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    memcpy(save->buffer_ptr,
986           save->copied.buffer,
987           numComponents * sizeof(fi_type));
988    save->buffer_ptr += numComponents;
989    save->vert_count += save->copied.nr;
990 }
991
992
993 static void
994 copy_to_current(struct gl_context *ctx)
995 {
996    struct vbo_save_context *save = &vbo_context(ctx)->save;
997    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
998
999    while (enabled) {
1000       const int i = u_bit_scan64(&enabled);
1001       assert(save->attrsz[i]);
1002
1003       if (save->attrtype[i] == GL_DOUBLE ||
1004           save->attrtype[i] == GL_UNSIGNED_INT64_ARB)
1005          memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat));
1006       else
1007          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
1008                                      save->attrptr[i], save->attrtype[i]);
1009    }
1010 }
1011
1012
1013 static void
1014 copy_from_current(struct gl_context *ctx)
1015 {
1016    struct vbo_save_context *save = &vbo_context(ctx)->save;
1017    GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1018
1019    while (enabled) {
1020       const int i = u_bit_scan64(&enabled);
1021
1022       switch (save->attrsz[i]) {
1023       case 4:
1024          save->attrptr[i][3] = save->current[i][3];
1025          FALLTHROUGH;
1026       case 3:
1027          save->attrptr[i][2] = save->current[i][2];
1028          FALLTHROUGH;
1029       case 2:
1030          save->attrptr[i][1] = save->current[i][1];
1031          FALLTHROUGH;
1032       case 1:
1033          save->attrptr[i][0] = save->current[i][0];
1034          break;
1035       case 0:
1036          unreachable("Unexpected vertex attribute size");
1037       }
1038    }
1039 }
1040
1041
1042 /**
1043  * Called when we increase the size of a vertex attribute.  For example,
1044  * if we've seen one or more glTexCoord2f() calls and now we get a
1045  * glTexCoord3f() call.
1046  * Flush existing data, set new attrib size, replay copied vertices.
1047  */
1048 static void
1049 upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
1050 {
1051    struct vbo_save_context *save = &vbo_context(ctx)->save;
1052    GLuint oldsz;
1053    GLuint i;
1054    fi_type *tmp;
1055
1056    /* Store the current run of vertices, and emit a GL_END.  Emit a
1057     * BEGIN in the new buffer.
1058     */
1059    if (save->vert_count)
1060       wrap_buffers(ctx);
1061    else
1062       assert(save->copied.nr == 0);
1063
1064    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
1065     * when the attribute already exists in the vertex and is having
1066     * its size increased.
1067     */
1068    copy_to_current(ctx);
1069
1070    /* Fix up sizes:
1071     */
1072    oldsz = save->attrsz[attr];
1073    save->attrsz[attr] = newsz;
1074    save->enabled |= BITFIELD64_BIT(attr);
1075
1076    save->vertex_size += newsz - oldsz;
1077    save->max_vert = ((save->vertex_store->bufferobj->Size / sizeof(float) -
1078                       save->vertex_store->used) /
1079                      save->vertex_size);
1080    save->vert_count = 0;
1081
1082    /* Recalculate all the attrptr[] values:
1083     */
1084    tmp = save->vertex;
1085    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
1086       if (save->attrsz[i]) {
1087          save->attrptr[i] = tmp;
1088          tmp += save->attrsz[i];
1089       }
1090       else {
1091          save->attrptr[i] = NULL;       /* will not be dereferenced. */
1092       }
1093    }
1094
1095    /* Copy from current to repopulate the vertex with correct values.
1096     */
1097    copy_from_current(ctx);
1098
1099    /* Replay stored vertices to translate them to new format here.
1100     *
1101     * If there are copied vertices and the new (upgraded) attribute
1102     * has not been defined before, this list is somewhat degenerate,
1103     * and will need fixup at runtime.
1104     */
1105    if (save->copied.nr) {
1106       const fi_type *data = save->copied.buffer;
1107       fi_type *dest = save->buffer_map;
1108
1109       /* Need to note this and fix up at runtime (or loopback):
1110        */
1111       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
1112          assert(oldsz == 0);
1113          save->dangling_attr_ref = GL_TRUE;
1114       }
1115
1116       for (i = 0; i < save->copied.nr; i++) {
1117          GLbitfield64 enabled = save->enabled;
1118          while (enabled) {
1119             const int j = u_bit_scan64(&enabled);
1120             assert(save->attrsz[j]);
1121             if (j == attr) {
1122                if (oldsz) {
1123                   COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
1124                                               save->attrtype[j]);
1125                   data += oldsz;
1126                   dest += newsz;
1127                }
1128                else {
1129                   COPY_SZ_4V(dest, newsz, save->current[attr]);
1130                   dest += newsz;
1131                }
1132             }
1133             else {
1134                GLint sz = save->attrsz[j];
1135                COPY_SZ_4V(dest, sz, data);
1136                data += sz;
1137                dest += sz;
1138             }
1139          }
1140       }
1141
1142       save->buffer_ptr = dest;
1143       save->vert_count += save->copied.nr;
1144    }
1145 }
1146
1147
1148 /**
1149  * This is called when the size of a vertex attribute changes.
1150  * For example, after seeing one or more glTexCoord2f() calls we
1151  * get a glTexCoord4f() or glTexCoord1f() call.
1152  */
1153 static void
1154 fixup_vertex(struct gl_context *ctx, GLuint attr,
1155              GLuint sz, GLenum newType)
1156 {
1157    struct vbo_save_context *save = &vbo_context(ctx)->save;
1158
1159    if (sz > save->attrsz[attr] ||
1160        newType != save->attrtype[attr]) {
1161       /* New size is larger.  Need to flush existing vertices and get
1162        * an enlarged vertex format.
1163        */
1164       upgrade_vertex(ctx, attr, sz);
1165    }
1166    else if (sz < save->active_sz[attr]) {
1167       GLuint i;
1168       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
1169
1170       /* New size is equal or smaller - just need to fill in some
1171        * zeros.
1172        */
1173       for (i = sz; i <= save->attrsz[attr]; i++)
1174          save->attrptr[attr][i - 1] = id[i - 1];
1175    }
1176
1177    save->active_sz[attr] = sz;
1178 }
1179
1180
1181 /**
1182  * Reset the current size of all vertex attributes to the default
1183  * value of 0.  This signals that we haven't yet seen any per-vertex
1184  * commands such as glNormal3f() or glTexCoord2f().
1185  */
1186 static void
1187 reset_vertex(struct gl_context *ctx)
1188 {
1189    struct vbo_save_context *save = &vbo_context(ctx)->save;
1190
1191    while (save->enabled) {
1192       const int i = u_bit_scan64(&save->enabled);
1193       assert(save->attrsz[i]);
1194       save->attrsz[i] = 0;
1195       save->active_sz[i] = 0;
1196    }
1197
1198    save->vertex_size = 0;
1199 }
1200
1201
1202 /**
1203  * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
1204  * It depends on a few things, including whether we're inside or outside
1205  * of glBegin/glEnd.
1206  */
1207 static inline bool
1208 is_vertex_position(const struct gl_context *ctx, GLuint index)
1209 {
1210    return (index == 0 &&
1211            _mesa_attr_zero_aliases_vertex(ctx) &&
1212            _mesa_inside_dlist_begin_end(ctx));
1213 }
1214
1215
1216
1217 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
1218
1219
1220 /* Only one size for each attribute may be active at once.  Eg. if
1221  * Color3f is installed/active, then Color4f may not be, even if the
1222  * vertex actually contains 4 color coordinates.  This is because the
1223  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
1224  * of the chooser function when switching between Color4f and Color3f.
1225  */
1226 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
1227 do {                                                            \
1228    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
1229    int sz = (sizeof(C) / sizeof(GLfloat));                      \
1230                                                                 \
1231    if (save->active_sz[A] != N)                                 \
1232       fixup_vertex(ctx, A, N * sz, T);                          \
1233                                                                 \
1234    {                                                            \
1235       C *dest = (C *)save->attrptr[A];                          \
1236       if (N>0) dest[0] = V0;                                    \
1237       if (N>1) dest[1] = V1;                                    \
1238       if (N>2) dest[2] = V2;                                    \
1239       if (N>3) dest[3] = V3;                                    \
1240       save->attrtype[A] = T;                                    \
1241    }                                                            \
1242                                                                 \
1243    if ((A) == 0) {                                              \
1244       GLuint i;                                                 \
1245                                                                 \
1246       for (i = 0; i < save->vertex_size; i++)                   \
1247          save->buffer_ptr[i] = save->vertex[i];                 \
1248                                                                 \
1249       save->buffer_ptr += save->vertex_size;                    \
1250                                                                 \
1251       if (++save->vert_count >= save->max_vert)                 \
1252          wrap_filled_vertex(ctx);                               \
1253    }                                                            \
1254 } while (0)
1255
1256 #define TAG(x) _save_##x
1257
1258 #include "vbo_attrib_tmp.h"
1259
1260
1261
1262 #define MAT( ATTR, N, face, params )                    \
1263 do {                                                    \
1264    if (face != GL_BACK)                                 \
1265       MAT_ATTR( ATTR, N, params ); /* front */          \
1266    if (face != GL_FRONT)                                \
1267       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
1268 } while (0)
1269
1270
1271 /**
1272  * Save a glMaterial call found between glBegin/End.
1273  * glMaterial calls outside Begin/End are handled in dlist.c.
1274  */
1275 static void GLAPIENTRY
1276 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1277 {
1278    GET_CURRENT_CONTEXT(ctx);
1279
1280    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
1281       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
1282       return;
1283    }
1284
1285    switch (pname) {
1286    case GL_EMISSION:
1287       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
1288       break;
1289    case GL_AMBIENT:
1290       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1291       break;
1292    case GL_DIFFUSE:
1293       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1294       break;
1295    case GL_SPECULAR:
1296       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
1297       break;
1298    case GL_SHININESS:
1299       if (*params < 0 || *params > ctx->Const.MaxShininess) {
1300          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
1301       }
1302       else {
1303          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
1304       }
1305       break;
1306    case GL_COLOR_INDEXES:
1307       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
1308       break;
1309    case GL_AMBIENT_AND_DIFFUSE:
1310       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
1311       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
1312       break;
1313    default:
1314       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
1315       return;
1316    }
1317 }
1318
1319
1320 /* Cope with EvalCoord/CallList called within a begin/end object:
1321  *     -- Flush current buffer
1322  *     -- Fallback to opcodes for the rest of the begin/end object.
1323  */
1324 static void
1325 dlist_fallback(struct gl_context *ctx)
1326 {
1327    struct vbo_save_context *save = &vbo_context(ctx)->save;
1328
1329    if (save->vert_count || save->prim_count) {
1330       if (save->prim_count > 0) {
1331          /* Close off in-progress primitive. */
1332          GLint i = save->prim_count - 1;
1333          save->prims[i].count = save->vert_count - save->prims[i].start;
1334       }
1335
1336       /* Need to replay this display list with loopback,
1337        * unfortunately, otherwise this primitive won't be handled
1338        * properly:
1339        */
1340       save->dangling_attr_ref = GL_TRUE;
1341
1342       compile_vertex_list(ctx);
1343    }
1344
1345    copy_to_current(ctx);
1346    reset_vertex(ctx);
1347    reset_counters(ctx);
1348    if (save->out_of_memory) {
1349       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1350    }
1351    else {
1352       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1353    }
1354    ctx->Driver.SaveNeedFlush = GL_FALSE;
1355 }
1356
1357
1358 static void GLAPIENTRY
1359 _save_EvalCoord1f(GLfloat u)
1360 {
1361    GET_CURRENT_CONTEXT(ctx);
1362    dlist_fallback(ctx);
1363    CALL_EvalCoord1f(ctx->Save, (u));
1364 }
1365
1366 static void GLAPIENTRY
1367 _save_EvalCoord1fv(const GLfloat * v)
1368 {
1369    GET_CURRENT_CONTEXT(ctx);
1370    dlist_fallback(ctx);
1371    CALL_EvalCoord1fv(ctx->Save, (v));
1372 }
1373
1374 static void GLAPIENTRY
1375 _save_EvalCoord2f(GLfloat u, GLfloat v)
1376 {
1377    GET_CURRENT_CONTEXT(ctx);
1378    dlist_fallback(ctx);
1379    CALL_EvalCoord2f(ctx->Save, (u, v));
1380 }
1381
1382 static void GLAPIENTRY
1383 _save_EvalCoord2fv(const GLfloat * v)
1384 {
1385    GET_CURRENT_CONTEXT(ctx);
1386    dlist_fallback(ctx);
1387    CALL_EvalCoord2fv(ctx->Save, (v));
1388 }
1389
1390 static void GLAPIENTRY
1391 _save_EvalPoint1(GLint i)
1392 {
1393    GET_CURRENT_CONTEXT(ctx);
1394    dlist_fallback(ctx);
1395    CALL_EvalPoint1(ctx->Save, (i));
1396 }
1397
1398 static void GLAPIENTRY
1399 _save_EvalPoint2(GLint i, GLint j)
1400 {
1401    GET_CURRENT_CONTEXT(ctx);
1402    dlist_fallback(ctx);
1403    CALL_EvalPoint2(ctx->Save, (i, j));
1404 }
1405
1406 static void GLAPIENTRY
1407 _save_CallList(GLuint l)
1408 {
1409    GET_CURRENT_CONTEXT(ctx);
1410    dlist_fallback(ctx);
1411    CALL_CallList(ctx->Save, (l));
1412 }
1413
1414 static void GLAPIENTRY
1415 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1416 {
1417    GET_CURRENT_CONTEXT(ctx);
1418    dlist_fallback(ctx);
1419    CALL_CallLists(ctx->Save, (n, type, v));
1420 }
1421
1422
1423
1424 /**
1425  * Called when a glBegin is getting compiled into a display list.
1426  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1427  */
1428 void
1429 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode,
1430                      bool no_current_update)
1431 {
1432    struct vbo_save_context *save = &vbo_context(ctx)->save;
1433    const GLuint i = save->prim_count++;
1434
1435    ctx->Driver.CurrentSavePrimitive = mode;
1436
1437    assert(i < save->prim_max);
1438    save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1439    save->prims[i].begin = 1;
1440    save->prims[i].end = 0;
1441    save->prims[i].start = save->vert_count;
1442    save->prims[i].count = 0;
1443
1444    save->no_current_update = no_current_update;
1445
1446    if (save->out_of_memory) {
1447       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1448    }
1449    else {
1450       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1451    }
1452
1453    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1454    ctx->Driver.SaveNeedFlush = GL_TRUE;
1455 }
1456
1457
1458 static void GLAPIENTRY
1459 _save_End(void)
1460 {
1461    GET_CURRENT_CONTEXT(ctx);
1462    struct vbo_save_context *save = &vbo_context(ctx)->save;
1463    const GLint i = save->prim_count - 1;
1464
1465    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1466    save->prims[i].end = 1;
1467    save->prims[i].count = (save->vert_count - save->prims[i].start);
1468
1469    if (i == (GLint) save->prim_max - 1) {
1470       compile_vertex_list(ctx);
1471       assert(save->copied.nr == 0);
1472    }
1473
1474    /* Swap out this vertex format while outside begin/end.  Any color,
1475     * etc. received between here and the next begin will be compiled
1476     * as opcodes.
1477     */
1478    if (save->out_of_memory) {
1479       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1480    }
1481    else {
1482       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1483    }
1484 }
1485
1486
1487 static void GLAPIENTRY
1488 _save_Begin(GLenum mode)
1489 {
1490    GET_CURRENT_CONTEXT(ctx);
1491    (void) mode;
1492    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1493 }
1494
1495
1496 static void GLAPIENTRY
1497 _save_PrimitiveRestartNV(void)
1498 {
1499    GET_CURRENT_CONTEXT(ctx);
1500    struct vbo_save_context *save = &vbo_context(ctx)->save;
1501
1502    if (save->prim_count == 0) {
1503       /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV
1504        * is an error.
1505        */
1506       _mesa_compile_error(ctx, GL_INVALID_OPERATION,
1507                           "glPrimitiveRestartNV called outside glBegin/End");
1508    } else {
1509       /* get current primitive mode */
1510       GLenum curPrim = save->prims[save->prim_count - 1].mode;
1511       bool no_current_update = save->no_current_update;
1512
1513       /* restart primitive */
1514       CALL_End(ctx->CurrentServerDispatch, ());
1515       vbo_save_NotifyBegin(ctx, curPrim, no_current_update);
1516    }
1517 }
1518
1519
1520 /* Unlike the functions above, these are to be hooked into the vtxfmt
1521  * maintained in ctx->ListState, active when the list is known or
1522  * suspected to be outside any begin/end primitive.
1523  * Note: OBE = Outside Begin/End
1524  */
1525 static void GLAPIENTRY
1526 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1527 {
1528    GET_CURRENT_CONTEXT(ctx);
1529    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1530
1531    vbo_save_NotifyBegin(ctx, GL_QUADS, false);
1532    CALL_Vertex2f(dispatch, (x1, y1));
1533    CALL_Vertex2f(dispatch, (x2, y1));
1534    CALL_Vertex2f(dispatch, (x2, y2));
1535    CALL_Vertex2f(dispatch, (x1, y2));
1536    CALL_End(dispatch, ());
1537 }
1538
1539
1540 static void GLAPIENTRY
1541 _save_OBE_Rectd(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
1542 {
1543    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1544 }
1545
1546 static void GLAPIENTRY
1547 _save_OBE_Rectdv(const GLdouble *v1, const GLdouble *v2)
1548 {
1549    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1550 }
1551
1552 static void GLAPIENTRY
1553 _save_OBE_Rectfv(const GLfloat *v1, const GLfloat *v2)
1554 {
1555    _save_OBE_Rectf(v1[0], v1[1], v2[0], v2[1]);
1556 }
1557
1558 static void GLAPIENTRY
1559 _save_OBE_Recti(GLint x1, GLint y1, GLint x2, GLint y2)
1560 {
1561    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1562 }
1563
1564 static void GLAPIENTRY
1565 _save_OBE_Rectiv(const GLint *v1, const GLint *v2)
1566 {
1567    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1568 }
1569
1570 static void GLAPIENTRY
1571 _save_OBE_Rects(GLshort x1, GLshort y1, GLshort x2, GLshort y2)
1572 {
1573    _save_OBE_Rectf((GLfloat) x1, (GLfloat) y1, (GLfloat) x2, (GLfloat) y2);
1574 }
1575
1576 static void GLAPIENTRY
1577 _save_OBE_Rectsv(const GLshort *v1, const GLshort *v2)
1578 {
1579    _save_OBE_Rectf((GLfloat) v1[0], (GLfloat) v1[1], (GLfloat) v2[0], (GLfloat) v2[1]);
1580 }
1581
1582 static void
1583 _ensure_draws_fits_in_storage(struct gl_context *ctx, int primcount, int vertcount)
1584 {
1585    struct vbo_save_context *save = &vbo_context(ctx)->save;
1586
1587    bool realloc_prim = save->prim_count + primcount > save->prim_max;
1588    bool realloc_vert = save->vertex_size && (save->vert_count + vertcount >= save->max_vert);
1589
1590    if (realloc_prim || realloc_vert) {
1591       if (save->vert_count || save->prim_count)
1592          compile_vertex_list(ctx);
1593       realloc_storage(ctx, realloc_prim ? primcount : -1, realloc_vert ? vertcount : -1);
1594       reset_counters(ctx);
1595       assert(save->prim_max);
1596    }
1597 }
1598
1599
1600 static void GLAPIENTRY
1601 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1602 {
1603    GET_CURRENT_CONTEXT(ctx);
1604    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1605    struct vbo_save_context *save = &vbo_context(ctx)->save;
1606    GLint i;
1607
1608    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1609       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1610       return;
1611    }
1612    if (count < 0) {
1613       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1614       return;
1615    }
1616
1617    if (save->out_of_memory)
1618       return;
1619
1620    _ensure_draws_fits_in_storage(ctx, 1, count);
1621
1622    /* Make sure to process any VBO binding changes */
1623    _mesa_update_state(ctx);
1624
1625    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1626
1627    vbo_save_NotifyBegin(ctx, mode, true);
1628
1629    for (i = 0; i < count; i++)
1630       _mesa_array_element(ctx, start + i);
1631    CALL_End(ctx->CurrentServerDispatch, ());
1632
1633    _mesa_vao_unmap_arrays(ctx, vao);
1634 }
1635
1636
1637 static void GLAPIENTRY
1638 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1639                           const GLsizei *count, GLsizei primcount)
1640 {
1641    GET_CURRENT_CONTEXT(ctx);
1642    GLint i;
1643
1644    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1645       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1646       return;
1647    }
1648
1649    if (primcount < 0) {
1650       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1651                           "glMultiDrawArrays(primcount<0)");
1652       return;
1653    }
1654
1655    unsigned vertcount = 0;
1656    for (i = 0; i < primcount; i++) {
1657       if (count[i] < 0) {
1658          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1659                              "glMultiDrawArrays(count[i]<0)");
1660          return;
1661       }
1662       vertcount += count[i];
1663    }
1664
1665    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1666
1667    for (i = 0; i < primcount; i++) {
1668       if (count[i] > 0) {
1669          _save_OBE_DrawArrays(mode, first[i], count[i]);
1670       }
1671    }
1672 }
1673
1674
1675 static void
1676 array_element(struct gl_context *ctx,
1677               GLint basevertex, GLuint elt, unsigned index_size_shift)
1678 {
1679    /* Section 10.3.5 Primitive Restart:
1680     * [...]
1681     *    When one of the *BaseVertex drawing commands specified in section 10.5
1682     * is used, the primitive restart comparison occurs before the basevertex
1683     * offset is added to the array index.
1684     */
1685    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1686     * then we call PrimitiveRestartNV and return.
1687     */
1688    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1689        elt == ctx->Array._RestartIndex[index_size_shift]) {
1690       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1691       return;
1692    }
1693
1694    _mesa_array_element(ctx, basevertex + elt);
1695 }
1696
1697
1698 /* Could do better by copying the arrays and element list intact and
1699  * then emitting an indexed prim at runtime.
1700  */
1701 static void GLAPIENTRY
1702 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1703                                  const GLvoid * indices, GLint basevertex)
1704 {
1705    GET_CURRENT_CONTEXT(ctx);
1706    struct vbo_save_context *save = &vbo_context(ctx)->save;
1707    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1708    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1709    GLint i;
1710
1711    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1712       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1713       return;
1714    }
1715    if (count < 0) {
1716       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1717       return;
1718    }
1719    if (type != GL_UNSIGNED_BYTE &&
1720        type != GL_UNSIGNED_SHORT &&
1721        type != GL_UNSIGNED_INT) {
1722       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1723       return;
1724    }
1725
1726    if (save->out_of_memory)
1727       return;
1728
1729    _ensure_draws_fits_in_storage(ctx, 1, count);
1730
1731    /* Make sure to process any VBO binding changes */
1732    _mesa_update_state(ctx);
1733
1734    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1735
1736    if (indexbuf)
1737       indices =
1738          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1739
1740    vbo_save_NotifyBegin(ctx, mode, true);
1741
1742    switch (type) {
1743    case GL_UNSIGNED_BYTE:
1744       for (i = 0; i < count; i++)
1745          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1746       break;
1747    case GL_UNSIGNED_SHORT:
1748       for (i = 0; i < count; i++)
1749          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1750       break;
1751    case GL_UNSIGNED_INT:
1752       for (i = 0; i < count; i++)
1753          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1754       break;
1755    default:
1756       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1757       break;
1758    }
1759
1760    CALL_End(ctx->CurrentServerDispatch, ());
1761
1762    _mesa_vao_unmap(ctx, vao);
1763 }
1764
1765 static void GLAPIENTRY
1766 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1767                        const GLvoid * indices)
1768 {
1769    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1770 }
1771
1772
1773 static void GLAPIENTRY
1774 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1775                             GLsizei count, GLenum type,
1776                             const GLvoid * indices)
1777 {
1778    GET_CURRENT_CONTEXT(ctx);
1779    struct vbo_save_context *save = &vbo_context(ctx)->save;
1780
1781    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1782       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1783       return;
1784    }
1785    if (count < 0) {
1786       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1787                           "glDrawRangeElements(count<0)");
1788       return;
1789    }
1790    if (type != GL_UNSIGNED_BYTE &&
1791        type != GL_UNSIGNED_SHORT &&
1792        type != GL_UNSIGNED_INT) {
1793       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1794       return;
1795    }
1796    if (end < start) {
1797       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1798                           "glDrawRangeElements(end < start)");
1799       return;
1800    }
1801
1802    if (save->out_of_memory)
1803       return;
1804
1805    _save_OBE_DrawElements(mode, count, type, indices);
1806 }
1807
1808
1809 static void GLAPIENTRY
1810 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1811                             const GLvoid * const *indices, GLsizei primcount)
1812 {
1813    GET_CURRENT_CONTEXT(ctx);
1814    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1815    GLsizei i;
1816
1817    int vertcount = 0;
1818    for (i = 0; i < primcount; i++) {
1819       vertcount += count[i];
1820    }
1821    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1822
1823    for (i = 0; i < primcount; i++) {
1824       if (count[i] > 0) {
1825          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1826       }
1827    }
1828 }
1829
1830
1831 static void GLAPIENTRY
1832 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1833                                       GLenum type,
1834                                       const GLvoid * const *indices,
1835                                       GLsizei primcount,
1836                                       const GLint *basevertex)
1837 {
1838    GET_CURRENT_CONTEXT(ctx);
1839    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1840    GLsizei i;
1841
1842    int vertcount = 0;
1843    for (i = 0; i < primcount; i++) {
1844       vertcount += count[i];
1845    }
1846    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1847
1848    for (i = 0; i < primcount; i++) {
1849       if (count[i] > 0) {
1850          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1851                                                       indices[i],
1852                                                       basevertex[i]));
1853       }
1854    }
1855 }
1856
1857
1858 static void
1859 vtxfmt_init(struct gl_context *ctx)
1860 {
1861    struct vbo_save_context *save = &vbo_context(ctx)->save;
1862    GLvertexformat *vfmt = &save->vtxfmt;
1863
1864 #define NAME_AE(x) _ae_##x
1865 #define NAME_CALLLIST(x) _save_##x
1866 #define NAME(x) _save_##x
1867 #define NAME_ES(x) _save_##x##ARB
1868
1869 #include "vbo_init_tmp.h"
1870 }
1871
1872
1873 /**
1874  * Initialize the dispatch table with the VBO functions for display
1875  * list compilation.
1876  */
1877 void
1878 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1879                              struct _glapi_table *exec)
1880 {
1881    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1882    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1883    SET_DrawElements(exec, _save_OBE_DrawElements);
1884    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1885    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1886    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1887    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1888    SET_Rectf(exec, _save_OBE_Rectf);
1889    SET_Rectd(exec, _save_OBE_Rectd);
1890    SET_Rectdv(exec, _save_OBE_Rectdv);
1891    SET_Rectfv(exec, _save_OBE_Rectfv);
1892    SET_Recti(exec, _save_OBE_Recti);
1893    SET_Rectiv(exec, _save_OBE_Rectiv);
1894    SET_Rects(exec, _save_OBE_Rects);
1895    SET_Rectsv(exec, _save_OBE_Rectsv);
1896
1897    /* Note: other glDraw functins aren't compiled into display lists */
1898 }
1899
1900
1901
1902 void
1903 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1904 {
1905    struct vbo_save_context *save = &vbo_context(ctx)->save;
1906
1907    /* Noop when we are actually active:
1908     */
1909    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1910       return;
1911
1912    if (save->vert_count || save->prim_count)
1913       compile_vertex_list(ctx);
1914
1915    copy_to_current(ctx);
1916    reset_vertex(ctx);
1917    reset_counters(ctx);
1918    ctx->Driver.SaveNeedFlush = GL_FALSE;
1919 }
1920
1921
1922 /**
1923  * Called from glNewList when we're starting to compile a display list.
1924  */
1925 void
1926 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1927 {
1928    struct vbo_save_context *save = &vbo_context(ctx)->save;
1929
1930    (void) list;
1931    (void) mode;
1932
1933    if (!save->prim_store)
1934       save->prim_store = alloc_prim_store(0);
1935
1936    if (!save->vertex_store)
1937       save->vertex_store = alloc_vertex_store(ctx, 0);
1938
1939    save->buffer_ptr = save->vertex_store->buffer_in_ram + save->vertex_store->used;
1940
1941    reset_vertex(ctx);
1942    reset_counters(ctx);
1943    ctx->Driver.SaveNeedFlush = GL_FALSE;
1944 }
1945
1946
1947 /**
1948  * Called from glEndList when we're finished compiling a display list.
1949  */
1950 void
1951 vbo_save_EndList(struct gl_context *ctx)
1952 {
1953    struct vbo_save_context *save = &vbo_context(ctx)->save;
1954
1955    /* EndList called inside a (saved) Begin/End pair?
1956     */
1957    if (_mesa_inside_dlist_begin_end(ctx)) {
1958       if (save->prim_count > 0) {
1959          GLint i = save->prim_count - 1;
1960          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1961          save->prims[i].end = 0;
1962          save->prims[i].count = save->vert_count - save->prims[i].start;
1963       }
1964
1965       /* Make sure this vertex list gets replayed by the "loopback"
1966        * mechanism:
1967        */
1968       save->dangling_attr_ref = GL_TRUE;
1969       vbo_save_SaveFlushVertices(ctx);
1970
1971       /* Swap out this vertex format while outside begin/end.  Any color,
1972        * etc. received between here and the next begin will be compiled
1973        * as opcodes.
1974        */
1975       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1976    }
1977
1978    assert(save->vertex_size == 0);
1979 }
1980
1981 /**
1982  * Called during context creation/init.
1983  */
1984 static void
1985 current_init(struct gl_context *ctx)
1986 {
1987    struct vbo_save_context *save = &vbo_context(ctx)->save;
1988    GLint i;
1989
1990    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_EDGEFLAG; i++) {
1991       const GLuint j = i - VBO_ATTRIB_POS;
1992       assert(j < VERT_ATTRIB_MAX);
1993       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1994       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1995    }
1996
1997    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1998       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1999       assert(j < MAT_ATTRIB_MAX);
2000       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
2001       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2002    }
2003 }
2004
2005
2006 /**
2007  * Initialize the display list compiler.  Called during context creation.
2008  */
2009 void
2010 vbo_save_api_init(struct vbo_save_context *save)
2011 {
2012    struct gl_context *ctx = gl_context_from_vbo_save(save);
2013
2014    vtxfmt_init(ctx);
2015    current_init(ctx);
2016    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop);
2017 }