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