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