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 #include "main/glheader.h"
     34 #include "main/bufferobj.h"
     35 #include "main/context.h"
     36 #include "main/macros.h"
     37 #include "main/vtxfmt.h"
     38 #include "main/dlist.h"
     39 #include "main/eval.h"
     40 #include "main/state.h"
     41 #include "main/light.h"
     42 #include "main/api_arrayelt.h"
     43 #include "main/api_validate.h"
     44 #include "main/dispatch.h"
     45 #include "util/bitscan.h"
     46 
     47 #include "vbo_context.h"
     48 #include "vbo_noop.h"
     49 
     50 
     51 /** ID/name for immediate-mode VBO */
     52 #define IMM_BUFFER_NAME 0xaabbccdd
     53 
     54 
     55 static void
     56 vbo_reset_all_attr(struct vbo_exec_context *exec);
     57 
     58 
     59 /**
     60  * Close off the last primitive, execute the buffer, restart the
     61  * primitive.  This is called when we fill a vertex buffer before
     62  * hitting glEnd.
     63  */
     64 static void
     65 vbo_exec_wrap_buffers(struct vbo_exec_context *exec)
     66 {
     67    if (exec->vtx.prim_count == 0) {
     68       exec->vtx.copied.nr = 0;
     69       exec->vtx.vert_count = 0;
     70       exec->vtx.buffer_ptr = exec->vtx.buffer_map;
     71    }
     72    else {
     73       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
     74       const GLuint last_begin = last_prim->begin;
     75       GLuint last_count;
     76 
     77       if (_mesa_inside_begin_end(exec->ctx)) {
     78 	 last_prim->count = exec->vtx.vert_count - last_prim->start;
     79       }
     80 
     81       last_count = last_prim->count;
     82 
     83       /* Special handling for wrapping GL_LINE_LOOP */
     84       if (last_prim->mode == GL_LINE_LOOP &&
     85           last_count > 0 &&
     86           !last_prim->end) {
     87          /* draw this section of the incomplete line loop as a line strip */
     88          last_prim->mode = GL_LINE_STRIP;
     89          if (!last_prim->begin) {
     90             /* This is not the first section of the line loop, so don't
     91              * draw the 0th vertex.  We're saving it until we draw the
     92              * very last section of the loop.
     93              */
     94             last_prim->start++;
     95             last_prim->count--;
     96          }
     97       }
     98 
     99       /* Execute the buffer and save copied vertices.
    100        */
    101       if (exec->vtx.vert_count)
    102 	 vbo_exec_vtx_flush( exec, GL_FALSE );
    103       else {
    104 	 exec->vtx.prim_count = 0;
    105 	 exec->vtx.copied.nr = 0;
    106       }
    107 
    108       /* Emit a glBegin to start the new list.
    109        */
    110       assert(exec->vtx.prim_count == 0);
    111 
    112       if (_mesa_inside_begin_end(exec->ctx)) {
    113 	 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
    114 	 exec->vtx.prim[0].begin = 0;
    115          exec->vtx.prim[0].end = 0;
    116 	 exec->vtx.prim[0].start = 0;
    117 	 exec->vtx.prim[0].count = 0;
    118 	 exec->vtx.prim_count++;
    119 
    120 	 if (exec->vtx.copied.nr == last_count)
    121 	    exec->vtx.prim[0].begin = last_begin;
    122       }
    123    }
    124 }
    125 
    126 
    127 /**
    128  * Deal with buffer wrapping where provoked by the vertex buffer
    129  * filling up, as opposed to upgrade_vertex().
    130  */
    131 static void
    132 vbo_exec_vtx_wrap(struct vbo_exec_context *exec)
    133 {
    134    unsigned numComponents;
    135 
    136    /* Run pipeline on current vertices, copy wrapped vertices
    137     * to exec->vtx.copied.
    138     */
    139    vbo_exec_wrap_buffers( exec );
    140 
    141    if (!exec->vtx.buffer_ptr) {
    142       /* probably ran out of memory earlier when allocating the VBO */
    143       return;
    144    }
    145 
    146    /* Copy stored stored vertices to start of new list.
    147     */
    148    assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
    149 
    150    numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size;
    151    memcpy(exec->vtx.buffer_ptr,
    152           exec->vtx.copied.buffer,
    153           numComponents * sizeof(fi_type));
    154    exec->vtx.buffer_ptr += numComponents;
    155    exec->vtx.vert_count += exec->vtx.copied.nr;
    156 
    157    exec->vtx.copied.nr = 0;
    158 }
    159 
    160 
    161 /**
    162  * Copy the active vertex's values to the ctx->Current fields.
    163  */
    164 static void
    165 vbo_exec_copy_to_current(struct vbo_exec_context *exec)
    166 {
    167    struct gl_context *ctx = exec->ctx;
    168    struct vbo_context *vbo = vbo_context(ctx);
    169    GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
    170 
    171    while (enabled) {
    172       const int i = u_bit_scan64(&enabled);
    173 
    174       /* Note: the exec->vtx.current[i] pointers point into the
    175        * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
    176        */
    177       GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
    178       fi_type tmp[8]; /* space for doubles */
    179       int dmul = exec->vtx.attrtype[i] == GL_DOUBLE ? 2 : 1;
    180 
    181       assert(exec->vtx.attrsz[i]);
    182 
    183       if (exec->vtx.attrtype[i] == GL_DOUBLE) {
    184          memset(tmp, 0, sizeof(tmp));
    185          memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attrsz[i] * sizeof(GLfloat));
    186       } else {
    187          COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
    188                                      exec->vtx.attrsz[i],
    189                                      exec->vtx.attrptr[i],
    190                                      exec->vtx.attrtype[i]);
    191       }
    192 
    193       if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
    194           memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
    195          memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul);
    196 
    197          /* Given that we explicitly state size here, there is no need
    198           * for the COPY_CLEAN above, could just copy 16 bytes and be
    199           * done.  The only problem is when Mesa accesses ctx->Current
    200           * directly.
    201           */
    202          /* Size here is in components - not bytes */
    203          vbo->currval[i].Size = exec->vtx.attrsz[i] / dmul;
    204          vbo->currval[i]._ElementSize =
    205             vbo->currval[i].Size * sizeof(GLfloat) * dmul;
    206          vbo->currval[i].Type = exec->vtx.attrtype[i];
    207          vbo->currval[i].Integer =
    208             vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
    209          vbo->currval[i].Doubles =
    210             vbo_attrtype_to_double_flag(exec->vtx.attrtype[i]);
    211 
    212          /* This triggers rather too much recalculation of Mesa state
    213           * that doesn't get used (eg light positions).
    214           */
    215          if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
    216              i <= VBO_ATTRIB_MAT_BACK_INDEXES)
    217             ctx->NewState |= _NEW_LIGHT;
    218 
    219          ctx->NewState |= _NEW_CURRENT_ATTRIB;
    220       }
    221    }
    222 
    223    /* Colormaterial -- this kindof sucks.
    224     */
    225    if (ctx->Light.ColorMaterialEnabled &&
    226        exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
    227       _mesa_update_color_material(ctx,
    228 				  ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
    229    }
    230 }
    231 
    232 
    233 /**
    234  * Copy current vertex attribute values into the current vertex.
    235  */
    236 static void
    237 vbo_exec_copy_from_current(struct vbo_exec_context *exec)
    238 {
    239    struct gl_context *ctx = exec->ctx;
    240    struct vbo_context *vbo = vbo_context(ctx);
    241    GLint i;
    242 
    243    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
    244       if (exec->vtx.attrtype[i] == GL_DOUBLE) {
    245          memcpy(exec->vtx.attrptr[i], vbo->currval[i].Ptr,
    246                 exec->vtx.attrsz[i] * sizeof(GLfloat));
    247       } else {
    248          const fi_type *current = (fi_type *) vbo->currval[i].Ptr;
    249          switch (exec->vtx.attrsz[i]) {
    250          case 4: exec->vtx.attrptr[i][3] = current[3];
    251          case 3: exec->vtx.attrptr[i][2] = current[2];
    252          case 2: exec->vtx.attrptr[i][1] = current[1];
    253          case 1: exec->vtx.attrptr[i][0] = current[0];
    254             break;
    255          }
    256       }
    257    }
    258 }
    259 
    260 
    261 /**
    262  * Flush existing data, set new attrib size, replay copied vertices.
    263  * This is called when we transition from a small vertex attribute size
    264  * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
    265  * We need to go back over the previous 2-component texcoords and insert
    266  * zero and one values.
    267  */
    268 static void
    269 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
    270                              GLuint attr, GLuint newSize )
    271 {
    272    struct gl_context *ctx = exec->ctx;
    273    struct vbo_context *vbo = vbo_context(ctx);
    274    const GLint lastcount = exec->vtx.vert_count;
    275    fi_type *old_attrptr[VBO_ATTRIB_MAX];
    276    const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
    277    const GLuint oldSize = exec->vtx.attrsz[attr];
    278    GLuint i;
    279 
    280    /* Run pipeline on current vertices, copy wrapped vertices
    281     * to exec->vtx.copied.
    282     */
    283    vbo_exec_wrap_buffers( exec );
    284 
    285    if (unlikely(exec->vtx.copied.nr)) {
    286       /* We're in the middle of a primitive, keep the old vertex
    287        * format around to be able to translate the copied vertices to
    288        * the new format.
    289        */
    290       memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
    291    }
    292 
    293    if (unlikely(oldSize)) {
    294       /* Do a COPY_TO_CURRENT to ensure back-copying works for the
    295        * case when the attribute already exists in the vertex and is
    296        * having its size increased.
    297        */
    298       vbo_exec_copy_to_current( exec );
    299    }
    300 
    301    /* Heuristic: Attempt to isolate attributes received outside
    302     * begin/end so that they don't bloat the vertices.
    303     */
    304    if (!_mesa_inside_begin_end(ctx) &&
    305        !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
    306       vbo_exec_copy_to_current( exec );
    307       vbo_reset_all_attr(exec);
    308    }
    309 
    310    /* Fix up sizes:
    311     */
    312    exec->vtx.attrsz[attr] = newSize;
    313    exec->vtx.vertex_size += newSize - oldSize;
    314    exec->vtx.max_vert = vbo_compute_max_verts(exec);
    315    exec->vtx.vert_count = 0;
    316    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
    317    exec->vtx.enabled |= BITFIELD64_BIT(attr);
    318 
    319    if (unlikely(oldSize)) {
    320       /* Size changed, recalculate all the attrptr[] values
    321        */
    322       fi_type *tmp = exec->vtx.vertex;
    323 
    324       for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
    325 	 if (exec->vtx.attrsz[i]) {
    326 	    exec->vtx.attrptr[i] = tmp;
    327 	    tmp += exec->vtx.attrsz[i];
    328 	 }
    329 	 else
    330 	    exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
    331       }
    332 
    333       /* Copy from current to repopulate the vertex with correct
    334        * values.
    335        */
    336       vbo_exec_copy_from_current( exec );
    337    }
    338    else {
    339       /* Just have to append the new attribute at the end */
    340       exec->vtx.attrptr[attr] = exec->vtx.vertex +
    341         exec->vtx.vertex_size - newSize;
    342    }
    343 
    344    /* Replay stored vertices to translate them
    345     * to new format here.
    346     *
    347     * -- No need to replay - just copy piecewise
    348     */
    349    if (unlikely(exec->vtx.copied.nr)) {
    350       fi_type *data = exec->vtx.copied.buffer;
    351       fi_type *dest = exec->vtx.buffer_ptr;
    352 
    353       assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
    354 
    355       for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
    356          GLbitfield64 enabled = exec->vtx.enabled;
    357          while (enabled) {
    358             const int j = u_bit_scan64(&enabled);
    359 	    GLuint sz = exec->vtx.attrsz[j];
    360             GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
    361             GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
    362 
    363             assert(sz);
    364 
    365             if (j == attr) {
    366                if (oldSize) {
    367                   fi_type tmp[4];
    368                   COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
    369                                               data + old_offset,
    370                                               exec->vtx.attrtype[j]);
    371                   COPY_SZ_4V(dest + new_offset, newSize, tmp);
    372                } else {
    373                   fi_type *current = (fi_type *)vbo->currval[j].Ptr;
    374                   COPY_SZ_4V(dest + new_offset, sz, current);
    375                }
    376             }
    377             else {
    378                COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
    379             }
    380 	 }
    381 
    382 	 data += old_vtx_size;
    383 	 dest += exec->vtx.vertex_size;
    384       }
    385 
    386       exec->vtx.buffer_ptr = dest;
    387       exec->vtx.vert_count += exec->vtx.copied.nr;
    388       exec->vtx.copied.nr = 0;
    389    }
    390 }
    391 
    392 
    393 /**
    394  * This is when a vertex attribute transitions to a different size.
    395  * For example, we saw a bunch of glTexCoord2f() calls and now we got a
    396  * glTexCoord4f() call.  We promote the array from size=2 to size=4.
    397  * \param newSize  size of new vertex (number of 32-bit words).
    398  */
    399 static void
    400 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr,
    401                       GLuint newSize, GLenum newType)
    402 {
    403    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
    404 
    405    if (newSize > exec->vtx.attrsz[attr] ||
    406        newType != exec->vtx.attrtype[attr]) {
    407       /* New size is larger.  Need to flush existing vertices and get
    408        * an enlarged vertex format.
    409        */
    410       vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
    411    }
    412    else if (newSize < exec->vtx.active_sz[attr]) {
    413       GLuint i;
    414       const fi_type *id =
    415             vbo_get_default_vals_as_union(exec->vtx.attrtype[attr]);
    416 
    417       /* New size is smaller - just need to fill in some
    418        * zeros.  Don't need to flush or wrap.
    419        */
    420       for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
    421          exec->vtx.attrptr[attr][i-1] = id[i-1];
    422    }
    423 
    424    exec->vtx.active_sz[attr] = newSize;
    425    exec->vtx.attrtype[attr] = newType;
    426 
    427    /* Does setting NeedFlush belong here?  Necessitates resetting
    428     * vtxfmt on each flush (otherwise flags won't get reset
    429     * afterwards).
    430     */
    431    if (attr == 0)
    432       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
    433 }
    434 
    435 
    436 /**
    437  * Called upon first glVertex, glColor, glTexCoord, etc.
    438  */
    439 static void
    440 vbo_exec_begin_vertices(struct gl_context *ctx)
    441 {
    442    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
    443 
    444    vbo_exec_vtx_map( exec );
    445 
    446    assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
    447    assert(exec->begin_vertices_flags);
    448 
    449    ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
    450 }
    451 
    452 
    453 /**
    454  * This macro is used to implement all the glVertex, glColor, glTexCoord,
    455  * glVertexAttrib, etc functions.
    456  * \param A  attribute index
    457  * \param N  attribute size (1..4)
    458  * \param T  type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
    459  * \param C  cast type (fi_type or double)
    460  * \param V0, V1, v2, V3  attribute value
    461  */
    462 #define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 )                        \
    463 do {									\
    464    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;		\
    465    int sz = (sizeof(C) / sizeof(GLfloat));                              \
    466                                                                         \
    467    assert(sz == 1 || sz == 2);                                          \
    468                                                                         \
    469    /* check if attribute size or type is changing */                    \
    470    if (unlikely(exec->vtx.active_sz[A] != N * sz) ||                    \
    471        unlikely(exec->vtx.attrtype[A] != T)) {                          \
    472       vbo_exec_fixup_vertex(ctx, A, N * sz, T);                         \
    473    }									\
    474                                                                         \
    475    /* store vertex attribute in vertex buffer */                        \
    476    {									\
    477       C *dest = (C *)exec->vtx.attrptr[A];                              \
    478       if (N>0) dest[0] = V0;						\
    479       if (N>1) dest[1] = V1;						\
    480       if (N>2) dest[2] = V2;						\
    481       if (N>3) dest[3] = V3;						\
    482       assert(exec->vtx.attrtype[A] == T);                               \
    483    }									\
    484 									\
    485    if ((A) == 0) {							\
    486       /* This is a glVertex call */					\
    487       GLuint i;								\
    488 									\
    489       if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
    490          vbo_exec_begin_vertices(ctx);                                  \
    491       }                                                                 \
    492                                                                         \
    493       if (unlikely(!exec->vtx.buffer_ptr)) {                            \
    494          vbo_exec_vtx_map(exec);                                        \
    495       }                                                                 \
    496       assert(exec->vtx.buffer_ptr);                                     \
    497                                                                         \
    498       /* copy 32-bit words */                                           \
    499       for (i = 0; i < exec->vtx.vertex_size; i++)			\
    500 	 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i];			\
    501 									\
    502       exec->vtx.buffer_ptr += exec->vtx.vertex_size;			\
    503 									\
    504       /* Set FLUSH_STORED_VERTICES to indicate that there's now */	\
    505       /* something to draw (not just updating a color or texcoord).*/	\
    506       ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;			\
    507 									\
    508       if (++exec->vtx.vert_count >= exec->vtx.max_vert)			\
    509 	 vbo_exec_vtx_wrap( exec );					\
    510    } else {                                                             \
    511       /* we now have accumulated per-vertex attributes */               \
    512       ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;                    \
    513    }                                                                    \
    514 } while (0)
    515 
    516 
    517 #undef ERROR
    518 #define ERROR(err) _mesa_error( ctx, err, __func__ )
    519 #define TAG(x) vbo_##x
    520 
    521 #include "vbo_attrib_tmp.h"
    522 
    523 
    524 
    525 /**
    526  * Execute a glMaterial call.  Note that if GL_COLOR_MATERIAL is enabled,
    527  * this may be a (partial) no-op.
    528  */
    529 static void GLAPIENTRY
    530 vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
    531 {
    532    GLbitfield updateMats;
    533    GET_CURRENT_CONTEXT(ctx);
    534 
    535    /* This function should be a no-op when it tries to update material
    536     * attributes which are currently tracking glColor via glColorMaterial.
    537     * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
    538     * indicating which material attributes can actually be updated below.
    539     */
    540    if (ctx->Light.ColorMaterialEnabled) {
    541       updateMats = ~ctx->Light._ColorMaterialBitmask;
    542    }
    543    else {
    544       /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
    545       updateMats = ALL_MATERIAL_BITS;
    546    }
    547 
    548    if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
    549       updateMats &= FRONT_MATERIAL_BITS;
    550    }
    551    else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
    552       updateMats &= BACK_MATERIAL_BITS;
    553    }
    554    else if (face != GL_FRONT_AND_BACK) {
    555       _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
    556       return;
    557    }
    558 
    559    switch (pname) {
    560    case GL_EMISSION:
    561       if (updateMats & MAT_BIT_FRONT_EMISSION)
    562          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
    563       if (updateMats & MAT_BIT_BACK_EMISSION)
    564          MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
    565       break;
    566    case GL_AMBIENT:
    567       if (updateMats & MAT_BIT_FRONT_AMBIENT)
    568          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
    569       if (updateMats & MAT_BIT_BACK_AMBIENT)
    570          MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
    571       break;
    572    case GL_DIFFUSE:
    573       if (updateMats & MAT_BIT_FRONT_DIFFUSE)
    574          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
    575       if (updateMats & MAT_BIT_BACK_DIFFUSE)
    576          MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
    577       break;
    578    case GL_SPECULAR:
    579       if (updateMats & MAT_BIT_FRONT_SPECULAR)
    580          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
    581       if (updateMats & MAT_BIT_BACK_SPECULAR)
    582          MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
    583       break;
    584    case GL_SHININESS:
    585       if (*params < 0 || *params > ctx->Const.MaxShininess) {
    586          _mesa_error(ctx, GL_INVALID_VALUE,
    587                      "glMaterial(invalid shininess: %f out range [0, %f])",
    588 		     *params, ctx->Const.MaxShininess);
    589          return;
    590       }
    591       if (updateMats & MAT_BIT_FRONT_SHININESS)
    592          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
    593       if (updateMats & MAT_BIT_BACK_SHININESS)
    594          MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
    595       break;
    596    case GL_COLOR_INDEXES:
    597       if (ctx->API != API_OPENGL_COMPAT) {
    598          _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
    599          return;
    600       }
    601       if (updateMats & MAT_BIT_FRONT_INDEXES)
    602          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
    603       if (updateMats & MAT_BIT_BACK_INDEXES)
    604          MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
    605       break;
    606    case GL_AMBIENT_AND_DIFFUSE:
    607       if (updateMats & MAT_BIT_FRONT_AMBIENT)
    608          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
    609       if (updateMats & MAT_BIT_FRONT_DIFFUSE)
    610          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
    611       if (updateMats & MAT_BIT_BACK_AMBIENT)
    612          MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
    613       if (updateMats & MAT_BIT_BACK_DIFFUSE)
    614          MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
    615       break;
    616    default:
    617       _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
    618       return;
    619    }
    620 }
    621 
    622 
    623 /**
    624  * Flush (draw) vertices.
    625  * \param  unmap - leave VBO unmapped after flushing?
    626  */
    627 static void
    628 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
    629 {
    630    if (exec->vtx.vert_count || unmap) {
    631       vbo_exec_vtx_flush( exec, unmap );
    632    }
    633 
    634    if (exec->vtx.vertex_size) {
    635       vbo_exec_copy_to_current( exec );
    636       vbo_reset_all_attr(exec);
    637    }
    638 }
    639 
    640 
    641 static void GLAPIENTRY
    642 vbo_exec_EvalCoord1f(GLfloat u)
    643 {
    644    GET_CURRENT_CONTEXT( ctx );
    645    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
    646 
    647    {
    648       GLint i;
    649       if (exec->eval.recalculate_maps)
    650 	 vbo_exec_eval_update( exec );
    651 
    652       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
    653 	 if (exec->eval.map1[i].map)
    654 	    if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
    655 	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz, GL_FLOAT );
    656       }
    657    }
    658 
    659 
    660    memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
    661            exec->vtx.vertex_size * sizeof(GLfloat));
    662 
    663    vbo_exec_do_EvalCoord1f( exec, u );
    664 
    665    memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
    666            exec->vtx.vertex_size * sizeof(GLfloat));
    667 }
    668 
    669 
    670 static void GLAPIENTRY
    671 vbo_exec_EvalCoord2f(GLfloat u, GLfloat v)
    672 {
    673    GET_CURRENT_CONTEXT( ctx );
    674    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
    675 
    676    {
    677       GLint i;
    678       if (exec->eval.recalculate_maps)
    679 	 vbo_exec_eval_update( exec );
    680 
    681       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
    682 	 if (exec->eval.map2[i].map)
    683 	    if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
    684 	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz, GL_FLOAT );
    685       }
    686 
    687       if (ctx->Eval.AutoNormal)
    688 	 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
    689 	    vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT );
    690    }
    691 
    692    memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
    693            exec->vtx.vertex_size * sizeof(GLfloat));
    694 
    695    vbo_exec_do_EvalCoord2f( exec, u, v );
    696 
    697    memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
    698            exec->vtx.vertex_size * sizeof(GLfloat));
    699 }
    700 
    701 
    702 static void GLAPIENTRY
    703 vbo_exec_EvalCoord1fv(const GLfloat *u)
    704 {
    705    vbo_exec_EvalCoord1f( u[0] );
    706 }
    707 
    708 
    709 static void GLAPIENTRY
    710 vbo_exec_EvalCoord2fv(const GLfloat *u)
    711 {
    712    vbo_exec_EvalCoord2f( u[0], u[1] );
    713 }
    714 
    715 
    716 static void GLAPIENTRY
    717 vbo_exec_EvalPoint1(GLint i)
    718 {
    719    GET_CURRENT_CONTEXT( ctx );
    720    GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
    721 		 (GLfloat) ctx->Eval.MapGrid1un);
    722    GLfloat u = i * du + ctx->Eval.MapGrid1u1;
    723 
    724    vbo_exec_EvalCoord1f( u );
    725 }
    726 
    727 
    728 static void GLAPIENTRY
    729 vbo_exec_EvalPoint2(GLint i, GLint j)
    730 {
    731    GET_CURRENT_CONTEXT( ctx );
    732    GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
    733 		 (GLfloat) ctx->Eval.MapGrid2un);
    734    GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
    735 		 (GLfloat) ctx->Eval.MapGrid2vn);
    736    GLfloat u = i * du + ctx->Eval.MapGrid2u1;
    737    GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
    738 
    739    vbo_exec_EvalCoord2f( u, v );
    740 }
    741 
    742 
    743 /**
    744  * Called via glBegin.
    745  */
    746 static void GLAPIENTRY
    747 vbo_exec_Begin(GLenum mode)
    748 {
    749    GET_CURRENT_CONTEXT( ctx );
    750    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
    751    int i;
    752 
    753    if (_mesa_inside_begin_end(ctx)) {
    754       _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
    755       return;
    756    }
    757 
    758    if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
    759       return;
    760    }
    761 
    762    vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
    763 
    764    if (ctx->NewState) {
    765       _mesa_update_state( ctx );
    766 
    767       CALL_Begin(ctx->Exec, (mode));
    768       return;
    769    }
    770 
    771    if (!_mesa_valid_to_render(ctx, "glBegin")) {
    772       return;
    773    }
    774 
    775    /* Heuristic: attempt to isolate attributes occurring outside
    776     * begin/end pairs.
    777     */
    778    if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
    779       vbo_exec_FlushVertices_internal(exec, GL_FALSE);
    780 
    781    i = exec->vtx.prim_count++;
    782    exec->vtx.prim[i].mode = mode;
    783    exec->vtx.prim[i].begin = 1;
    784    exec->vtx.prim[i].end = 0;
    785    exec->vtx.prim[i].indexed = 0;
    786    exec->vtx.prim[i].weak = 0;
    787    exec->vtx.prim[i].pad = 0;
    788    exec->vtx.prim[i].start = exec->vtx.vert_count;
    789    exec->vtx.prim[i].count = 0;
    790    exec->vtx.prim[i].num_instances = 1;
    791    exec->vtx.prim[i].base_instance = 0;
    792    exec->vtx.prim[i].is_indirect = 0;
    793 
    794    ctx->Driver.CurrentExecPrimitive = mode;
    795 
    796    ctx->Exec = ctx->BeginEnd;
    797    /* We may have been called from a display list, in which case we should
    798     * leave dlist.c's dispatch table in place.
    799     */
    800    if (ctx->CurrentDispatch == ctx->OutsideBeginEnd) {
    801       ctx->CurrentDispatch = ctx->BeginEnd;
    802       _glapi_set_dispatch(ctx->CurrentDispatch);
    803    } else {
    804       assert(ctx->CurrentDispatch == ctx->Save);
    805    }
    806 }
    807 
    808 
    809 /**
    810  * Try to merge / concatenate the two most recent VBO primitives.
    811  */
    812 static void
    813 try_vbo_merge(struct vbo_exec_context *exec)
    814 {
    815    struct _mesa_prim *cur =  &exec->vtx.prim[exec->vtx.prim_count - 1];
    816 
    817    assert(exec->vtx.prim_count >= 1);
    818 
    819    vbo_try_prim_conversion(cur);
    820 
    821    if (exec->vtx.prim_count >= 2) {
    822       struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
    823       assert(prev == cur - 1);
    824 
    825       if (vbo_can_merge_prims(prev, cur)) {
    826          assert(cur->begin);
    827          assert(cur->end);
    828          assert(prev->begin);
    829          assert(prev->end);
    830          vbo_merge_prims(prev, cur);
    831          exec->vtx.prim_count--;  /* drop the last primitive */
    832       }
    833    }
    834 }
    835 
    836 
    837 /**
    838  * Called via glEnd.
    839  */
    840 static void GLAPIENTRY
    841 vbo_exec_End(void)
    842 {
    843    GET_CURRENT_CONTEXT( ctx );
    844    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
    845 
    846    if (!_mesa_inside_begin_end(ctx)) {
    847       _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
    848       return;
    849    }
    850 
    851    ctx->Exec = ctx->OutsideBeginEnd;
    852    if (ctx->CurrentDispatch == ctx->BeginEnd) {
    853       ctx->CurrentDispatch = ctx->OutsideBeginEnd;
    854       _glapi_set_dispatch(ctx->CurrentDispatch);
    855    }
    856 
    857    if (exec->vtx.prim_count > 0) {
    858       /* close off current primitive */
    859       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
    860 
    861       last_prim->end = 1;
    862       last_prim->count = exec->vtx.vert_count - last_prim->start;
    863 
    864       /* Special handling for GL_LINE_LOOP */
    865       if (last_prim->mode == GL_LINE_LOOP && last_prim->begin == 0) {
    866          /* We're finishing drawing a line loop.  Append 0th vertex onto
    867           * end of vertex buffer so we can draw it as a line strip.
    868           */
    869          const fi_type *src = exec->vtx.buffer_map +
    870             last_prim->start * exec->vtx.vertex_size;
    871          fi_type *dst = exec->vtx.buffer_map +
    872             exec->vtx.vert_count * exec->vtx.vertex_size;
    873 
    874          /* copy 0th vertex to end of buffer */
    875          memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
    876 
    877          last_prim->start++;  /* skip vertex0 */
    878          /* note that last_prim->count stays unchanged */
    879          last_prim->mode = GL_LINE_STRIP;
    880 
    881          /* Increment the vertex count so the next primitive doesn't
    882           * overwrite the last vertex which we just added.
    883           */
    884          exec->vtx.vert_count++;
    885          exec->vtx.buffer_ptr += exec->vtx.vertex_size;
    886       }
    887 
    888       try_vbo_merge(exec);
    889    }
    890 
    891    ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
    892 
    893    if (exec->vtx.prim_count == VBO_MAX_PRIM)
    894       vbo_exec_vtx_flush( exec, GL_FALSE );
    895 
    896    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
    897       _mesa_flush(ctx);
    898    }
    899 }
    900 
    901 
    902 /**
    903  * Called via glPrimitiveRestartNV()
    904  */
    905 static void GLAPIENTRY
    906 vbo_exec_PrimitiveRestartNV(void)
    907 {
    908    GLenum curPrim;
    909    GET_CURRENT_CONTEXT(ctx);
    910 
    911    curPrim = ctx->Driver.CurrentExecPrimitive;
    912 
    913    if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
    914       _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
    915    }
    916    else {
    917       vbo_exec_End();
    918       vbo_exec_Begin(curPrim);
    919    }
    920 }
    921 
    922 
    923 static void
    924 vbo_exec_vtxfmt_init(struct vbo_exec_context *exec)
    925 {
    926    struct gl_context *ctx = exec->ctx;
    927    GLvertexformat *vfmt = &exec->vtxfmt;
    928 
    929    vfmt->ArrayElement = _ae_ArrayElement;
    930 
    931    vfmt->Begin = vbo_exec_Begin;
    932    vfmt->End = vbo_exec_End;
    933    vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
    934 
    935    vfmt->CallList = _mesa_CallList;
    936    vfmt->CallLists = _mesa_CallLists;
    937 
    938    vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
    939    vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
    940    vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
    941    vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
    942    vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
    943    vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
    944 
    945    /* from attrib_tmp.h:
    946     */
    947    vfmt->Color3f = vbo_Color3f;
    948    vfmt->Color3fv = vbo_Color3fv;
    949    vfmt->Color4f = vbo_Color4f;
    950    vfmt->Color4fv = vbo_Color4fv;
    951    vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
    952    vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
    953    vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
    954    vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
    955    vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
    956    vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
    957    vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
    958    vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
    959    vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
    960    vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
    961    vfmt->Normal3f = vbo_Normal3f;
    962    vfmt->Normal3fv = vbo_Normal3fv;
    963    vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
    964    vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
    965    vfmt->TexCoord1f = vbo_TexCoord1f;
    966    vfmt->TexCoord1fv = vbo_TexCoord1fv;
    967    vfmt->TexCoord2f = vbo_TexCoord2f;
    968    vfmt->TexCoord2fv = vbo_TexCoord2fv;
    969    vfmt->TexCoord3f = vbo_TexCoord3f;
    970    vfmt->TexCoord3fv = vbo_TexCoord3fv;
    971    vfmt->TexCoord4f = vbo_TexCoord4f;
    972    vfmt->TexCoord4fv = vbo_TexCoord4fv;
    973    vfmt->Vertex2f = vbo_Vertex2f;
    974    vfmt->Vertex2fv = vbo_Vertex2fv;
    975    vfmt->Vertex3f = vbo_Vertex3f;
    976    vfmt->Vertex3fv = vbo_Vertex3fv;
    977    vfmt->Vertex4f = vbo_Vertex4f;
    978    vfmt->Vertex4fv = vbo_Vertex4fv;
    979 
    980    if (ctx->API == API_OPENGLES2) {
    981       vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
    982       vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
    983       vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
    984       vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
    985       vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
    986       vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
    987       vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
    988       vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
    989    } else {
    990       vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
    991       vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
    992       vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
    993       vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
    994       vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
    995       vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
    996       vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
    997       vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
    998    }
    999 
   1000    /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
   1001     * they can have a single entrypoint for updating any of the legacy
   1002     * attribs.
   1003     */
   1004    vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
   1005    vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
   1006    vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
   1007    vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
   1008    vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
   1009    vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
   1010    vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
   1011    vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
   1012 
   1013    /* integer-valued */
   1014    vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
   1015    vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
   1016    vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
   1017    vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
   1018    vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
   1019    vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
   1020    vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
   1021 
   1022    /* unsigned integer-valued */
   1023    vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
   1024    vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
   1025    vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
   1026    vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
   1027    vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
   1028    vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
   1029    vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
   1030 
   1031    vfmt->Materialfv = vbo_Materialfv;
   1032 
   1033    vfmt->EdgeFlag = vbo_EdgeFlag;
   1034    vfmt->Indexf = vbo_Indexf;
   1035    vfmt->Indexfv = vbo_Indexfv;
   1036 
   1037    /* ARB_vertex_type_2_10_10_10_rev */
   1038    vfmt->VertexP2ui = vbo_VertexP2ui;
   1039    vfmt->VertexP2uiv = vbo_VertexP2uiv;
   1040    vfmt->VertexP3ui = vbo_VertexP3ui;
   1041    vfmt->VertexP3uiv = vbo_VertexP3uiv;
   1042    vfmt->VertexP4ui = vbo_VertexP4ui;
   1043    vfmt->VertexP4uiv = vbo_VertexP4uiv;
   1044 
   1045    vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
   1046    vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
   1047    vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
   1048    vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
   1049    vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
   1050    vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
   1051    vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
   1052    vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
   1053 
   1054    vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
   1055    vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
   1056    vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
   1057    vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
   1058    vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
   1059    vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
   1060    vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
   1061    vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
   1062 
   1063    vfmt->NormalP3ui = vbo_NormalP3ui;
   1064    vfmt->NormalP3uiv = vbo_NormalP3uiv;
   1065 
   1066    vfmt->ColorP3ui = vbo_ColorP3ui;
   1067    vfmt->ColorP3uiv = vbo_ColorP3uiv;
   1068    vfmt->ColorP4ui = vbo_ColorP4ui;
   1069    vfmt->ColorP4uiv = vbo_ColorP4uiv;
   1070 
   1071    vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
   1072    vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
   1073 
   1074    vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
   1075    vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
   1076    vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
   1077    vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
   1078    vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
   1079    vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
   1080    vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
   1081    vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
   1082 
   1083    vfmt->VertexAttribL1d = vbo_VertexAttribL1d;
   1084    vfmt->VertexAttribL2d = vbo_VertexAttribL2d;
   1085    vfmt->VertexAttribL3d = vbo_VertexAttribL3d;
   1086    vfmt->VertexAttribL4d = vbo_VertexAttribL4d;
   1087 
   1088    vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv;
   1089    vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv;
   1090    vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv;
   1091    vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv;
   1092 }
   1093 
   1094 
   1095 /**
   1096  * Tell the VBO module to use a real OpenGL vertex buffer object to
   1097  * store accumulated immediate-mode vertex data.
   1098  * This replaces the malloced buffer which was created in
   1099  * vb_exec_vtx_init() below.
   1100  */
   1101 void
   1102 vbo_use_buffer_objects(struct gl_context *ctx)
   1103 {
   1104    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
   1105    /* Any buffer name but 0 can be used here since this bufferobj won't
   1106     * go into the bufferobj hashtable.
   1107     */
   1108    GLuint bufName = IMM_BUFFER_NAME;
   1109    GLenum target = GL_ARRAY_BUFFER_ARB;
   1110    GLenum usage = GL_STREAM_DRAW_ARB;
   1111    GLsizei size = VBO_VERT_BUFFER_SIZE;
   1112 
   1113    /* Make sure this func is only used once */
   1114    assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
   1115 
   1116    _mesa_align_free(exec->vtx.buffer_map);
   1117    exec->vtx.buffer_map = NULL;
   1118    exec->vtx.buffer_ptr = NULL;
   1119 
   1120    /* Allocate a real buffer object now */
   1121    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
   1122    exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName);
   1123    if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage,
   1124                                GL_MAP_WRITE_BIT |
   1125                                GL_DYNAMIC_STORAGE_BIT |
   1126                                GL_CLIENT_STORAGE_BIT,
   1127                                exec->vtx.bufferobj)) {
   1128       _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
   1129    }
   1130 }
   1131 
   1132 
   1133 /**
   1134  * If this function is called, all VBO buffers will be unmapped when
   1135  * we flush.
   1136  * Otherwise, if a simple command like glColor3f() is called and we flush,
   1137  * the current VBO may be left mapped.
   1138  */
   1139 void
   1140 vbo_always_unmap_buffers(struct gl_context *ctx)
   1141 {
   1142    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
   1143    exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
   1144 }
   1145 
   1146 
   1147 void
   1148 vbo_exec_vtx_init(struct vbo_exec_context *exec)
   1149 {
   1150    struct gl_context *ctx = exec->ctx;
   1151    struct vbo_context *vbo = vbo_context(ctx);
   1152    GLuint i;
   1153 
   1154    /* Allocate a buffer object.  Will just reuse this object
   1155     * continuously, unless vbo_use_buffer_objects() is called to enable
   1156     * use of real VBOs.
   1157     */
   1158    _mesa_reference_buffer_object(ctx,
   1159                                  &exec->vtx.bufferobj,
   1160                                  ctx->Shared->NullBufferObj);
   1161 
   1162    assert(!exec->vtx.buffer_map);
   1163    exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
   1164    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
   1165 
   1166    vbo_exec_vtxfmt_init( exec );
   1167    _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
   1168 
   1169    exec->vtx.enabled = 0;
   1170    for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
   1171       assert(i < ARRAY_SIZE(exec->vtx.attrsz));
   1172       exec->vtx.attrsz[i] = 0;
   1173       assert(i < ARRAY_SIZE(exec->vtx.attrtype));
   1174       exec->vtx.attrtype[i] = GL_FLOAT;
   1175       assert(i < ARRAY_SIZE(exec->vtx.active_sz));
   1176       exec->vtx.active_sz[i] = 0;
   1177    }
   1178    for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
   1179       assert(i < ARRAY_SIZE(exec->vtx.inputs));
   1180       assert(i < ARRAY_SIZE(exec->vtx.arrays));
   1181       exec->vtx.inputs[i] = &exec->vtx.arrays[i];
   1182    }
   1183 
   1184    {
   1185       struct gl_vertex_array *arrays = exec->vtx.arrays;
   1186       unsigned i;
   1187 
   1188       memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS],
   1189              VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
   1190       for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
   1191          struct gl_vertex_array *array;
   1192          array = &arrays[VERT_ATTRIB_FF(i)];
   1193          array->BufferObj = NULL;
   1194          _mesa_reference_buffer_object(ctx, &array->BufferObj,
   1195                                  vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
   1196       }
   1197 
   1198       memcpy(arrays + VERT_ATTRIB_GENERIC(0),
   1199              &vbo->currval[VBO_ATTRIB_GENERIC0],
   1200              VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
   1201 
   1202       for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
   1203          struct gl_vertex_array *array;
   1204          array = &arrays[VERT_ATTRIB_GENERIC(i)];
   1205          array->BufferObj = NULL;
   1206          _mesa_reference_buffer_object(ctx, &array->BufferObj,
   1207                            vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj);
   1208       }
   1209    }
   1210 
   1211    exec->vtx.vertex_size = 0;
   1212 
   1213    exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
   1214 }
   1215 
   1216 
   1217 void
   1218 vbo_exec_vtx_destroy(struct vbo_exec_context *exec)
   1219 {
   1220    /* using a real VBO for vertex data */
   1221    struct gl_context *ctx = exec->ctx;
   1222    unsigned i;
   1223 
   1224    /* True VBOs should already be unmapped
   1225     */
   1226    if (exec->vtx.buffer_map) {
   1227       assert(exec->vtx.bufferobj->Name == 0 ||
   1228              exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
   1229       if (exec->vtx.bufferobj->Name == 0) {
   1230          _mesa_align_free(exec->vtx.buffer_map);
   1231          exec->vtx.buffer_map = NULL;
   1232          exec->vtx.buffer_ptr = NULL;
   1233       }
   1234    }
   1235 
   1236    /* Drop any outstanding reference to the vertex buffer
   1237     */
   1238    for (i = 0; i < ARRAY_SIZE(exec->vtx.arrays); i++) {
   1239       _mesa_reference_buffer_object(ctx,
   1240                                     &exec->vtx.arrays[i].BufferObj,
   1241                                     NULL);
   1242    }
   1243 
   1244    /* Free the vertex buffer.  Unmap first if needed.
   1245     */
   1246    if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
   1247       ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
   1248    }
   1249    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
   1250 }
   1251 
   1252 
   1253 /**
   1254  * If inside glBegin()/glEnd(), it should assert(0).  Otherwise, if
   1255  * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
   1256  * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
   1257  * __struct gl_contextRec::Current and gl_light_attrib::Material
   1258  *
   1259  * Note that the default T&L engine never clears the
   1260  * FLUSH_UPDATE_CURRENT bit, even after performing the update.
   1261  *
   1262  * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
   1263  */
   1264 void
   1265 vbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags)
   1266 {
   1267    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
   1268 
   1269 #ifdef DEBUG
   1270    /* debug check: make sure we don't get called recursively */
   1271    exec->flush_call_depth++;
   1272    assert(exec->flush_call_depth == 1);
   1273 #endif
   1274 
   1275    if (_mesa_inside_begin_end(ctx)) {
   1276       /* We've had glBegin but not glEnd! */
   1277 #ifdef DEBUG
   1278       exec->flush_call_depth--;
   1279       assert(exec->flush_call_depth == 0);
   1280 #endif
   1281       return;
   1282    }
   1283 
   1284    /* Flush (draw), and make sure VBO is left unmapped when done */
   1285    vbo_exec_FlushVertices_internal(exec, GL_TRUE);
   1286 
   1287    /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
   1288     */
   1289    ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
   1290 
   1291 #ifdef DEBUG
   1292    exec->flush_call_depth--;
   1293    assert(exec->flush_call_depth == 0);
   1294 #endif
   1295 }
   1296 
   1297 
   1298 /**
   1299  * Reset the vertex attribute by setting its size to zero.
   1300  */
   1301 static void
   1302 vbo_reset_attr(struct vbo_exec_context *exec, GLuint attr)
   1303 {
   1304    exec->vtx.attrsz[attr] = 0;
   1305    exec->vtx.attrtype[attr] = GL_FLOAT;
   1306    exec->vtx.active_sz[attr] = 0;
   1307 }
   1308 
   1309 
   1310 static void
   1311 vbo_reset_all_attr(struct vbo_exec_context *exec)
   1312 {
   1313    while (exec->vtx.enabled) {
   1314       const int i = u_bit_scan64(&exec->vtx.enabled);
   1315       vbo_reset_attr(exec, i);
   1316    }
   1317 
   1318    exec->vtx.vertex_size = 0;
   1319 }
   1320 
   1321 
   1322 void GLAPIENTRY
   1323 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
   1324 {
   1325    vbo_Color4f(r, g, b, a);
   1326 }
   1327 
   1328 
   1329 void GLAPIENTRY
   1330 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
   1331 {
   1332    vbo_Normal3f(x, y, z);
   1333 }
   1334 
   1335 
   1336 void GLAPIENTRY
   1337 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
   1338 {
   1339    vbo_MultiTexCoord4f(target, s, t, r, q);
   1340 }
   1341 
   1342 
   1343 void GLAPIENTRY
   1344 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
   1345 {
   1346    vbo_Materialfv(face, pname, params);
   1347 }
   1348 
   1349 
   1350 void GLAPIENTRY
   1351 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
   1352 {
   1353    GLfloat p[4];
   1354    p[0] = param;
   1355    p[1] = p[2] = p[3] = 0.0F;
   1356    vbo_Materialfv(face, pname, p);
   1357 }
   1358 
   1359 
   1360 /**
   1361  * A special version of glVertexAttrib4f that does not treat index 0 as
   1362  * VBO_ATTRIB_POS.
   1363  */
   1364 static void
   1365 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
   1366 {
   1367    GET_CURRENT_CONTEXT(ctx);
   1368    if (index < MAX_VERTEX_GENERIC_ATTRIBS)
   1369       ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
   1370    else
   1371       ERROR(GL_INVALID_VALUE);
   1372 }
   1373 
   1374 void GLAPIENTRY
   1375 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
   1376 {
   1377    VertexAttrib4f_nopos(index, x, y, z, w);
   1378 }
   1379 
   1380 
   1381 void GLAPIENTRY
   1382 _es_VertexAttrib1f(GLuint indx, GLfloat x)
   1383 {
   1384    VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
   1385 }
   1386 
   1387 
   1388 void GLAPIENTRY
   1389 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
   1390 {
   1391    VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
   1392 }
   1393 
   1394 
   1395 void GLAPIENTRY
   1396 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
   1397 {
   1398    VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
   1399 }
   1400 
   1401 
   1402 void GLAPIENTRY
   1403 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
   1404 {
   1405    VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
   1406 }
   1407 
   1408 
   1409 void GLAPIENTRY
   1410 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
   1411 {
   1412    VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
   1413 }
   1414 
   1415 
   1416 void GLAPIENTRY
   1417 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
   1418 {
   1419    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
   1420 }
   1421 
   1422 
   1423 void GLAPIENTRY
   1424 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
   1425 {
   1426    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
   1427 }
   1428