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