dlist: implement vertices deduplication
[platform/upstream/mesa.git] / src / mesa / vbo / vbo_save_api.c
1 /**************************************************************************
2
3 Copyright 2002-2008 VMware, Inc.
4
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29  * Authors:
30  *   Keith Whitwell <keithw@vmware.com>
31  */
32
33
34
35 /* Display list compiler attempts to store lists of vertices with the
36  * same vertex layout.  Additionally it attempts to minimize the need
37  * for execute-time fixup of these vertex lists, allowing them to be
38  * cached on hardware.
39  *
40  * There are still some circumstances where this can be thwarted, for
41  * example by building a list that consists of one very long primitive
42  * (eg Begin(Triangles), 1000 vertices, End), and calling that list
43  * from inside a different begin/end object (Begin(Lines), CallList,
44  * End).
45  *
46  * In that case the code will have to replay the list as individual
47  * commands through the Exec dispatch table, or fix up the copied
48  * vertices at execute-time.
49  *
50  * The other case where fixup is required is when a vertex attribute
51  * is introduced in the middle of a primitive.  Eg:
52  *  Begin(Lines)
53  *  TexCoord1f()           Vertex2f()
54  *  TexCoord1f() Color3f() Vertex2f()
55  *  End()
56  *
57  *  If the current value of Color isn't known at compile-time, this
58  *  primitive will require fixup.
59  *
60  *
61  * The list compiler currently doesn't attempt to compile lists
62  * containing EvalCoord or EvalPoint commands.  On encountering one of
63  * these, compilation falls back to opcodes.
64  *
65  * This could be improved to fallback only when a mix of EvalCoord and
66  * Vertex commands are issued within a single primitive.
67  */
68
69
70 #include "main/glheader.h"
71 #include "main/arrayobj.h"
72 #include "main/bufferobj.h"
73 #include "main/context.h"
74 #include "main/dlist.h"
75 #include "main/enums.h"
76 #include "main/eval.h"
77 #include "main/macros.h"
78 #include "main/draw_validate.h"
79 #include "main/api_arrayelt.h"
80 #include "main/vtxfmt.h"
81 #include "main/dispatch.h"
82 #include "main/state.h"
83 #include "main/varray.h"
84 #include "util/bitscan.h"
85 #include "util/u_memory.h"
86 #include "util/hash_table.h"
87
88 #include "gallium/include/pipe/p_state.h"
89
90 #include "vbo_noop.h"
91 #include "vbo_private.h"
92
93
94 #ifdef ERROR
95 #undef ERROR
96 #endif
97
98 /* An interesting VBO number/name to help with debugging */
99 #define VBO_BUF_ID  12345
100
101 static void GLAPIENTRY
102 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
103
104 static void GLAPIENTRY
105 _save_EvalCoord1f(GLfloat u);
106
107 static void GLAPIENTRY
108 _save_EvalCoord2f(GLfloat u, GLfloat v);
109
110 /*
111  * NOTE: Old 'parity' issue is gone, but copying can still be
112  * wrong-footed on replay.
113  */
114 static GLuint
115 copy_vertices(struct gl_context *ctx,
116               const struct vbo_save_vertex_list *node,
117               const fi_type * src_buffer)
118 {
119    struct vbo_save_context *save = &vbo_context(ctx)->save;
120    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
121    GLuint sz = save->vertex_size;
122    const fi_type *src = src_buffer + prim->start * sz;
123    fi_type *dst = save->copied.buffer;
124
125    if (prim->end)
126       return 0;
127
128    return vbo_copy_vertices(ctx, prim->mode, prim->start, &prim->count,
129                             prim->begin, sz, true, dst, src);
130 }
131
132
133 static struct vbo_save_vertex_store *
134 alloc_vertex_store(struct gl_context *ctx, int vertex_count)
135 {
136    struct vbo_save_context *save = &vbo_context(ctx)->save;
137    struct vbo_save_vertex_store *vertex_store =
138       CALLOC_STRUCT(vbo_save_vertex_store);
139
140    int size = MAX2(vertex_count * save->vertex_size, VBO_SAVE_BUFFER_SIZE);
141
142    /* obj->Name needs to be non-zero, but won't ever be examined more
143     * closely than that.  In particular these buffers won't be entered
144     * into the hash and can never be confused with ones visible to the
145     * user.  Perhaps there could be a special number for internal
146     * buffers:
147     */
148    vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID);
149    if (vertex_store->bufferobj) {
150       vertex_store->buffer_in_ram_size = size * sizeof(GLfloat);
151       vertex_store->buffer_in_ram = malloc(vertex_store->buffer_in_ram_size);
152       save->out_of_memory = vertex_store->buffer_in_ram == NULL;
153       save->out_of_memory =
154          !ctx->Driver.BufferData(ctx,
155                                  GL_ARRAY_BUFFER_ARB,
156                                  size * sizeof(GLfloat),
157                                  NULL, GL_STATIC_DRAW_ARB,
158                                  GL_MAP_WRITE_BIT,
159                                  vertex_store->bufferobj);
160    }
161    else {
162       save->out_of_memory = GL_TRUE;
163    }
164
165    if (save->out_of_memory) {
166       _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
167       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
168    }
169
170    vertex_store->used = 0;
171
172    return vertex_store;
173 }
174
175
176 static void
177 free_vertex_store(struct gl_context *ctx,
178                   struct vbo_save_vertex_store *vertex_store)
179 {
180    free(vertex_store->buffer_in_ram);
181
182    if (vertex_store->bufferobj) {
183       _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
184    }
185
186    free(vertex_store);
187 }
188
189
190 static struct vbo_save_primitive_store *
191 alloc_prim_store(int prim_count)
192 {
193    struct vbo_save_primitive_store *store =
194       CALLOC_STRUCT(vbo_save_primitive_store);
195    store->size = MAX2(prim_count, VBO_SAVE_PRIM_SIZE);
196    store->prims = calloc(store->size, sizeof(struct _mesa_prim));
197    store->used = 0;
198    store->refcount = 1;
199    return store;
200 }
201
202
203 static void
204 reset_counters(struct gl_context *ctx)
205 {
206    struct vbo_save_context *save = &vbo_context(ctx)->save;
207
208    save->prims = save->prim_store->prims + save->prim_store->used;
209    save->buffer_map = save->vertex_store->buffer_in_ram + save->vertex_store->used;
210
211    assert(save->buffer_map == save->buffer_ptr);
212
213    if (save->vertex_size)
214       save->max_vert = (save->vertex_store->bufferobj->Size / sizeof(float) - save->vertex_store->used) /
215                         save->vertex_size;
216    else
217       save->max_vert = 0;
218
219    save->vert_count = 0;
220    save->prim_count = 0;
221    save->prim_max = save->prim_store->size - save->prim_store->used;
222    save->dangling_attr_ref = GL_FALSE;
223 }
224
225 /**
226  * For a list of prims, try merging prims that can just be extensions of the
227  * previous prim.
228  */
229 static void
230 merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list,
231             GLuint *prim_count)
232 {
233    GLuint i;
234    struct _mesa_prim *prev_prim = prim_list;
235
236    for (i = 1; i < *prim_count; i++) {
237       struct _mesa_prim *this_prim = prim_list + i;
238
239       vbo_try_prim_conversion(&this_prim->mode, &this_prim->count);
240
241       if (vbo_merge_draws(ctx, true,
242                           prev_prim->mode, this_prim->mode,
243                           prev_prim->start, this_prim->start,
244                           &prev_prim->count, this_prim->count,
245                           prev_prim->basevertex, this_prim->basevertex,
246                           &prev_prim->end,
247                           this_prim->begin, this_prim->end)) {
248          /* We've found a prim that just extend the previous one.  Tack it
249           * onto the previous one, and let this primitive struct get dropped.
250           */
251          continue;
252       }
253
254       /* If any previous primitives have been dropped, then we need to copy
255        * this later one into the next available slot.
256        */
257       prev_prim++;
258       if (prev_prim != this_prim)
259          *prev_prim = *this_prim;
260    }
261
262    *prim_count = prev_prim - prim_list + 1;
263 }
264
265
266 /**
267  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
268  * don't have to worry about handling the _mesa_prim::begin/end flags.
269  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
270  */
271 static void
272 convert_line_loop_to_strip(struct vbo_save_context *save,
273                            struct vbo_save_vertex_list *node)
274 {
275    struct _mesa_prim *prim = &node->cold->prims[node->cold->prim_count - 1];
276
277    assert(prim->mode == GL_LINE_LOOP);
278
279    if (prim->end) {
280       /* Copy the 0th vertex to end of the buffer and extend the
281        * vertex count by one to finish the line loop.
282        */
283       const GLuint sz = save->vertex_size;
284       /* 0th vertex: */
285       const fi_type *src = save->buffer_map + prim->start * sz;
286       /* end of buffer: */
287       fi_type *dst = save->buffer_map + (prim->start + prim->count) * sz;
288
289       memcpy(dst, src, sz * sizeof(float));
290
291       prim->count++;
292       node->cold->vertex_count++;
293       save->vert_count++;
294       save->buffer_ptr += sz;
295       save->vertex_store->used += sz;
296    }
297
298    if (!prim->begin) {
299       /* Drawing the second or later section of a long line loop.
300        * Skip the 0th vertex.
301        */
302       prim->start++;
303       prim->count--;
304    }
305
306    prim->mode = GL_LINE_STRIP;
307 }
308
309
310 /* Compare the present vao if it has the same setup. */
311 static bool
312 compare_vao(gl_vertex_processing_mode mode,
313             const struct gl_vertex_array_object *vao,
314             const struct gl_buffer_object *bo, GLintptr buffer_offset,
315             GLuint stride, GLbitfield64 vao_enabled,
316             const GLubyte size[VBO_ATTRIB_MAX],
317             const GLenum16 type[VBO_ATTRIB_MAX],
318             const GLuint offset[VBO_ATTRIB_MAX])
319 {
320    if (!vao)
321       return false;
322
323    /* If the enabled arrays are not the same we are not equal. */
324    if (vao_enabled != vao->Enabled)
325       return false;
326
327    /* Check the buffer binding at 0 */
328    if (vao->BufferBinding[0].BufferObj != bo)
329       return false;
330    /* BufferBinding[0].Offset != buffer_offset is checked per attribute */
331    if (vao->BufferBinding[0].Stride != stride)
332       return false;
333    assert(vao->BufferBinding[0].InstanceDivisor == 0);
334
335    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */
336    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
337
338    /* Now check the enabled arrays */
339    GLbitfield mask = vao_enabled;
340    while (mask) {
341       const int attr = u_bit_scan(&mask);
342       const unsigned char vbo_attr = vao_to_vbo_map[attr];
343       const GLenum16 tp = type[vbo_attr];
344       const GLintptr off = offset[vbo_attr] + buffer_offset;
345       const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr];
346       if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off)
347          return false;
348       if (attrib->Format.Type != tp)
349          return false;
350       if (attrib->Format.Size != size[vbo_attr])
351          return false;
352       assert(attrib->Format.Format == GL_RGBA);
353       assert(attrib->Format.Normalized == GL_FALSE);
354       assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp));
355       assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp));
356       assert(attrib->BufferBindingIndex == 0);
357    }
358
359    return true;
360 }
361
362
363 /* Create or reuse the vao for the vertex processing mode. */
364 static void
365 update_vao(struct gl_context *ctx,
366            gl_vertex_processing_mode mode,
367            struct gl_vertex_array_object **vao,
368            struct gl_buffer_object *bo, GLintptr buffer_offset,
369            GLuint stride, GLbitfield64 vbo_enabled,
370            const GLubyte size[VBO_ATTRIB_MAX],
371            const GLenum16 type[VBO_ATTRIB_MAX],
372            const GLuint offset[VBO_ATTRIB_MAX])
373 {
374    /* Compute the bitmasks of vao_enabled arrays */
375    GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled);
376
377    /*
378     * Check if we can possibly reuse the exisiting one.
379     * In the long term we should reset them when something changes.
380     */
381    if (compare_vao(mode, *vao, bo, buffer_offset, stride,
382                    vao_enabled, size, type, offset))
383       return;
384
385    /* The initial refcount is 1 */
386    _mesa_reference_vao(ctx, vao, NULL);
387    *vao = _mesa_new_vao(ctx, ~((GLuint)0));
388
389    /*
390     * assert(stride <= ctx->Const.MaxVertexAttribStride);
391     * MaxVertexAttribStride is not set for drivers that does not
392     * expose GL 44 or GLES 31.
393     */
394
395    /* Bind the buffer object at binding point 0 */
396    _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false,
397                             false);
398
399    /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space
400     * Note that the position/generic0 aliasing is done in the VAO.
401     */
402    const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode];
403    /* Now set the enable arrays */
404    GLbitfield mask = vao_enabled;
405    while (mask) {
406       const int vao_attr = u_bit_scan(&mask);
407       const GLubyte vbo_attr = vao_to_vbo_map[vao_attr];
408       assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset);
409
410       _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset,
411                              size[vbo_attr], type[vbo_attr], offset[vbo_attr]);
412       _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0);
413    }
414    _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled);
415    assert(vao_enabled == (*vao)->Enabled);
416    assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0);
417
418    /* Finalize and freeze the VAO */
419    _mesa_set_vao_immutable(ctx, *vao);
420 }
421
422
423 static void
424 realloc_storage(struct gl_context *ctx, int prim_count, int vertex_count)
425 {
426    struct vbo_save_context *save = &vbo_context(ctx)->save;
427    if (vertex_count >= 0) {
428       /* Release old reference:
429        */
430       free_vertex_store(ctx, save->vertex_store);
431       save->vertex_store = NULL;
432       /* When we have a new vbo, we will for sure need a new vao */
433       for (gl_vertex_processing_mode vpm = 0; vpm < VP_MODE_MAX; ++vpm)
434          _mesa_reference_vao(ctx, &save->VAO[vpm], NULL);
435
436       /* Allocate and map new store:
437        */
438       save->vertex_store = alloc_vertex_store(ctx, vertex_count);
439       save->buffer_ptr = save->vertex_store->buffer_in_ram + save->vertex_store->used;
440       save->out_of_memory = save->buffer_ptr == NULL;
441    }
442
443    if (prim_count >= 0) {
444       if (--save->prim_store->refcount == 0) {
445          free(save->prim_store->prims);
446          free(save->prim_store);
447       }
448       save->prim_store = alloc_prim_store(prim_count);
449    }
450 }
451
452 struct vertex_key {
453    unsigned vertex_size;
454    fi_type *vertex_attributes;
455 };
456
457 static uint32_t _hash_vertex_key(const void *key)
458 {
459    struct vertex_key *k = (struct vertex_key*)key;
460    unsigned sz = k->vertex_size;
461    assert(sz);
462    return _mesa_hash_data(k->vertex_attributes, sz * sizeof(float));
463 }
464
465 static bool _compare_vertex_key(const void *key1, const void *key2)
466 {
467    struct vertex_key *k1 = (struct vertex_key*)key1;
468    struct vertex_key *k2 = (struct vertex_key*)key2;
469    /* All the compared vertices are going to be drawn with the same VAO,
470     * so we can compare the attributes. */
471    assert (k1->vertex_size == k2->vertex_size);
472    return memcmp(k1->vertex_attributes,
473                  k2->vertex_attributes,
474                  k1->vertex_size * sizeof(float)) == 0;
475 }
476
477 static void _free_entry(struct hash_entry *entry)
478 {
479    free((void*)entry->key);
480 }
481
482 /* Add vertex to the vertex buffer and return its index. If this vertex is a duplicate
483  * of an existing vertex, return the original index instead.
484  */
485 static uint32_t
486 add_vertex(struct vbo_save_context *save, struct hash_table *hash_to_index,
487            uint32_t index, uint32_t offset_in_bytes, uint32_t base_index, fi_type *new_buffer,
488            uint32_t *max_index)
489 {
490    /* If vertex deduplication is disabled return the original index. */
491    if (!hash_to_index)
492       return index;
493
494    /* Apply the offset into buffer_in_ram ... */
495    fi_type *vert = save->vertex_store->buffer_in_ram + offset_in_bytes / sizeof(float);
496    /* ... and cancel the start_offset trick.
497     * This way we get the correct offset in all cases (= start_offset being 0 or not).
498     */
499    vert += save->vertex_size * (index - base_index);
500
501    struct vertex_key *key = malloc(sizeof(struct vertex_key));
502    key->vertex_size = save->vertex_size;
503    key->vertex_attributes = vert;
504
505    struct hash_entry *entry = _mesa_hash_table_search(hash_to_index, key);
506    if (entry) {
507       free(key);
508       /* We found an existing vertex with the same hash, return its index. */
509       return (uintptr_t) entry->data;
510    } else {
511       /* This is a new vertex. Determine a new index and copy its attributes to the vertex
512        * buffer. Note that 'new_buffer' is created at each list compilation so we write vertices
513        * starting at index 0.
514        */
515       uint32_t n = _mesa_hash_table_num_entries(hash_to_index);
516       *max_index = MAX2(n + base_index, *max_index);
517
518       memcpy(&new_buffer[save->vertex_size * n],
519              vert,
520              save->vertex_size * sizeof(fi_type));
521
522       _mesa_hash_table_insert(hash_to_index, key, (void*)(uintptr_t)(n + base_index));
523
524       /* The index buffer is shared between list compilations, so add the base index to get
525        * the final index.
526        */
527       return n + base_index;
528    }
529 }
530
531
532 /**
533  * Insert the active immediate struct onto the display list currently
534  * being built.
535  */
536 static void
537 compile_vertex_list(struct gl_context *ctx)
538 {
539    struct vbo_save_context *save = &vbo_context(ctx)->save;
540    struct vbo_save_vertex_list *node;
541
542    /* Allocate space for this structure in the display list currently
543     * being compiled.
544     */
545    node = (struct vbo_save_vertex_list *)
546       _mesa_dlist_alloc_vertex_list(ctx, !save->dangling_attr_ref && !save->no_current_update);
547
548    if (!node)
549       return;
550
551    memset(node, 0, sizeof(struct vbo_save_vertex_list));
552    node->cold = calloc(1, sizeof(*node->cold));
553
554    /* Make sure the pointer is aligned to the size of a pointer */
555    assert((GLintptr) node % sizeof(void *) == 0);
556
557    /* Duplicate our template, increment refcounts to the storage structs:
558     */
559    GLintptr old_offset = 0;
560    if (save->VAO[0]) {
561       old_offset = save->VAO[0]->BufferBinding[0].Offset
562          + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset;
563    }
564    const GLsizei stride = save->vertex_size*sizeof(GLfloat);
565    GLintptr buffer_offset =
566        (save->buffer_map - save->vertex_store->buffer_in_ram) * sizeof(GLfloat);
567    const GLintptr original_buffer_offset = buffer_offset;
568    assert(old_offset <= buffer_offset);
569    const GLintptr offset_diff = buffer_offset - old_offset;
570    GLuint start_offset = 0;
571    if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) {
572       /* The vertex size is an exact multiple of the buffer offset.
573        * This means that we can use zero-based vertex attribute pointers
574        * and specify the start of the primitive with the _mesa_prim::start
575        * field.  This results in issuing several draw calls with identical
576        * vertex attribute information.  This can result in fewer state
577        * changes in drivers.  In particular, the Gallium CSO module will
578        * filter out redundant vertex buffer changes.
579        */
580       /* We cannot immediately update the primitives as some methods below
581        * still need the uncorrected start vertices
582        */
583       start_offset = offset_diff/stride;
584       assert(old_offset == buffer_offset - offset_diff);
585       buffer_offset = old_offset;
586    }
587    GLuint offsets[VBO_ATTRIB_MAX];
588    for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) {
589       offsets[i] = offset;
590       offset += save->attrsz[i] * sizeof(GLfloat);
591    }
592    node->cold->vertex_count = save->vert_count;
593    node->cold->wrap_count = save->copied.nr;
594    node->cold->prims = save->prims;
595    node->cold->ib.obj = NULL;
596    node->cold->prim_count = save->prim_count;
597    node->cold->prim_store = save->prim_store;
598
599    /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs
600     * Note that this may reuse the previous one of possible.
601     */
602    for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) {
603       /* create or reuse the vao */
604       update_vao(ctx, vpm, &save->VAO[vpm],
605                  save->vertex_store->bufferobj, buffer_offset, stride,
606                  save->enabled, save->attrsz, save->attrtype, offsets);
607       /* Reference the vao in the dlist */
608       node->VAO[vpm] = NULL;
609       _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]);
610    }
611
612    node->cold->prim_store->refcount++;
613
614    if (save->no_current_update) {
615       node->cold->current_data = NULL;
616    }
617    else {
618       GLuint current_size = save->vertex_size - save->attrsz[0];
619       node->cold->current_data = NULL;
620
621       if (current_size) {
622          node->cold->current_data = malloc(current_size * sizeof(GLfloat));
623          if (node->cold->current_data) {
624             const char *buffer = (const char *)save->buffer_map;
625             unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat);
626             unsigned vertex_offset = 0;
627
628             if (node->cold->vertex_count)
629                vertex_offset = (node->cold->vertex_count - 1) * stride;
630
631             memcpy(node->cold->current_data, buffer + vertex_offset + attr_offset,
632                    current_size * sizeof(GLfloat));
633          } else {
634             _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation");
635          }
636       }
637    }
638
639    assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->cold->vertex_count == 0);
640
641    if (save->dangling_attr_ref)
642       ctx->ListState.Current.UseLoopback = true;
643
644    save->vertex_store->used += save->vertex_size * node->cold->vertex_count;
645    save->prim_store->used += node->cold->prim_count;
646
647    /* Copy duplicated vertices
648     */
649    save->copied.nr = copy_vertices(ctx, node, save->buffer_map);
650
651    if (node->cold->prims[node->cold->prim_count - 1].mode == GL_LINE_LOOP) {
652       convert_line_loop_to_strip(save, node);
653    }
654
655    merge_prims(ctx, node->cold->prims, &node->cold->prim_count);
656
657    /* Correct the primitive starts, we can only do this here as copy_vertices
658     * and convert_line_loop_to_strip above consume the uncorrected starts.
659     * On the other hand the _vbo_loopback_vertex_list call below needs the
660     * primitves to be corrected already.
661     */
662    for (unsigned i = 0; i < node->cold->prim_count; i++) {
663       node->cold->prims[i].start += start_offset;
664    }
665
666    /* Create an index buffer. */
667    node->cold->min_index = node->cold->max_index = 0;
668    if (save->vert_count == 0 || save->prim_count == 0)
669       goto end;
670
671    /* We won't modify node->prims, so use a const alias to avoid unintended
672     * writes to it. */
673    const struct _mesa_prim *original_prims = node->cold->prims;
674
675    int end = original_prims[node->cold->prim_count - 1].start +
676              original_prims[node->cold->prim_count - 1].count;
677    int total_vert_count = end - original_prims[0].start;
678
679    node->cold->min_index = node->cold->prims[0].start;
680    node->cold->max_index = end - 1;
681
682    /* Estimate for the worst case: all prims are line strips (the +1 is because
683     * wrap_buffers may call use but the last primitive may not be complete) */
684    int max_indices_count = MAX2(total_vert_count * 2 - (node->cold->prim_count * 2) + 1,
685                                 total_vert_count);
686
687    int indices_offset = 0;
688    int available = save->previous_ib ? (save->previous_ib->Size / 4 - save->ib_first_free_index) : 0;
689    if (available >= max_indices_count) {
690       indices_offset = save->ib_first_free_index;
691    }
692    int size = max_indices_count * sizeof(uint32_t);
693    uint32_t* indices = (uint32_t*) malloc(size);
694    struct _mesa_prim *merged_prims = NULL;
695
696    int idx = 0;
697    struct hash_table *vertex_to_index = NULL;
698    fi_type *temp_vertices_buffer = NULL;
699
700    /* The loopback replay code doesn't use the index buffer, so we can't
701     * dedup vertices in this case.
702     */
703    if (!ctx->ListState.Current.UseLoopback) {
704       vertex_to_index = _mesa_hash_table_create(NULL, _hash_vertex_key, _compare_vertex_key);
705       temp_vertices_buffer = malloc(save->vertex_store->buffer_in_ram_size);
706    }
707
708    uint32_t max_index = 0;
709
710    int last_valid_prim = -1;
711    /* Construct indices array. */
712    for (unsigned i = 0; i < node->cold->prim_count; i++) {
713       assert(original_prims[i].basevertex == 0);
714       GLubyte mode = original_prims[i].mode;
715
716       int vertex_count = original_prims[i].count;
717       if (!vertex_count) {
718          continue;
719       }
720
721       /* Line strips may get converted to lines */
722       if (mode == GL_LINE_STRIP)
723          mode = GL_LINES;
724
725       /* If 2 consecutive prims use the same mode => merge them. */
726       bool merge_prims = last_valid_prim >= 0 &&
727                          mode == merged_prims[last_valid_prim].mode &&
728                          mode != GL_LINE_LOOP && mode != GL_TRIANGLE_FAN &&
729                          mode != GL_QUAD_STRIP && mode != GL_POLYGON &&
730                          mode != GL_PATCHES;
731
732       /* To be able to merge consecutive triangle strips we need to insert
733        * a degenerate triangle.
734        */
735       if (merge_prims &&
736           mode == GL_TRIANGLE_STRIP) {
737          /* Insert a degenerate triangle */
738          assert(merged_prims[last_valid_prim].mode == GL_TRIANGLE_STRIP);
739          unsigned tri_count = merged_prims[last_valid_prim].count - 2;
740
741          indices[idx] = indices[idx - 1];
742          indices[idx + 1] = add_vertex(save, vertex_to_index, original_prims[i].start,
743                                        original_buffer_offset, start_offset,
744                                        temp_vertices_buffer, &max_index);
745          idx += 2;
746          merged_prims[last_valid_prim].count += 2;
747
748          if (tri_count % 2) {
749             /* Add another index to preserve winding order */
750             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start,
751                                         original_buffer_offset, start_offset,
752                                         temp_vertices_buffer, &max_index);
753             merged_prims[last_valid_prim].count++;
754          }
755       }
756
757       int start = idx;
758
759       /* Convert line strips to lines if it'll allow if the previous
760        * prim mode is GL_LINES (so merge_prims is true) or if the next
761        * primitive mode is GL_LINES or GL_LINE_LOOP.
762        */
763       if (original_prims[i].mode == GL_LINE_STRIP &&
764           (merge_prims ||
765            (i < node->cold->prim_count - 1 &&
766             (original_prims[i + 1].mode == GL_LINE_STRIP ||
767              original_prims[i + 1].mode == GL_LINES)))) {
768          for (unsigned j = 0; j < vertex_count; j++) {
769             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
770                                         original_buffer_offset, start_offset,
771                                         temp_vertices_buffer, &max_index);
772             /* Repeat all but the first/last indices. */
773             if (j && j != vertex_count - 1) {
774                indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
775                                            original_buffer_offset, start_offset,
776                                            temp_vertices_buffer, &max_index);
777             }
778          }
779       } else {
780          /* We didn't convert to LINES, so restore the original mode */
781          mode = original_prims[i].mode;
782
783          for (unsigned j = 0; j < vertex_count; j++) {
784             indices[idx++] = add_vertex(save, vertex_to_index, original_prims[i].start + j,
785                                         original_buffer_offset, start_offset,
786                                         temp_vertices_buffer, &max_index);
787          }
788       }
789
790       if (merge_prims) {
791          /* Update vertex count. */
792          merged_prims[last_valid_prim].count += idx - start;
793       } else {
794          /* Keep this primitive */
795          last_valid_prim += 1;
796          assert(last_valid_prim <= i);
797          merged_prims = realloc(merged_prims, (1 + last_valid_prim) * sizeof(struct _mesa_prim));
798          merged_prims[last_valid_prim] = original_prims[i];
799          merged_prims[last_valid_prim].start = indices_offset + start;
800          merged_prims[last_valid_prim].count = idx - start;
801       }
802       merged_prims[last_valid_prim].mode = mode;
803    }
804
805    assert(idx > 0 && idx <= max_indices_count);
806
807    unsigned merged_prim_count = last_valid_prim + 1;
808    node->cold->ib.ptr = NULL;
809    node->cold->ib.count = idx;
810    node->cold->ib.index_size_shift = (GL_UNSIGNED_INT - GL_UNSIGNED_BYTE) >> 1;
811
812    if (!indices_offset) {
813       /* Allocate a new index buffer */
814       _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
815       save->previous_ib = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID + 1);
816       bool success = ctx->Driver.BufferData(ctx,
817                                             GL_ELEMENT_ARRAY_BUFFER_ARB,
818                                             MAX2(VBO_SAVE_INDEX_SIZE, idx) * sizeof(uint32_t),
819                                             NULL,
820                                             GL_STATIC_DRAW_ARB, GL_MAP_WRITE_BIT,
821                                             save->previous_ib);
822       if (!success) {
823          _mesa_reference_buffer_object(ctx, &save->previous_ib, NULL);
824          _mesa_error(ctx, GL_OUT_OF_MEMORY, "IB allocation");
825       }
826    }
827
828    _mesa_reference_buffer_object(ctx, &node->cold->ib.obj, save->previous_ib);
829
830    if (node->cold->ib.obj) {
831       ctx->Driver.BufferSubData(ctx,
832                                 indices_offset * sizeof(uint32_t),
833                                 idx * sizeof(uint32_t),
834                                 indices,
835                                 node->cold->ib.obj);
836       save->ib_first_free_index = indices_offset + idx;
837    } else {
838       node->cold->vertex_count = 0;
839       node->cold->prim_count = 0;
840    }
841
842
843   if (vertex_to_index) {
844       ctx->Driver.BufferSubData(ctx,
845                                 original_buffer_offset,
846                                 (max_index - start_offset + 1) * save->vertex_size * sizeof(fi_type),
847                                 temp_vertices_buffer,
848                                 save->vertex_store->bufferobj);
849
850       _mesa_hash_table_destroy(vertex_to_index, _free_entry);
851       free(temp_vertices_buffer);
852    } else {
853       ctx->Driver.BufferSubData(ctx,
854                                 original_buffer_offset,
855                                 idx * save->vertex_size * sizeof(fi_type),
856                                 &save->vertex_store->buffer_in_ram[original_buffer_offset / sizeof(float)],
857                                 save->vertex_store->bufferobj);
858    }
859
860    /* Prepare for DrawGallium */
861    memset(&node->merged.info, 0, sizeof(struct pipe_draw_info));
862    /* The other info fields will be updated in vbo_save_playback_vertex_list */
863    node->merged.info.index_size = 4;
864    node->merged.info.instance_count = 1;
865    node->merged.info.index.gl_bo = node->cold->ib.obj;
866    if (merged_prim_count == 1) {
867       node->merged.info.mode = merged_prims[0].mode;
868       node->merged.start_count.start = merged_prims[0].start;
869       node->merged.start_count.count = merged_prims[0].count;
870       node->merged.start_count.index_bias = 0;
871       node->merged.mode = NULL;
872    } else {
873       node->merged.mode = malloc(merged_prim_count * sizeof(unsigned char));
874       node->merged.start_counts = malloc(merged_prim_count * sizeof(struct pipe_draw_start_count_bias));
875       for (unsigned i = 0; i < merged_prim_count; i++) {
876          node->merged.start_counts[i].start = merged_prims[i].start;
877          node->merged.start_counts[i].count = merged_prims[i].count;
878          node->merged.start_counts[i].index_bias = 0;
879          node->merged.mode[i] = merged_prims[i].mode;
880       }
881    }
882    node->merged.num_draws = merged_prim_count;
883    if (node->merged.num_draws > 1) {
884       bool same_mode = true;
885       for (unsigned i = 1; i < node->merged.num_draws && same_mode; i++) {
886          same_mode = node->merged.mode[i] == node->merged.mode[0];
887       }
888       if (same_mode) {
889          /* All primitives use the same mode, so we can simplify a bit */
890          node->merged.info.mode = node->merged.mode[0];
891          free(node->merged.mode);
892          node->merged.mode = NULL;
893       }
894    }
895
896    free(indices);
897    free(merged_prims);
898
899 end:
900    /* Deal with GL_COMPILE_AND_EXECUTE:
901     */
902    if (ctx->ExecuteFlag) {
903       struct _glapi_table *dispatch = GET_DISPATCH();
904
905       _glapi_set_dispatch(ctx->Exec);
906
907       /* Note that the range of referenced vertices must be mapped already */
908       _vbo_loopback_vertex_list(ctx, node, save->vertex_store->buffer_in_ram);
909
910       _glapi_set_dispatch(dispatch);
911    }
912
913    /* Decide whether the storage structs are full, or can be used for
914     * the next vertex lists as well.
915     */
916    if (save->vertex_store->used >
917        save->vertex_store->bufferobj->Size / sizeof(float) - 16 * (save->vertex_size + 4)) {
918       realloc_storage(ctx, -1, 0);
919    }
920    else {
921       /* update buffer_ptr for next vertex */
922       save->buffer_ptr = save->vertex_store->buffer_in_ram
923          + save->vertex_store->used;
924    }
925
926    if (save->prim_store->used > save->prim_store->size - 6) {
927       realloc_storage(ctx, 0, -1);
928    }
929
930    /* Reset our structures for the next run of vertices:
931     */
932    reset_counters(ctx);
933 }
934
935
936 /**
937  * This is called when we fill a vertex buffer before we hit a glEnd().
938  * We
939  * TODO -- If no new vertices have been stored, don't bother saving it.
940  */
941 static void
942 wrap_buffers(struct gl_context *ctx)
943 {
944    struct vbo_save_context *save = &vbo_context(ctx)->save;
945    GLint i = save->prim_count - 1;
946    GLenum mode;
947
948    assert(i < (GLint) save->prim_max);
949    assert(i >= 0);
950
951    /* Close off in-progress primitive.
952     */
953    save->prims[i].count = (save->vert_count - save->prims[i].start);
954    mode = save->prims[i].mode;
955
956    /* store the copied vertices, and allocate a new list.
957     */
958    compile_vertex_list(ctx);
959
960    /* Restart interrupted primitive
961     */
962    save->prims[0].mode = mode;
963    save->prims[0].begin = 0;
964    save->prims[0].end = 0;
965    save->prims[0].start = 0;
966    save->prims[0].count = 0;
967    save->prim_count = 1;
968 }
969
970
971 /**
972  * Called only when buffers are wrapped as the result of filling the
973  * vertex_store struct.
974  */
975 static void
976 wrap_filled_vertex(struct gl_context *ctx)
977 {
978    struct vbo_save_context *save = &vbo_context(ctx)->save;
979    unsigned numComponents;
980
981    /* Emit a glEnd to close off the last vertex list.
982     */
983    wrap_buffers(ctx);
984
985    /* Copy stored stored vertices to start of new list.
986     */
987    assert(save->max_vert - save->vert_count > save->copied.nr);
988
989    numComponents = save->copied.nr * save->vertex_size;
990    memcpy(save->buffer_ptr,
991           save->copied.buffer,
992           numComponents * sizeof(fi_type));
993    save->buffer_ptr += numComponents;
994    save->vert_count += save->copied.nr;
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->bufferobj->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->buffer_ptr = dest;
1148       save->vert_count += 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                                                                 \
1251       for (i = 0; i < save->vertex_size; i++)                   \
1252          save->buffer_ptr[i] = save->vertex[i];                 \
1253                                                                 \
1254       save->buffer_ptr += save->vertex_size;                    \
1255                                                                 \
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_count) {
1335       if (save->prim_count > 0) {
1336          /* Close off in-progress primitive. */
1337          GLint i = save->prim_count - 1;
1338          save->prims[i].count = save->vert_count - save->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_count++;
1439
1440    ctx->Driver.CurrentSavePrimitive = mode;
1441
1442    assert(i < save->prim_max);
1443    save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1444    save->prims[i].begin = 1;
1445    save->prims[i].end = 0;
1446    save->prims[i].start = save->vert_count;
1447    save->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_count - 1;
1469
1470    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1471    save->prims[i].end = 1;
1472    save->prims[i].count = (save->vert_count - save->prims[i].start);
1473
1474    if (i == (GLint) save->prim_max - 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_count == 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->prims[save->prim_count - 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_count + primcount > save->prim_max;
1593    bool realloc_vert = save->vertex_size && (save->vert_count + vertcount >= save->max_vert);
1594
1595    if (realloc_prim || realloc_vert) {
1596       if (save->vert_count || save->prim_count)
1597          compile_vertex_list(ctx);
1598       realloc_storage(ctx, realloc_prim ? primcount : -1, realloc_vert ? vertcount : -1);
1599       reset_counters(ctx);
1600       assert(save->prim_max);
1601    }
1602 }
1603
1604
1605 static void GLAPIENTRY
1606 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1607 {
1608    GET_CURRENT_CONTEXT(ctx);
1609    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1610    struct vbo_save_context *save = &vbo_context(ctx)->save;
1611    GLint i;
1612
1613    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1614       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1615       return;
1616    }
1617    if (count < 0) {
1618       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1619       return;
1620    }
1621
1622    if (save->out_of_memory)
1623       return;
1624
1625    _ensure_draws_fits_in_storage(ctx, 1, count);
1626
1627    /* Make sure to process any VBO binding changes */
1628    _mesa_update_state(ctx);
1629
1630    _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT);
1631
1632    vbo_save_NotifyBegin(ctx, mode, true);
1633
1634    for (i = 0; i < count; i++)
1635       _mesa_array_element(ctx, start + i);
1636    CALL_End(ctx->CurrentServerDispatch, ());
1637
1638    _mesa_vao_unmap_arrays(ctx, vao);
1639 }
1640
1641
1642 static void GLAPIENTRY
1643 _save_OBE_MultiDrawArrays(GLenum mode, const GLint *first,
1644                           const GLsizei *count, GLsizei primcount)
1645 {
1646    GET_CURRENT_CONTEXT(ctx);
1647    GLint i;
1648
1649    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1650       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)");
1651       return;
1652    }
1653
1654    if (primcount < 0) {
1655       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1656                           "glMultiDrawArrays(primcount<0)");
1657       return;
1658    }
1659
1660    unsigned vertcount = 0;
1661    for (i = 0; i < primcount; i++) {
1662       if (count[i] < 0) {
1663          _mesa_compile_error(ctx, GL_INVALID_VALUE,
1664                              "glMultiDrawArrays(count[i]<0)");
1665          return;
1666       }
1667       vertcount += count[i];
1668    }
1669
1670    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1671
1672    for (i = 0; i < primcount; i++) {
1673       if (count[i] > 0) {
1674          _save_OBE_DrawArrays(mode, first[i], count[i]);
1675       }
1676    }
1677 }
1678
1679
1680 static void
1681 array_element(struct gl_context *ctx,
1682               GLint basevertex, GLuint elt, unsigned index_size_shift)
1683 {
1684    /* Section 10.3.5 Primitive Restart:
1685     * [...]
1686     *    When one of the *BaseVertex drawing commands specified in section 10.5
1687     * is used, the primitive restart comparison occurs before the basevertex
1688     * offset is added to the array index.
1689     */
1690    /* If PrimitiveRestart is enabled and the index is the RestartIndex
1691     * then we call PrimitiveRestartNV and return.
1692     */
1693    if (ctx->Array._PrimitiveRestart[index_size_shift] &&
1694        elt == ctx->Array._RestartIndex[index_size_shift]) {
1695       CALL_PrimitiveRestartNV(ctx->CurrentServerDispatch, ());
1696       return;
1697    }
1698
1699    _mesa_array_element(ctx, basevertex + elt);
1700 }
1701
1702
1703 /* Could do better by copying the arrays and element list intact and
1704  * then emitting an indexed prim at runtime.
1705  */
1706 static void GLAPIENTRY
1707 _save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
1708                                  const GLvoid * indices, GLint basevertex)
1709 {
1710    GET_CURRENT_CONTEXT(ctx);
1711    struct vbo_save_context *save = &vbo_context(ctx)->save;
1712    struct gl_vertex_array_object *vao = ctx->Array.VAO;
1713    struct gl_buffer_object *indexbuf = vao->IndexBufferObj;
1714    GLint i;
1715
1716    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1717       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1718       return;
1719    }
1720    if (count < 0) {
1721       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1722       return;
1723    }
1724    if (type != GL_UNSIGNED_BYTE &&
1725        type != GL_UNSIGNED_SHORT &&
1726        type != GL_UNSIGNED_INT) {
1727       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1728       return;
1729    }
1730
1731    if (save->out_of_memory)
1732       return;
1733
1734    _ensure_draws_fits_in_storage(ctx, 1, count);
1735
1736    /* Make sure to process any VBO binding changes */
1737    _mesa_update_state(ctx);
1738
1739    _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT);
1740
1741    if (indexbuf)
1742       indices =
1743          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1744
1745    vbo_save_NotifyBegin(ctx, mode, true);
1746
1747    switch (type) {
1748    case GL_UNSIGNED_BYTE:
1749       for (i = 0; i < count; i++)
1750          array_element(ctx, basevertex, ((GLubyte *) indices)[i], 0);
1751       break;
1752    case GL_UNSIGNED_SHORT:
1753       for (i = 0; i < count; i++)
1754          array_element(ctx, basevertex, ((GLushort *) indices)[i], 1);
1755       break;
1756    case GL_UNSIGNED_INT:
1757       for (i = 0; i < count; i++)
1758          array_element(ctx, basevertex, ((GLuint *) indices)[i], 2);
1759       break;
1760    default:
1761       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1762       break;
1763    }
1764
1765    CALL_End(ctx->CurrentServerDispatch, ());
1766
1767    _mesa_vao_unmap(ctx, vao);
1768 }
1769
1770 static void GLAPIENTRY
1771 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1772                        const GLvoid * indices)
1773 {
1774    _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0);
1775 }
1776
1777
1778 static void GLAPIENTRY
1779 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1780                             GLsizei count, GLenum type,
1781                             const GLvoid * indices)
1782 {
1783    GET_CURRENT_CONTEXT(ctx);
1784    struct vbo_save_context *save = &vbo_context(ctx)->save;
1785
1786    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1787       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1788       return;
1789    }
1790    if (count < 0) {
1791       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1792                           "glDrawRangeElements(count<0)");
1793       return;
1794    }
1795    if (type != GL_UNSIGNED_BYTE &&
1796        type != GL_UNSIGNED_SHORT &&
1797        type != GL_UNSIGNED_INT) {
1798       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1799       return;
1800    }
1801    if (end < start) {
1802       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1803                           "glDrawRangeElements(end < start)");
1804       return;
1805    }
1806
1807    if (save->out_of_memory)
1808       return;
1809
1810    _save_OBE_DrawElements(mode, count, type, indices);
1811 }
1812
1813
1814 static void GLAPIENTRY
1815 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1816                             const GLvoid * const *indices, GLsizei primcount)
1817 {
1818    GET_CURRENT_CONTEXT(ctx);
1819    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1820    GLsizei i;
1821
1822    int vertcount = 0;
1823    for (i = 0; i < primcount; i++) {
1824       vertcount += count[i];
1825    }
1826    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1827
1828    for (i = 0; i < primcount; i++) {
1829       if (count[i] > 0) {
1830          CALL_DrawElements(dispatch, (mode, count[i], type, indices[i]));
1831       }
1832    }
1833 }
1834
1835
1836 static void GLAPIENTRY
1837 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1838                                       GLenum type,
1839                                       const GLvoid * const *indices,
1840                                       GLsizei primcount,
1841                                       const GLint *basevertex)
1842 {
1843    GET_CURRENT_CONTEXT(ctx);
1844    struct _glapi_table *dispatch = ctx->CurrentServerDispatch;
1845    GLsizei i;
1846
1847    int vertcount = 0;
1848    for (i = 0; i < primcount; i++) {
1849       vertcount += count[i];
1850    }
1851    _ensure_draws_fits_in_storage(ctx, primcount, vertcount);
1852
1853    for (i = 0; i < primcount; i++) {
1854       if (count[i] > 0) {
1855          CALL_DrawElementsBaseVertex(dispatch, (mode, count[i], type,
1856                                                       indices[i],
1857                                                       basevertex[i]));
1858       }
1859    }
1860 }
1861
1862
1863 static void
1864 vtxfmt_init(struct gl_context *ctx)
1865 {
1866    struct vbo_save_context *save = &vbo_context(ctx)->save;
1867    GLvertexformat *vfmt = &save->vtxfmt;
1868
1869 #define NAME_AE(x) _ae_##x
1870 #define NAME_CALLLIST(x) _save_##x
1871 #define NAME(x) _save_##x
1872 #define NAME_ES(x) _save_##x##ARB
1873
1874 #include "vbo_init_tmp.h"
1875 }
1876
1877
1878 /**
1879  * Initialize the dispatch table with the VBO functions for display
1880  * list compilation.
1881  */
1882 void
1883 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1884                              struct _glapi_table *exec)
1885 {
1886    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1887    SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays);
1888    SET_DrawElements(exec, _save_OBE_DrawElements);
1889    SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex);
1890    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1891    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1892    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1893    SET_Rectf(exec, _save_OBE_Rectf);
1894    SET_Rectd(exec, _save_OBE_Rectd);
1895    SET_Rectdv(exec, _save_OBE_Rectdv);
1896    SET_Rectfv(exec, _save_OBE_Rectfv);
1897    SET_Recti(exec, _save_OBE_Recti);
1898    SET_Rectiv(exec, _save_OBE_Rectiv);
1899    SET_Rects(exec, _save_OBE_Rects);
1900    SET_Rectsv(exec, _save_OBE_Rectsv);
1901
1902    /* Note: other glDraw functins aren't compiled into display lists */
1903 }
1904
1905
1906
1907 void
1908 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1909 {
1910    struct vbo_save_context *save = &vbo_context(ctx)->save;
1911
1912    /* Noop when we are actually active:
1913     */
1914    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1915       return;
1916
1917    if (save->vert_count || save->prim_count)
1918       compile_vertex_list(ctx);
1919
1920    copy_to_current(ctx);
1921    reset_vertex(ctx);
1922    reset_counters(ctx);
1923    ctx->Driver.SaveNeedFlush = GL_FALSE;
1924 }
1925
1926
1927 /**
1928  * Called from glNewList when we're starting to compile a display list.
1929  */
1930 void
1931 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1932 {
1933    struct vbo_save_context *save = &vbo_context(ctx)->save;
1934
1935    (void) list;
1936    (void) mode;
1937
1938    if (!save->prim_store)
1939       save->prim_store = alloc_prim_store(0);
1940
1941    if (!save->vertex_store)
1942       save->vertex_store = alloc_vertex_store(ctx, 0);
1943
1944    save->buffer_ptr = save->vertex_store->buffer_in_ram + save->vertex_store->used;
1945
1946    reset_vertex(ctx);
1947    reset_counters(ctx);
1948    ctx->Driver.SaveNeedFlush = GL_FALSE;
1949 }
1950
1951
1952 /**
1953  * Called from glEndList when we're finished compiling a display list.
1954  */
1955 void
1956 vbo_save_EndList(struct gl_context *ctx)
1957 {
1958    struct vbo_save_context *save = &vbo_context(ctx)->save;
1959
1960    /* EndList called inside a (saved) Begin/End pair?
1961     */
1962    if (_mesa_inside_dlist_begin_end(ctx)) {
1963       if (save->prim_count > 0) {
1964          GLint i = save->prim_count - 1;
1965          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1966          save->prims[i].end = 0;
1967          save->prims[i].count = save->vert_count - save->prims[i].start;
1968       }
1969
1970       /* Make sure this vertex list gets replayed by the "loopback"
1971        * mechanism:
1972        */
1973       save->dangling_attr_ref = GL_TRUE;
1974       vbo_save_SaveFlushVertices(ctx);
1975
1976       /* Swap out this vertex format while outside begin/end.  Any color,
1977        * etc. received between here and the next begin will be compiled
1978        * as opcodes.
1979        */
1980       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1981    }
1982
1983    assert(save->vertex_size == 0);
1984 }
1985
1986 /**
1987  * Called during context creation/init.
1988  */
1989 static void
1990 current_init(struct gl_context *ctx)
1991 {
1992    struct vbo_save_context *save = &vbo_context(ctx)->save;
1993    GLint i;
1994
1995    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1996       const GLuint j = i - VBO_ATTRIB_POS;
1997       assert(j < VERT_ATTRIB_MAX);
1998       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1999       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
2000    }
2001
2002    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
2003       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
2004       assert(j < MAT_ATTRIB_MAX);
2005       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
2006       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
2007    }
2008 }
2009
2010
2011 /**
2012  * Initialize the display list compiler.  Called during context creation.
2013  */
2014 void
2015 vbo_save_api_init(struct vbo_save_context *save)
2016 {
2017    struct gl_context *ctx = gl_context_from_vbo_save(save);
2018
2019    vtxfmt_init(ctx);
2020    current_init(ctx);
2021    _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop);
2022 }