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