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