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