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