OSDN Git Service

virgl: add openarena readpixels workaround.
[android-x86/external-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/bufferobj.h"
72 #include "main/context.h"
73 #include "main/dlist.h"
74 #include "main/enums.h"
75 #include "main/eval.h"
76 #include "main/macros.h"
77 #include "main/api_validate.h"
78 #include "main/api_arrayelt.h"
79 #include "main/vtxfmt.h"
80 #include "main/dispatch.h"
81
82 #include "vbo_context.h"
83 #include "vbo_noop.h"
84
85
86 #ifdef ERROR
87 #undef ERROR
88 #endif
89
90
91 /* An interesting VBO number/name to help with debugging */
92 #define VBO_BUF_ID  12345
93
94
95 /*
96  * NOTE: Old 'parity' issue is gone, but copying can still be
97  * wrong-footed on replay.
98  */
99 static GLuint
100 _save_copy_vertices(struct gl_context *ctx,
101                     const struct vbo_save_vertex_list *node,
102                     const fi_type * src_buffer)
103 {
104    struct vbo_save_context *save = &vbo_context(ctx)->save;
105    const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
106    GLuint nr = prim->count;
107    GLuint sz = save->vertex_size;
108    const fi_type *src = src_buffer + prim->start * sz;
109    fi_type *dst = save->copied.buffer;
110    GLuint ovf, i;
111
112    if (prim->end)
113       return 0;
114
115    switch (prim->mode) {
116    case GL_POINTS:
117       return 0;
118    case GL_LINES:
119       ovf = nr & 1;
120       for (i = 0; i < ovf; i++)
121          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
122                 sz * sizeof(GLfloat));
123       return i;
124    case GL_TRIANGLES:
125       ovf = nr % 3;
126       for (i = 0; i < ovf; i++)
127          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
128                 sz * sizeof(GLfloat));
129       return i;
130    case GL_QUADS:
131       ovf = nr & 3;
132       for (i = 0; i < ovf; i++)
133          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
134                 sz * sizeof(GLfloat));
135       return i;
136    case GL_LINE_STRIP:
137       if (nr == 0)
138          return 0;
139       else {
140          memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat));
141          return 1;
142       }
143    case GL_LINE_LOOP:
144    case GL_TRIANGLE_FAN:
145    case GL_POLYGON:
146       if (nr == 0)
147          return 0;
148       else if (nr == 1) {
149          memcpy(dst, src + 0, sz * sizeof(GLfloat));
150          return 1;
151       }
152       else {
153          memcpy(dst, src + 0, sz * sizeof(GLfloat));
154          memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
155          return 2;
156       }
157    case GL_TRIANGLE_STRIP:
158    case GL_QUAD_STRIP:
159       switch (nr) {
160       case 0:
161          ovf = 0;
162          break;
163       case 1:
164          ovf = 1;
165          break;
166       default:
167          ovf = 2 + (nr & 1);
168          break;
169       }
170       for (i = 0; i < ovf; i++)
171          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
172                 sz * sizeof(GLfloat));
173       return i;
174    default:
175       assert(0);
176       return 0;
177    }
178 }
179
180
181 static struct vbo_save_vertex_store *
182 alloc_vertex_store(struct gl_context *ctx)
183 {
184    struct vbo_save_context *save = &vbo_context(ctx)->save;
185    struct vbo_save_vertex_store *vertex_store =
186       CALLOC_STRUCT(vbo_save_vertex_store);
187
188    /* obj->Name needs to be non-zero, but won't ever be examined more
189     * closely than that.  In particular these buffers won't be entered
190     * into the hash and can never be confused with ones visible to the
191     * user.  Perhaps there could be a special number for internal
192     * buffers:
193     */
194    vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID);
195    if (vertex_store->bufferobj) {
196       save->out_of_memory =
197          !ctx->Driver.BufferData(ctx,
198                                  GL_ARRAY_BUFFER_ARB,
199                                  VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
200                                  NULL, GL_STATIC_DRAW_ARB,
201                                  GL_MAP_WRITE_BIT |
202                                  GL_DYNAMIC_STORAGE_BIT,
203                                  vertex_store->bufferobj);
204    }
205    else {
206       save->out_of_memory = GL_TRUE;
207    }
208
209    if (save->out_of_memory) {
210       _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
211       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
212    }
213
214    vertex_store->buffer = NULL;
215    vertex_store->used = 0;
216    vertex_store->refcount = 1;
217
218    return vertex_store;
219 }
220
221
222 static void
223 free_vertex_store(struct gl_context *ctx,
224                   struct vbo_save_vertex_store *vertex_store)
225 {
226    assert(!vertex_store->buffer);
227
228    if (vertex_store->bufferobj) {
229       _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
230    }
231
232    free(vertex_store);
233 }
234
235
236 fi_type *
237 vbo_save_map_vertex_store(struct gl_context *ctx,
238                           struct vbo_save_vertex_store *vertex_store)
239 {
240    const GLbitfield access = (GL_MAP_WRITE_BIT |
241                               GL_MAP_INVALIDATE_RANGE_BIT |
242                               GL_MAP_UNSYNCHRONIZED_BIT |
243                               GL_MAP_FLUSH_EXPLICIT_BIT);
244
245    assert(vertex_store->bufferobj);
246    assert(!vertex_store->buffer);  /* the buffer should not be mapped */
247
248    if (vertex_store->bufferobj->Size > 0) {
249       /* Map the remaining free space in the VBO */
250       GLintptr offset = vertex_store->used * sizeof(GLfloat);
251       GLsizeiptr size = vertex_store->bufferobj->Size - offset;
252       fi_type *range = (fi_type *)
253          ctx->Driver.MapBufferRange(ctx, offset, size, access,
254                                     vertex_store->bufferobj,
255                                     MAP_INTERNAL);
256       if (range) {
257          /* compute address of start of whole buffer (needed elsewhere) */
258          vertex_store->buffer = range - vertex_store->used;
259          assert(vertex_store->buffer);
260          return range;
261       }
262       else {
263          vertex_store->buffer = NULL;
264          return NULL;
265       }
266    }
267    else {
268       /* probably ran out of memory for buffers */
269       return NULL;
270    }
271 }
272
273
274 void
275 vbo_save_unmap_vertex_store(struct gl_context *ctx,
276                             struct vbo_save_vertex_store *vertex_store)
277 {
278    if (vertex_store->bufferobj->Size > 0) {
279       GLintptr offset = 0;
280       GLsizeiptr length = vertex_store->used * sizeof(GLfloat)
281          - vertex_store->bufferobj->Mappings[MAP_INTERNAL].Offset;
282
283       /* Explicitly flush the region we wrote to */
284       ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
285                                          vertex_store->bufferobj,
286                                          MAP_INTERNAL);
287
288       ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj, MAP_INTERNAL);
289    }
290    vertex_store->buffer = NULL;
291 }
292
293
294 static struct vbo_save_primitive_store *
295 alloc_prim_store(struct gl_context *ctx)
296 {
297    struct vbo_save_primitive_store *store =
298       CALLOC_STRUCT(vbo_save_primitive_store);
299    (void) ctx;
300    store->used = 0;
301    store->refcount = 1;
302    return store;
303 }
304
305
306 static void
307 _save_reset_counters(struct gl_context *ctx)
308 {
309    struct vbo_save_context *save = &vbo_context(ctx)->save;
310
311    save->prim = save->prim_store->buffer + save->prim_store->used;
312    save->buffer = save->vertex_store->buffer + save->vertex_store->used;
313
314    assert(save->buffer == save->buffer_ptr);
315
316    if (save->vertex_size)
317       save->max_vert = (VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
318                         save->vertex_size;
319    else
320       save->max_vert = 0;
321
322    save->vert_count = 0;
323    save->prim_count = 0;
324    save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
325    save->dangling_attr_ref = GL_FALSE;
326 }
327
328 /**
329  * For a list of prims, try merging prims that can just be extensions of the
330  * previous prim.
331  */
332 static void
333 merge_prims(struct _mesa_prim *prim_list,
334             GLuint *prim_count)
335 {
336    GLuint i;
337    struct _mesa_prim *prev_prim = prim_list;
338
339    for (i = 1; i < *prim_count; i++) {
340       struct _mesa_prim *this_prim = prim_list + i;
341
342       vbo_try_prim_conversion(this_prim);
343
344       if (vbo_can_merge_prims(prev_prim, this_prim)) {
345          /* We've found a prim that just extend the previous one.  Tack it
346           * onto the previous one, and let this primitive struct get dropped.
347           */
348          vbo_merge_prims(prev_prim, this_prim);
349          continue;
350       }
351
352       /* If any previous primitives have been dropped, then we need to copy
353        * this later one into the next available slot.
354        */
355       prev_prim++;
356       if (prev_prim != this_prim)
357          *prev_prim = *this_prim;
358    }
359
360    *prim_count = prev_prim - prim_list + 1;
361 }
362
363
364 /**
365  * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers
366  * don't have to worry about handling the _mesa_prim::begin/end flags.
367  * See https://bugs.freedesktop.org/show_bug.cgi?id=81174
368  */
369 static void
370 convert_line_loop_to_strip(struct vbo_save_context *save,
371                            struct vbo_save_vertex_list *node)
372 {
373    struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
374
375    assert(prim->mode == GL_LINE_LOOP);
376
377    if (prim->end) {
378       /* Copy the 0th vertex to end of the buffer and extend the
379        * vertex count by one to finish the line loop.
380        */
381       const GLuint sz = save->vertex_size;
382       /* 0th vertex: */
383       const fi_type *src = save->buffer + prim->start * sz;
384       /* end of buffer: */
385       fi_type *dst = save->buffer + (prim->start + prim->count) * sz;
386
387       memcpy(dst, src, sz * sizeof(float));
388
389       prim->count++;
390       node->count++;
391       save->vert_count++;
392       save->buffer_ptr += sz;
393       save->vertex_store->used += sz;
394    }
395
396    if (!prim->begin) {
397       /* Drawing the second or later section of a long line loop.
398        * Skip the 0th vertex.
399        */
400       prim->start++;
401       prim->count--;
402    }
403
404    prim->mode = GL_LINE_STRIP;
405 }
406
407
408 /**
409  * Insert the active immediate struct onto the display list currently
410  * being built.
411  */
412 static void
413 _save_compile_vertex_list(struct gl_context *ctx)
414 {
415    struct vbo_save_context *save = &vbo_context(ctx)->save;
416    struct vbo_save_vertex_list *node;
417
418    /* Allocate space for this structure in the display list currently
419     * being compiled.
420     */
421    node = (struct vbo_save_vertex_list *)
422       _mesa_dlist_alloc_aligned(ctx, save->opcode_vertex_list, sizeof(*node));
423
424    if (!node)
425       return;
426
427    /* Make sure the pointer is aligned to the size of a pointer */
428    assert((GLintptr) node % sizeof(void *) == 0);
429
430    /* Duplicate our template, increment refcounts to the storage structs:
431     */
432    memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
433    memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
434    node->vertex_size = save->vertex_size;
435    node->buffer_offset =
436       (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
437    node->count = save->vert_count;
438    node->wrap_count = save->copied.nr;
439    node->dangling_attr_ref = save->dangling_attr_ref;
440    node->prim = save->prim;
441    node->prim_count = save->prim_count;
442    node->vertex_store = save->vertex_store;
443    node->prim_store = save->prim_store;
444
445    node->vertex_store->refcount++;
446    node->prim_store->refcount++;
447
448    if (node->prim[0].no_current_update) {
449       node->current_size = 0;
450       node->current_data = NULL;
451    }
452    else {
453       node->current_size = node->vertex_size - node->attrsz[0];
454       node->current_data = NULL;
455
456       if (node->current_size) {
457          /* If the malloc fails, we just pull the data out of the VBO
458           * later instead.
459           */
460          node->current_data = malloc(node->current_size * sizeof(GLfloat));
461          if (node->current_data) {
462             const char *buffer = (const char *) save->vertex_store->buffer;
463             unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
464             unsigned vertex_offset = 0;
465
466             if (node->count)
467                vertex_offset =
468                   (node->count - 1) * node->vertex_size * sizeof(GLfloat);
469
470             memcpy(node->current_data,
471                    buffer + node->buffer_offset + vertex_offset + attr_offset,
472                    node->current_size * sizeof(GLfloat));
473          }
474       }
475    }
476
477    assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
478
479    if (save->dangling_attr_ref)
480       ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
481
482    save->vertex_store->used += save->vertex_size * node->count;
483    save->prim_store->used += node->prim_count;
484
485    /* Copy duplicated vertices
486     */
487    save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
488
489    if (node->prim[node->prim_count - 1].mode == GL_LINE_LOOP) {
490       convert_line_loop_to_strip(save, node);
491    }
492
493    merge_prims(node->prim, &node->prim_count);
494
495    /* Deal with GL_COMPILE_AND_EXECUTE:
496     */
497    if (ctx->ExecuteFlag) {
498       struct _glapi_table *dispatch = GET_DISPATCH();
499
500       _glapi_set_dispatch(ctx->Exec);
501
502       vbo_loopback_vertex_list(ctx,
503                                (const GLfloat *) ((const char *) save->
504                                                   vertex_store->buffer +
505                                                   node->buffer_offset),
506                                node->attrsz, node->prim, node->prim_count,
507                                node->wrap_count, node->vertex_size);
508
509       _glapi_set_dispatch(dispatch);
510    }
511
512    /* Decide whether the storage structs are full, or can be used for
513     * the next vertex lists as well.
514     */
515    if (save->vertex_store->used >
516        VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
517
518       /* Unmap old store:
519        */
520       vbo_save_unmap_vertex_store(ctx, save->vertex_store);
521
522       /* Release old reference:
523        */
524       save->vertex_store->refcount--;
525       assert(save->vertex_store->refcount != 0);
526       save->vertex_store = NULL;
527
528       /* Allocate and map new store:
529        */
530       save->vertex_store = alloc_vertex_store(ctx);
531       save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
532       save->out_of_memory = save->buffer_ptr == NULL;
533    }
534    else {
535       /* update buffer_ptr for next vertex */
536       save->buffer_ptr = save->vertex_store->buffer + save->vertex_store->used;
537    }
538
539    if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
540       save->prim_store->refcount--;
541       assert(save->prim_store->refcount != 0);
542       save->prim_store = alloc_prim_store(ctx);
543    }
544
545    /* Reset our structures for the next run of vertices:
546     */
547    _save_reset_counters(ctx);
548 }
549
550
551 /**
552  * This is called when we fill a vertex buffer before we hit a glEnd().
553  * We
554  * TODO -- If no new vertices have been stored, don't bother saving it.
555  */
556 static void
557 _save_wrap_buffers(struct gl_context *ctx)
558 {
559    struct vbo_save_context *save = &vbo_context(ctx)->save;
560    GLint i = save->prim_count - 1;
561    GLenum mode;
562    GLboolean weak;
563    GLboolean no_current_update;
564
565    assert(i < (GLint) save->prim_max);
566    assert(i >= 0);
567
568    /* Close off in-progress primitive.
569     */
570    save->prim[i].count = (save->vert_count - save->prim[i].start);
571    mode = save->prim[i].mode;
572    weak = save->prim[i].weak;
573    no_current_update = save->prim[i].no_current_update;
574
575    /* store the copied vertices, and allocate a new list.
576     */
577    _save_compile_vertex_list(ctx);
578
579    /* Restart interrupted primitive
580     */
581    save->prim[0].mode = mode;
582    save->prim[0].weak = weak;
583    save->prim[0].no_current_update = no_current_update;
584    save->prim[0].begin = 0;
585    save->prim[0].end = 0;
586    save->prim[0].pad = 0;
587    save->prim[0].start = 0;
588    save->prim[0].count = 0;
589    save->prim[0].num_instances = 1;
590    save->prim[0].base_instance = 0;
591    save->prim[0].is_indirect = 0;
592    save->prim_count = 1;
593 }
594
595
596 /**
597  * Called only when buffers are wrapped as the result of filling the
598  * vertex_store struct.
599  */
600 static void
601 _save_wrap_filled_vertex(struct gl_context *ctx)
602 {
603    struct vbo_save_context *save = &vbo_context(ctx)->save;
604    unsigned numComponents;
605
606    /* Emit a glEnd to close off the last vertex list.
607     */
608    _save_wrap_buffers(ctx);
609
610    /* Copy stored stored vertices to start of new list.
611     */
612    assert(save->max_vert - save->vert_count > save->copied.nr);
613
614    numComponents = save->copied.nr * save->vertex_size;
615    memcpy(save->buffer_ptr,
616           save->copied.buffer,
617           numComponents * sizeof(fi_type));
618    save->buffer_ptr += numComponents;
619    save->vert_count += save->copied.nr;
620 }
621
622
623 static void
624 _save_copy_to_current(struct gl_context *ctx)
625 {
626    struct vbo_save_context *save = &vbo_context(ctx)->save;
627    GLuint i;
628
629    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
630       if (save->attrsz[i]) {
631          save->currentsz[i][0] = save->attrsz[i];
632          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
633                                      save->attrptr[i], save->attrtype[i]);
634       }
635    }
636 }
637
638
639 static void
640 _save_copy_from_current(struct gl_context *ctx)
641 {
642    struct vbo_save_context *save = &vbo_context(ctx)->save;
643    GLint i;
644
645    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
646       switch (save->attrsz[i]) {
647       case 4:
648          save->attrptr[i][3] = save->current[i][3];
649       case 3:
650          save->attrptr[i][2] = save->current[i][2];
651       case 2:
652          save->attrptr[i][1] = save->current[i][1];
653       case 1:
654          save->attrptr[i][0] = save->current[i][0];
655       case 0:
656          break;
657       }
658    }
659 }
660
661
662 /**
663  * Called when we increase the size of a vertex attribute.  For example,
664  * if we've seen one or more glTexCoord2f() calls and now we get a
665  * glTexCoord3f() call.
666  * Flush existing data, set new attrib size, replay copied vertices.
667  */
668 static void
669 _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
670 {
671    struct vbo_save_context *save = &vbo_context(ctx)->save;
672    GLuint oldsz;
673    GLuint i;
674    fi_type *tmp;
675
676    /* Store the current run of vertices, and emit a GL_END.  Emit a
677     * BEGIN in the new buffer.
678     */
679    if (save->vert_count)
680       _save_wrap_buffers(ctx);
681    else
682       assert(save->copied.nr == 0);
683
684    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
685     * when the attribute already exists in the vertex and is having
686     * its size increased.
687     */
688    _save_copy_to_current(ctx);
689
690    /* Fix up sizes:
691     */
692    oldsz = save->attrsz[attr];
693    save->attrsz[attr] = newsz;
694
695    save->vertex_size += newsz - oldsz;
696    save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
697                      save->vertex_size);
698    save->vert_count = 0;
699
700    /* Recalculate all the attrptr[] values:
701     */
702    tmp = save->vertex;
703    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
704       if (save->attrsz[i]) {
705          save->attrptr[i] = tmp;
706          tmp += save->attrsz[i];
707       }
708       else {
709          save->attrptr[i] = NULL;       /* will not be dereferenced. */
710       }
711    }
712
713    /* Copy from current to repopulate the vertex with correct values.
714     */
715    _save_copy_from_current(ctx);
716
717    /* Replay stored vertices to translate them to new format here.
718     *
719     * If there are copied vertices and the new (upgraded) attribute
720     * has not been defined before, this list is somewhat degenerate,
721     * and will need fixup at runtime.
722     */
723    if (save->copied.nr) {
724       const fi_type *data = save->copied.buffer;
725       fi_type *dest = save->buffer;
726       GLuint j;
727
728       /* Need to note this and fix up at runtime (or loopback):
729        */
730       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
731          assert(oldsz == 0);
732          save->dangling_attr_ref = GL_TRUE;
733       }
734
735       for (i = 0; i < save->copied.nr; i++) {
736          for (j = 0; j < VBO_ATTRIB_MAX; j++) {
737             if (save->attrsz[j]) {
738                if (j == attr) {
739                   if (oldsz) {
740                      COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
741                                                  save->attrtype[j]);
742                      data += oldsz;
743                      dest += newsz;
744                   }
745                   else {
746                      COPY_SZ_4V(dest, newsz, save->current[attr]);
747                      dest += newsz;
748                   }
749                }
750                else {
751                   GLint sz = save->attrsz[j];
752                   COPY_SZ_4V(dest, sz, data);
753                   data += sz;
754                   dest += sz;
755                }
756             }
757          }
758       }
759
760       save->buffer_ptr = dest;
761       save->vert_count += save->copied.nr;
762    }
763 }
764
765
766 /**
767  * This is called when the size of a vertex attribute changes.
768  * For example, after seeing one or more glTexCoord2f() calls we
769  * get a glTexCoord4f() or glTexCoord1f() call.
770  */
771 static void
772 save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
773 {
774    struct vbo_save_context *save = &vbo_context(ctx)->save;
775
776    if (sz > save->attrsz[attr]) {
777       /* New size is larger.  Need to flush existing vertices and get
778        * an enlarged vertex format.
779        */
780       _save_upgrade_vertex(ctx, attr, sz);
781    }
782    else if (sz < save->active_sz[attr]) {
783       GLuint i;
784       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
785
786       /* New size is equal or smaller - just need to fill in some
787        * zeros.
788        */
789       for (i = sz; i <= save->attrsz[attr]; i++)
790          save->attrptr[attr][i - 1] = id[i - 1];
791    }
792
793    save->active_sz[attr] = sz;
794 }
795
796
797 /**
798  * Reset the current size of all vertex attributes to the default
799  * value of 0.  This signals that we haven't yet seen any per-vertex
800  * commands such as glNormal3f() or glTexCoord2f().
801  */
802 static void
803 _save_reset_vertex(struct gl_context *ctx)
804 {
805    struct vbo_save_context *save = &vbo_context(ctx)->save;
806    GLuint i;
807
808    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
809       save->attrsz[i] = 0;
810       save->active_sz[i] = 0;
811    }
812
813    save->vertex_size = 0;
814 }
815
816
817
818 #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
819
820
821 /* Only one size for each attribute may be active at once.  Eg. if
822  * Color3f is installed/active, then Color4f may not be, even if the
823  * vertex actually contains 4 color coordinates.  This is because the
824  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
825  * of the chooser function when switching between Color4f and Color3f.
826  */
827 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
828 do {                                                            \
829    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
830                                                                 \
831    if (save->active_sz[A] != N)                                 \
832       save_fixup_vertex(ctx, A, N);                             \
833                                                                 \
834    {                                                            \
835       C *dest = (C *)save->attrptr[A];                          \
836       if (N>0) dest[0] = V0;                                    \
837       if (N>1) dest[1] = V1;                                    \
838       if (N>2) dest[2] = V2;                                    \
839       if (N>3) dest[3] = V3;                                    \
840       save->attrtype[A] = T;                                    \
841    }                                                            \
842                                                                 \
843    if ((A) == 0) {                                              \
844       GLuint i;                                                 \
845                                                                 \
846       for (i = 0; i < save->vertex_size; i++)                   \
847          save->buffer_ptr[i] = save->vertex[i];                 \
848                                                                 \
849       save->buffer_ptr += save->vertex_size;                    \
850                                                                 \
851       if (++save->vert_count >= save->max_vert)                 \
852          _save_wrap_filled_vertex(ctx);                         \
853    }                                                            \
854 } while (0)
855
856 #define TAG(x) _save_##x
857
858 #include "vbo_attrib_tmp.h"
859
860
861
862 #define MAT( ATTR, N, face, params )                    \
863 do {                                                    \
864    if (face != GL_BACK)                                 \
865       MAT_ATTR( ATTR, N, params ); /* front */          \
866    if (face != GL_FRONT)                                \
867       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
868 } while (0)
869
870
871 /**
872  * Save a glMaterial call found between glBegin/End.
873  * glMaterial calls outside Begin/End are handled in dlist.c.
874  */
875 static void GLAPIENTRY
876 _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
877 {
878    GET_CURRENT_CONTEXT(ctx);
879
880    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
881       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
882       return;
883    }
884
885    switch (pname) {
886    case GL_EMISSION:
887       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
888       break;
889    case GL_AMBIENT:
890       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
891       break;
892    case GL_DIFFUSE:
893       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
894       break;
895    case GL_SPECULAR:
896       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
897       break;
898    case GL_SHININESS:
899       if (*params < 0 || *params > ctx->Const.MaxShininess) {
900          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
901       }
902       else {
903          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
904       }
905       break;
906    case GL_COLOR_INDEXES:
907       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
908       break;
909    case GL_AMBIENT_AND_DIFFUSE:
910       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
911       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
912       break;
913    default:
914       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
915       return;
916    }
917 }
918
919
920 /* Cope with EvalCoord/CallList called within a begin/end object:
921  *     -- Flush current buffer
922  *     -- Fallback to opcodes for the rest of the begin/end object.
923  */
924 static void
925 dlist_fallback(struct gl_context *ctx)
926 {
927    struct vbo_save_context *save = &vbo_context(ctx)->save;
928
929    if (save->vert_count || save->prim_count) {
930       if (save->prim_count > 0) {
931          /* Close off in-progress primitive. */
932          GLint i = save->prim_count - 1;
933          save->prim[i].count = save->vert_count - save->prim[i].start;
934       }
935
936       /* Need to replay this display list with loopback,
937        * unfortunately, otherwise this primitive won't be handled
938        * properly:
939        */
940       save->dangling_attr_ref = GL_TRUE;
941
942       _save_compile_vertex_list(ctx);
943    }
944
945    _save_copy_to_current(ctx);
946    _save_reset_vertex(ctx);
947    _save_reset_counters(ctx);
948    if (save->out_of_memory) {
949       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
950    }
951    else {
952       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
953    }
954    ctx->Driver.SaveNeedFlush = GL_FALSE;
955 }
956
957
958 static void GLAPIENTRY
959 _save_EvalCoord1f(GLfloat u)
960 {
961    GET_CURRENT_CONTEXT(ctx);
962    dlist_fallback(ctx);
963    CALL_EvalCoord1f(ctx->Save, (u));
964 }
965
966 static void GLAPIENTRY
967 _save_EvalCoord1fv(const GLfloat * v)
968 {
969    GET_CURRENT_CONTEXT(ctx);
970    dlist_fallback(ctx);
971    CALL_EvalCoord1fv(ctx->Save, (v));
972 }
973
974 static void GLAPIENTRY
975 _save_EvalCoord2f(GLfloat u, GLfloat v)
976 {
977    GET_CURRENT_CONTEXT(ctx);
978    dlist_fallback(ctx);
979    CALL_EvalCoord2f(ctx->Save, (u, v));
980 }
981
982 static void GLAPIENTRY
983 _save_EvalCoord2fv(const GLfloat * v)
984 {
985    GET_CURRENT_CONTEXT(ctx);
986    dlist_fallback(ctx);
987    CALL_EvalCoord2fv(ctx->Save, (v));
988 }
989
990 static void GLAPIENTRY
991 _save_EvalPoint1(GLint i)
992 {
993    GET_CURRENT_CONTEXT(ctx);
994    dlist_fallback(ctx);
995    CALL_EvalPoint1(ctx->Save, (i));
996 }
997
998 static void GLAPIENTRY
999 _save_EvalPoint2(GLint i, GLint j)
1000 {
1001    GET_CURRENT_CONTEXT(ctx);
1002    dlist_fallback(ctx);
1003    CALL_EvalPoint2(ctx->Save, (i, j));
1004 }
1005
1006 static void GLAPIENTRY
1007 _save_CallList(GLuint l)
1008 {
1009    GET_CURRENT_CONTEXT(ctx);
1010    dlist_fallback(ctx);
1011    CALL_CallList(ctx->Save, (l));
1012 }
1013
1014 static void GLAPIENTRY
1015 _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
1016 {
1017    GET_CURRENT_CONTEXT(ctx);
1018    dlist_fallback(ctx);
1019    CALL_CallLists(ctx->Save, (n, type, v));
1020 }
1021
1022
1023
1024 /**
1025  * Called when a glBegin is getting compiled into a display list.
1026  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
1027  */
1028 GLboolean
1029 vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
1030 {
1031    struct vbo_save_context *save = &vbo_context(ctx)->save;
1032    const GLuint i = save->prim_count++;
1033
1034    assert(i < save->prim_max);
1035    save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
1036    save->prim[i].begin = 1;
1037    save->prim[i].end = 0;
1038    save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
1039    save->prim[i].no_current_update =
1040       (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
1041    save->prim[i].pad = 0;
1042    save->prim[i].start = save->vert_count;
1043    save->prim[i].count = 0;
1044    save->prim[i].num_instances = 1;
1045    save->prim[i].base_instance = 0;
1046    save->prim[i].is_indirect = 0;
1047
1048    if (save->out_of_memory) {
1049       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1050    }
1051    else {
1052       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
1053    }
1054
1055    /* We need to call vbo_save_SaveFlushVertices() if there's state change */
1056    ctx->Driver.SaveNeedFlush = GL_TRUE;
1057
1058    /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
1059     * opcode into the display list.
1060     */
1061    return GL_TRUE;
1062 }
1063
1064
1065 static void GLAPIENTRY
1066 _save_End(void)
1067 {
1068    GET_CURRENT_CONTEXT(ctx);
1069    struct vbo_save_context *save = &vbo_context(ctx)->save;
1070    const GLint i = save->prim_count - 1;
1071
1072    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1073    save->prim[i].end = 1;
1074    save->prim[i].count = (save->vert_count - save->prim[i].start);
1075
1076    if (i == (GLint) save->prim_max - 1) {
1077       _save_compile_vertex_list(ctx);
1078       assert(save->copied.nr == 0);
1079    }
1080
1081    /* Swap out this vertex format while outside begin/end.  Any color,
1082     * etc. received between here and the next begin will be compiled
1083     * as opcodes.
1084     */
1085    if (save->out_of_memory) {
1086       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
1087    }
1088    else {
1089       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1090    }
1091 }
1092
1093
1094 static void GLAPIENTRY
1095 _save_Begin(GLenum mode)
1096 {
1097    GET_CURRENT_CONTEXT(ctx);
1098    (void) mode;
1099    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
1100 }
1101
1102
1103 static void GLAPIENTRY
1104 _save_PrimitiveRestartNV(void)
1105 {
1106    GLenum curPrim;
1107    GET_CURRENT_CONTEXT(ctx);
1108
1109    curPrim = ctx->Driver.CurrentSavePrimitive;
1110
1111    _save_End();
1112    _save_Begin(curPrim);
1113 }
1114
1115
1116 /* Unlike the functions above, these are to be hooked into the vtxfmt
1117  * maintained in ctx->ListState, active when the list is known or
1118  * suspected to be outside any begin/end primitive.
1119  * Note: OBE = Outside Begin/End
1120  */
1121 static void GLAPIENTRY
1122 _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
1123 {
1124    GET_CURRENT_CONTEXT(ctx);
1125    vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
1126    CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
1127    CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
1128    CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
1129    CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
1130    CALL_End(GET_DISPATCH(), ());
1131 }
1132
1133
1134 static void GLAPIENTRY
1135 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
1136 {
1137    GET_CURRENT_CONTEXT(ctx);
1138    struct vbo_save_context *save = &vbo_context(ctx)->save;
1139    GLint i;
1140
1141    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1142       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
1143       return;
1144    }
1145    if (count < 0) {
1146       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
1147       return;
1148    }
1149
1150    if (save->out_of_memory)
1151       return;
1152
1153    _ae_map_vbos(ctx);
1154
1155    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
1156                               | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1157
1158    for (i = 0; i < count; i++)
1159       CALL_ArrayElement(GET_DISPATCH(), (start + i));
1160    CALL_End(GET_DISPATCH(), ());
1161
1162    _ae_unmap_vbos(ctx);
1163 }
1164
1165
1166 /* Could do better by copying the arrays and element list intact and
1167  * then emitting an indexed prim at runtime.
1168  */
1169 static void GLAPIENTRY
1170 _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
1171                        const GLvoid * indices)
1172 {
1173    GET_CURRENT_CONTEXT(ctx);
1174    struct vbo_save_context *save = &vbo_context(ctx)->save;
1175    struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj;
1176    GLint i;
1177
1178    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1179       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
1180       return;
1181    }
1182    if (count < 0) {
1183       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1184       return;
1185    }
1186    if (type != GL_UNSIGNED_BYTE &&
1187        type != GL_UNSIGNED_SHORT &&
1188        type != GL_UNSIGNED_INT) {
1189       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
1190       return;
1191    }
1192
1193    if (save->out_of_memory)
1194       return;
1195
1196    _ae_map_vbos(ctx);
1197
1198    if (_mesa_is_bufferobj(indexbuf))
1199       indices =
1200          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
1201
1202    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
1203                               VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
1204
1205    switch (type) {
1206    case GL_UNSIGNED_BYTE:
1207       for (i = 0; i < count; i++)
1208          CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
1209       break;
1210    case GL_UNSIGNED_SHORT:
1211       for (i = 0; i < count; i++)
1212          CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
1213       break;
1214    case GL_UNSIGNED_INT:
1215       for (i = 0; i < count; i++)
1216          CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
1217       break;
1218    default:
1219       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
1220       break;
1221    }
1222
1223    CALL_End(GET_DISPATCH(), ());
1224
1225    _ae_unmap_vbos(ctx);
1226 }
1227
1228
1229 static void GLAPIENTRY
1230 _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
1231                             GLsizei count, GLenum type,
1232                             const GLvoid * indices)
1233 {
1234    GET_CURRENT_CONTEXT(ctx);
1235    struct vbo_save_context *save = &vbo_context(ctx)->save;
1236
1237    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
1238       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
1239       return;
1240    }
1241    if (count < 0) {
1242       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1243                           "glDrawRangeElements(count<0)");
1244       return;
1245    }
1246    if (type != GL_UNSIGNED_BYTE &&
1247        type != GL_UNSIGNED_SHORT &&
1248        type != GL_UNSIGNED_INT) {
1249       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
1250       return;
1251    }
1252    if (end < start) {
1253       _mesa_compile_error(ctx, GL_INVALID_VALUE,
1254                           "glDrawRangeElements(end < start)");
1255       return;
1256    }
1257
1258    if (save->out_of_memory)
1259       return;
1260
1261    _save_OBE_DrawElements(mode, count, type, indices);
1262 }
1263
1264
1265 static void GLAPIENTRY
1266 _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
1267                             const GLvoid * const *indices, GLsizei primcount)
1268 {
1269    GLsizei i;
1270
1271    for (i = 0; i < primcount; i++) {
1272       if (count[i] > 0) {
1273          CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
1274       }
1275    }
1276 }
1277
1278
1279 static void GLAPIENTRY
1280 _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
1281                                       GLenum type,
1282                                       const GLvoid * const *indices,
1283                                       GLsizei primcount,
1284                                       const GLint *basevertex)
1285 {
1286    GLsizei i;
1287
1288    for (i = 0; i < primcount; i++) {
1289       if (count[i] > 0) {
1290          CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
1291                                                       indices[i],
1292                                                       basevertex[i]));
1293       }
1294    }
1295 }
1296
1297
1298 static void
1299 _save_vtxfmt_init(struct gl_context *ctx)
1300 {
1301    struct vbo_save_context *save = &vbo_context(ctx)->save;
1302    GLvertexformat *vfmt = &save->vtxfmt;
1303
1304    vfmt->ArrayElement = _ae_ArrayElement;
1305
1306    vfmt->Color3f = _save_Color3f;
1307    vfmt->Color3fv = _save_Color3fv;
1308    vfmt->Color4f = _save_Color4f;
1309    vfmt->Color4fv = _save_Color4fv;
1310    vfmt->EdgeFlag = _save_EdgeFlag;
1311    vfmt->End = _save_End;
1312    vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
1313    vfmt->FogCoordfEXT = _save_FogCoordfEXT;
1314    vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
1315    vfmt->Indexf = _save_Indexf;
1316    vfmt->Indexfv = _save_Indexfv;
1317    vfmt->Materialfv = _save_Materialfv;
1318    vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
1319    vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
1320    vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
1321    vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
1322    vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
1323    vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
1324    vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
1325    vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
1326    vfmt->Normal3f = _save_Normal3f;
1327    vfmt->Normal3fv = _save_Normal3fv;
1328    vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
1329    vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
1330    vfmt->TexCoord1f = _save_TexCoord1f;
1331    vfmt->TexCoord1fv = _save_TexCoord1fv;
1332    vfmt->TexCoord2f = _save_TexCoord2f;
1333    vfmt->TexCoord2fv = _save_TexCoord2fv;
1334    vfmt->TexCoord3f = _save_TexCoord3f;
1335    vfmt->TexCoord3fv = _save_TexCoord3fv;
1336    vfmt->TexCoord4f = _save_TexCoord4f;
1337    vfmt->TexCoord4fv = _save_TexCoord4fv;
1338    vfmt->Vertex2f = _save_Vertex2f;
1339    vfmt->Vertex2fv = _save_Vertex2fv;
1340    vfmt->Vertex3f = _save_Vertex3f;
1341    vfmt->Vertex3fv = _save_Vertex3fv;
1342    vfmt->Vertex4f = _save_Vertex4f;
1343    vfmt->Vertex4fv = _save_Vertex4fv;
1344    vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
1345    vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
1346    vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
1347    vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
1348    vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
1349    vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
1350    vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
1351    vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
1352
1353    vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
1354    vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
1355    vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
1356    vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
1357    vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
1358    vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
1359    vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
1360    vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
1361
1362    /* integer-valued */
1363    vfmt->VertexAttribI1i = _save_VertexAttribI1i;
1364    vfmt->VertexAttribI2i = _save_VertexAttribI2i;
1365    vfmt->VertexAttribI3i = _save_VertexAttribI3i;
1366    vfmt->VertexAttribI4i = _save_VertexAttribI4i;
1367    vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
1368    vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
1369    vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
1370
1371    /* unsigned integer-valued */
1372    vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
1373    vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
1374    vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
1375    vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
1376    vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
1377    vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
1378    vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
1379
1380    vfmt->VertexP2ui = _save_VertexP2ui;
1381    vfmt->VertexP3ui = _save_VertexP3ui;
1382    vfmt->VertexP4ui = _save_VertexP4ui;
1383    vfmt->VertexP2uiv = _save_VertexP2uiv;
1384    vfmt->VertexP3uiv = _save_VertexP3uiv;
1385    vfmt->VertexP4uiv = _save_VertexP4uiv;
1386
1387    vfmt->TexCoordP1ui = _save_TexCoordP1ui;
1388    vfmt->TexCoordP2ui = _save_TexCoordP2ui;
1389    vfmt->TexCoordP3ui = _save_TexCoordP3ui;
1390    vfmt->TexCoordP4ui = _save_TexCoordP4ui;
1391    vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
1392    vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
1393    vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
1394    vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
1395
1396    vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
1397    vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
1398    vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
1399    vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
1400    vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
1401    vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
1402    vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
1403    vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
1404
1405    vfmt->NormalP3ui = _save_NormalP3ui;
1406    vfmt->NormalP3uiv = _save_NormalP3uiv;
1407
1408    vfmt->ColorP3ui = _save_ColorP3ui;
1409    vfmt->ColorP4ui = _save_ColorP4ui;
1410    vfmt->ColorP3uiv = _save_ColorP3uiv;
1411    vfmt->ColorP4uiv = _save_ColorP4uiv;
1412
1413    vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
1414    vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
1415
1416    vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
1417    vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
1418    vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
1419    vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
1420
1421    vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
1422    vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
1423    vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
1424    vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
1425
1426    vfmt->VertexAttribL1d = _save_VertexAttribL1d;
1427    vfmt->VertexAttribL2d = _save_VertexAttribL2d;
1428    vfmt->VertexAttribL3d = _save_VertexAttribL3d;
1429    vfmt->VertexAttribL4d = _save_VertexAttribL4d;
1430
1431    vfmt->VertexAttribL1dv = _save_VertexAttribL1dv;
1432    vfmt->VertexAttribL2dv = _save_VertexAttribL2dv;
1433    vfmt->VertexAttribL3dv = _save_VertexAttribL3dv;
1434    vfmt->VertexAttribL4dv = _save_VertexAttribL4dv;
1435
1436    /* This will all require us to fallback to saving the list as opcodes:
1437     */
1438    vfmt->CallList = _save_CallList;
1439    vfmt->CallLists = _save_CallLists;
1440
1441    vfmt->EvalCoord1f = _save_EvalCoord1f;
1442    vfmt->EvalCoord1fv = _save_EvalCoord1fv;
1443    vfmt->EvalCoord2f = _save_EvalCoord2f;
1444    vfmt->EvalCoord2fv = _save_EvalCoord2fv;
1445    vfmt->EvalPoint1 = _save_EvalPoint1;
1446    vfmt->EvalPoint2 = _save_EvalPoint2;
1447
1448    /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
1449     * only used when we're inside a glBegin/End pair.
1450     */
1451    vfmt->Begin = _save_Begin;
1452 }
1453
1454
1455 /**
1456  * Initialize the dispatch table with the VBO functions for display
1457  * list compilation.
1458  */
1459 void
1460 vbo_initialize_save_dispatch(const struct gl_context *ctx,
1461                              struct _glapi_table *exec)
1462 {
1463    SET_DrawArrays(exec, _save_OBE_DrawArrays);
1464    SET_DrawElements(exec, _save_OBE_DrawElements);
1465    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
1466    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
1467    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
1468    SET_Rectf(exec, _save_OBE_Rectf);
1469    /* Note: other glDraw functins aren't compiled into display lists */
1470 }
1471
1472
1473
1474 void
1475 vbo_save_SaveFlushVertices(struct gl_context *ctx)
1476 {
1477    struct vbo_save_context *save = &vbo_context(ctx)->save;
1478
1479    /* Noop when we are actually active:
1480     */
1481    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
1482       return;
1483
1484    if (save->vert_count || save->prim_count)
1485       _save_compile_vertex_list(ctx);
1486
1487    _save_copy_to_current(ctx);
1488    _save_reset_vertex(ctx);
1489    _save_reset_counters(ctx);
1490    ctx->Driver.SaveNeedFlush = GL_FALSE;
1491 }
1492
1493
1494 void
1495 vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
1496 {
1497    struct vbo_save_context *save = &vbo_context(ctx)->save;
1498
1499    (void) list;
1500    (void) mode;
1501
1502    if (!save->prim_store)
1503       save->prim_store = alloc_prim_store(ctx);
1504
1505    if (!save->vertex_store)
1506       save->vertex_store = alloc_vertex_store(ctx);
1507
1508    save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
1509
1510    _save_reset_vertex(ctx);
1511    _save_reset_counters(ctx);
1512    ctx->Driver.SaveNeedFlush = GL_FALSE;
1513 }
1514
1515
1516 void
1517 vbo_save_EndList(struct gl_context *ctx)
1518 {
1519    struct vbo_save_context *save = &vbo_context(ctx)->save;
1520
1521    /* EndList called inside a (saved) Begin/End pair?
1522     */
1523    if (_mesa_inside_dlist_begin_end(ctx)) {
1524       if (save->prim_count > 0) {
1525          GLint i = save->prim_count - 1;
1526          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
1527          save->prim[i].end = 0;
1528          save->prim[i].count = save->vert_count - save->prim[i].start;
1529       }
1530
1531       /* Make sure this vertex list gets replayed by the "loopback"
1532        * mechanism:
1533        */
1534       save->dangling_attr_ref = GL_TRUE;
1535       vbo_save_SaveFlushVertices(ctx);
1536
1537       /* Swap out this vertex format while outside begin/end.  Any color,
1538        * etc. received between here and the next begin will be compiled
1539        * as opcodes.
1540        */
1541       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
1542    }
1543
1544    vbo_save_unmap_vertex_store(ctx, save->vertex_store);
1545
1546    assert(save->vertex_size == 0);
1547 }
1548
1549
1550 void
1551 vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
1552 {
1553    struct vbo_save_context *save = &vbo_context(ctx)->save;
1554    save->replay_flags |= dlist->Flags;
1555 }
1556
1557
1558 void
1559 vbo_save_EndCallList(struct gl_context *ctx)
1560 {
1561    struct vbo_save_context *save = &vbo_context(ctx)->save;
1562
1563    if (ctx->ListState.CallDepth == 1) {
1564       /* This is correct: want to keep only the VBO_SAVE_FALLBACK
1565        * flag, if it is set:
1566        */
1567       save->replay_flags &= VBO_SAVE_FALLBACK;
1568    }
1569 }
1570
1571
1572 static void
1573 vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
1574 {
1575    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1576    (void) ctx;
1577
1578    if (--node->vertex_store->refcount == 0)
1579       free_vertex_store(ctx, node->vertex_store);
1580
1581    if (--node->prim_store->refcount == 0)
1582       free(node->prim_store);
1583
1584    free(node->current_data);
1585    node->current_data = NULL;
1586 }
1587
1588
1589 static void
1590 vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f)
1591 {
1592    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
1593    GLuint i;
1594    struct gl_buffer_object *buffer = node->vertex_store ?
1595       node->vertex_store->bufferobj : NULL;
1596    (void) ctx;
1597
1598    fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, "
1599            "buffer %p\n",
1600            node->count, node->prim_count, node->vertex_size,
1601            buffer);
1602
1603    for (i = 0; i < node->prim_count; i++) {
1604       struct _mesa_prim *prim = &node->prim[i];
1605       fprintf(f, "   prim %d: %s%s %d..%d %s %s\n",
1606              i,
1607              _mesa_lookup_prim_by_nr(prim->mode),
1608              prim->weak ? " (weak)" : "",
1609              prim->start,
1610              prim->start + prim->count,
1611              (prim->begin) ? "BEGIN" : "(wrap)",
1612              (prim->end) ? "END" : "(wrap)");
1613    }
1614 }
1615
1616
1617 /**
1618  * Called during context creation/init.
1619  */
1620 static void
1621 _save_current_init(struct gl_context *ctx)
1622 {
1623    struct vbo_save_context *save = &vbo_context(ctx)->save;
1624    GLint i;
1625
1626    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
1627       const GLuint j = i - VBO_ATTRIB_POS;
1628       assert(j < VERT_ATTRIB_MAX);
1629       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
1630       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
1631    }
1632
1633    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
1634       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
1635       assert(j < MAT_ATTRIB_MAX);
1636       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
1637       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
1638    }
1639 }
1640
1641
1642 /**
1643  * Initialize the display list compiler.  Called during context creation.
1644  */
1645 void
1646 vbo_save_api_init(struct vbo_save_context *save)
1647 {
1648    struct gl_context *ctx = save->ctx;
1649    GLuint i;
1650
1651    save->opcode_vertex_list =
1652       _mesa_dlist_alloc_opcode(ctx,
1653                                sizeof(struct vbo_save_vertex_list),
1654                                vbo_save_playback_vertex_list,
1655                                vbo_destroy_vertex_list,
1656                                vbo_print_vertex_list);
1657
1658    _save_vtxfmt_init(ctx);
1659    _save_current_init(ctx);
1660    _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
1661
1662    /* These will actually get set again when binding/drawing */
1663    for (i = 0; i < VBO_ATTRIB_MAX; i++)
1664       save->inputs[i] = &save->arrays[i];
1665 }