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