17117f1b4Smrg/**************************************************************************
27117f1b4Smrg
3af69d88dSmrgCopyright 2002-2008 VMware, Inc.
47117f1b4Smrg
57117f1b4SmrgAll Rights Reserved.
67117f1b4Smrg
77117f1b4SmrgPermission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrgcopy of this software and associated documentation files (the "Software"),
97117f1b4Smrgto deal in the Software without restriction, including without limitation
107117f1b4Smrgon the rights to use, copy, modify, merge, publish, distribute, sub
117117f1b4Smrglicense, and/or sell copies of the Software, and to permit persons to whom
127117f1b4Smrgthe Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg
147117f1b4SmrgThe above copyright notice and this permission notice (including the next
157117f1b4Smrgparagraph) shall be included in all copies or substantial portions of the
167117f1b4SmrgSoftware.
177117f1b4Smrg
187117f1b4SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
197117f1b4SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
207117f1b4SmrgFITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21af69d88dSmrgVMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
227117f1b4SmrgDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
237117f1b4SmrgOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
247117f1b4SmrgUSE OR OTHER DEALINGS IN THE SOFTWARE.
257117f1b4Smrg
267117f1b4Smrg**************************************************************************/
277117f1b4Smrg
287117f1b4Smrg/*
297117f1b4Smrg * Authors:
30af69d88dSmrg *   Keith Whitwell <keithw@vmware.com>
317117f1b4Smrg */
327117f1b4Smrg
33c1f859d4Smrg#include "main/glheader.h"
34c1f859d4Smrg#include "main/bufferobj.h"
35c1f859d4Smrg#include "main/context.h"
36c1f859d4Smrg#include "main/macros.h"
37c1f859d4Smrg#include "main/vtxfmt.h"
38c1f859d4Smrg#include "main/dlist.h"
394a49301eSmrg#include "main/eval.h"
40c1f859d4Smrg#include "main/state.h"
41c1f859d4Smrg#include "main/light.h"
42c1f859d4Smrg#include "main/api_arrayelt.h"
4301e04c3fSmrg#include "main/draw_validate.h"
44cdc920a0Smrg#include "main/dispatch.h"
4501e04c3fSmrg#include "util/bitscan.h"
467ec681f3Smrg#include "util/u_memory.h"
477117f1b4Smrg
48af69d88dSmrg#include "vbo_noop.h"
4901e04c3fSmrg#include "vbo_private.h"
507117f1b4Smrg
517117f1b4Smrg
524a49301eSmrg/** ID/name for immediate-mode VBO */
534a49301eSmrg#define IMM_BUFFER_NAME 0xaabbccdd
544a49301eSmrg
554a49301eSmrg
567ec681f3Smrgstatic void GLAPIENTRY
577ec681f3Smrgvbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
587ec681f3Smrg
597ec681f3Smrgstatic void GLAPIENTRY
607ec681f3Smrgvbo_exec_EvalCoord1f(GLfloat u);
617ec681f3Smrg
627ec681f3Smrgstatic void GLAPIENTRY
637ec681f3Smrgvbo_exec_EvalCoord2f(GLfloat u, GLfloat v);
647ec681f3Smrg
657ec681f3Smrg
6601e04c3fSmrgstatic void
6701e04c3fSmrgvbo_reset_all_attr(struct vbo_exec_context *exec);
687117f1b4Smrg
697117f1b4Smrg
704a49301eSmrg/**
714a49301eSmrg * Close off the last primitive, execute the buffer, restart the
7201e04c3fSmrg * primitive.  This is called when we fill a vertex buffer before
7301e04c3fSmrg * hitting glEnd.
747117f1b4Smrg */
7501e04c3fSmrgstatic void
7601e04c3fSmrgvbo_exec_wrap_buffers(struct vbo_exec_context *exec)
777117f1b4Smrg{
787117f1b4Smrg   if (exec->vtx.prim_count == 0) {
797117f1b4Smrg      exec->vtx.copied.nr = 0;
807117f1b4Smrg      exec->vtx.vert_count = 0;
814a49301eSmrg      exec->vtx.buffer_ptr = exec->vtx.buffer_map;
827117f1b4Smrg   }
837117f1b4Smrg   else {
847ec681f3Smrg      struct gl_context *ctx = gl_context_from_vbo_exec(exec);
857ec681f3Smrg      unsigned last = exec->vtx.prim_count - 1;
867ec681f3Smrg      struct pipe_draw_start_count_bias *last_draw = &exec->vtx.draw[last];
877ec681f3Smrg      const bool last_begin = exec->vtx.markers[last].begin;
887ec681f3Smrg      GLuint last_count = 0;
897ec681f3Smrg
907ec681f3Smrg      if (_mesa_inside_begin_end(ctx)) {
917ec681f3Smrg         last_draw->count = exec->vtx.vert_count - last_draw->start;
927ec681f3Smrg         last_count = last_draw->count;
937ec681f3Smrg         exec->vtx.markers[last].end = 0;
947117f1b4Smrg      }
957117f1b4Smrg
9601e04c3fSmrg      /* Special handling for wrapping GL_LINE_LOOP */
977ec681f3Smrg      if (exec->vtx.mode[last] == GL_LINE_LOOP &&
9801e04c3fSmrg          last_count > 0 &&
997ec681f3Smrg          !exec->vtx.markers[last].end) {
10001e04c3fSmrg         /* draw this section of the incomplete line loop as a line strip */
1017ec681f3Smrg         exec->vtx.mode[last] = GL_LINE_STRIP;
1027ec681f3Smrg         if (!last_begin) {
10301e04c3fSmrg            /* This is not the first section of the line loop, so don't
10401e04c3fSmrg             * draw the 0th vertex.  We're saving it until we draw the
10501e04c3fSmrg             * very last section of the loop.
10601e04c3fSmrg             */
1077ec681f3Smrg            last_draw->start++;
1087ec681f3Smrg            last_draw->count--;
10901e04c3fSmrg         }
11001e04c3fSmrg      }
1117117f1b4Smrg
1127117f1b4Smrg      /* Execute the buffer and save copied vertices.
1137117f1b4Smrg       */
1147117f1b4Smrg      if (exec->vtx.vert_count)
1157ec681f3Smrg         vbo_exec_vtx_flush(exec);
1167117f1b4Smrg      else {
11701e04c3fSmrg         exec->vtx.prim_count = 0;
11801e04c3fSmrg         exec->vtx.copied.nr = 0;
1197117f1b4Smrg      }
1207117f1b4Smrg
1217117f1b4Smrg      /* Emit a glBegin to start the new list.
1227117f1b4Smrg       */
1237117f1b4Smrg      assert(exec->vtx.prim_count == 0);
1247117f1b4Smrg
1257ec681f3Smrg      if (_mesa_inside_begin_end(ctx)) {
1267ec681f3Smrg         exec->vtx.mode[0] = ctx->Driver.CurrentExecPrimitive;
1277ec681f3Smrg         exec->vtx.draw[0].start = 0;
1287ec681f3Smrg         exec->vtx.markers[0].begin = 0;
12901e04c3fSmrg         exec->vtx.prim_count++;
13001e04c3fSmrg
13101e04c3fSmrg         if (exec->vtx.copied.nr == last_count)
1327ec681f3Smrg            exec->vtx.markers[0].begin = last_begin;
1337117f1b4Smrg      }
1347117f1b4Smrg   }
1357117f1b4Smrg}
1367117f1b4Smrg
1377117f1b4Smrg
1384a49301eSmrg/**
1394a49301eSmrg * Deal with buffer wrapping where provoked by the vertex buffer
1407117f1b4Smrg * filling up, as opposed to upgrade_vertex().
1417117f1b4Smrg */
14201e04c3fSmrgstatic void
14301e04c3fSmrgvbo_exec_vtx_wrap(struct vbo_exec_context *exec)
1447117f1b4Smrg{
14501e04c3fSmrg   unsigned numComponents;
1467117f1b4Smrg
1477117f1b4Smrg   /* Run pipeline on current vertices, copy wrapped vertices
1487117f1b4Smrg    * to exec->vtx.copied.
1497117f1b4Smrg    */
15001e04c3fSmrg   vbo_exec_wrap_buffers(exec);
15101e04c3fSmrg
152af69d88dSmrg   if (!exec->vtx.buffer_ptr) {
153af69d88dSmrg      /* probably ran out of memory earlier when allocating the VBO */
154af69d88dSmrg      return;
155af69d88dSmrg   }
156af69d88dSmrg
15701e04c3fSmrg   /* Copy stored stored vertices to start of new list.
1587117f1b4Smrg    */
1597117f1b4Smrg   assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
1607117f1b4Smrg
16101e04c3fSmrg   numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size;
16201e04c3fSmrg   memcpy(exec->vtx.buffer_ptr,
16301e04c3fSmrg          exec->vtx.copied.buffer,
16401e04c3fSmrg          numComponents * sizeof(fi_type));
16501e04c3fSmrg   exec->vtx.buffer_ptr += numComponents;
16601e04c3fSmrg   exec->vtx.vert_count += exec->vtx.copied.nr;
1677117f1b4Smrg
1687117f1b4Smrg   exec->vtx.copied.nr = 0;
1697117f1b4Smrg}
1707117f1b4Smrg
1717117f1b4Smrg
1724a49301eSmrg/**
1737117f1b4Smrg * Copy the active vertex's values to the ctx->Current fields.
1747117f1b4Smrg */
17501e04c3fSmrgstatic void
17601e04c3fSmrgvbo_exec_copy_to_current(struct vbo_exec_context *exec)
1777117f1b4Smrg{
1787ec681f3Smrg   struct gl_context *ctx = gl_context_from_vbo_exec(exec);
1797117f1b4Smrg   struct vbo_context *vbo = vbo_context(ctx);
18001e04c3fSmrg   GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
1817ec681f3Smrg   bool color0_changed = false;
1827117f1b4Smrg
18301e04c3fSmrg   while (enabled) {
18401e04c3fSmrg      const int i = u_bit_scan64(&enabled);
1854a49301eSmrg
18601e04c3fSmrg      /* Note: the exec->vtx.current[i] pointers point into the
18701e04c3fSmrg       * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
18801e04c3fSmrg       */
18901e04c3fSmrg      GLfloat *current = (GLfloat *)vbo->current[i].Ptr;
19001e04c3fSmrg      fi_type tmp[8]; /* space for doubles */
1917ec681f3Smrg      int dmul_shift = 0;
19201e04c3fSmrg
1937ec681f3Smrg      assert(exec->vtx.attr[i].size);
19401e04c3fSmrg
1957ec681f3Smrg      if (exec->vtx.attr[i].type == GL_DOUBLE ||
1967ec681f3Smrg          exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB) {
19701e04c3fSmrg         memset(tmp, 0, sizeof(tmp));
1987ec681f3Smrg         memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attr[i].size * sizeof(GLfloat));
1997ec681f3Smrg         dmul_shift = 1;
20001e04c3fSmrg      } else {
20101e04c3fSmrg         COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
2027ec681f3Smrg                                     exec->vtx.attr[i].size,
203af69d88dSmrg                                     exec->vtx.attrptr[i],
2047ec681f3Smrg                                     exec->vtx.attr[i].type);
20501e04c3fSmrg      }
20601e04c3fSmrg
2077ec681f3Smrg      if (memcmp(current, tmp, 4 * sizeof(GLfloat) << dmul_shift) != 0) {
2087ec681f3Smrg         memcpy(current, tmp, 4 * sizeof(GLfloat) << dmul_shift);
20901e04c3fSmrg
2107ec681f3Smrg         if (i == VBO_ATTRIB_COLOR0)
2117ec681f3Smrg            color0_changed = true;
21201e04c3fSmrg
2137ec681f3Smrg         if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT) {
2147ec681f3Smrg            ctx->NewState |= _NEW_MATERIAL;
2157ec681f3Smrg            ctx->PopAttribState |= GL_LIGHTING_BIT;
2167ec681f3Smrg
2177ec681f3Smrg            /* The fixed-func vertex program uses this. */
2187ec681f3Smrg            if (i == VBO_ATTRIB_MAT_FRONT_SHININESS ||
2197ec681f3Smrg                i == VBO_ATTRIB_MAT_BACK_SHININESS)
2207ec681f3Smrg               ctx->NewState |= _NEW_FF_VERT_PROGRAM;
2217ec681f3Smrg         } else {
2227ec681f3Smrg            ctx->NewState |= _NEW_CURRENT_ATTRIB;
2237ec681f3Smrg            ctx->PopAttribState |= GL_CURRENT_BIT;
2247ec681f3Smrg         }
2257ec681f3Smrg      }
22601e04c3fSmrg
2277ec681f3Smrg      /* Given that we explicitly state size here, there is no need
2287ec681f3Smrg       * for the COPY_CLEAN above, could just copy 16 bytes and be
2297ec681f3Smrg       * done.  The only problem is when Mesa accesses ctx->Current
2307ec681f3Smrg       * directly.
2317ec681f3Smrg       */
2327ec681f3Smrg      /* Size here is in components - not bytes */
2337ec681f3Smrg      if (exec->vtx.attr[i].type != vbo->current[i].Format.Type ||
2347ec681f3Smrg          (exec->vtx.attr[i].size >> dmul_shift) != vbo->current[i].Format.Size) {
2357ec681f3Smrg         vbo_set_vertex_format(&vbo->current[i].Format,
2367ec681f3Smrg                               exec->vtx.attr[i].size >> dmul_shift,
2377ec681f3Smrg                               exec->vtx.attr[i].type);
2387117f1b4Smrg      }
2397117f1b4Smrg   }
2407117f1b4Smrg
2417ec681f3Smrg   if (color0_changed && ctx->Light.ColorMaterialEnabled) {
24201e04c3fSmrg      _mesa_update_color_material(ctx,
24301e04c3fSmrg                                  ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
2447117f1b4Smrg   }
2457117f1b4Smrg}
2467117f1b4Smrg
2477117f1b4Smrg
2484a49301eSmrg/**
2494a49301eSmrg * Flush existing data, set new attrib size, replay copied vertices.
2503464ebd5Sriastradh * This is called when we transition from a small vertex attribute size
2513464ebd5Sriastradh * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
2523464ebd5Sriastradh * We need to go back over the previous 2-component texcoords and insert
2533464ebd5Sriastradh * zero and one values.
25401e04c3fSmrg * \param attr  VBO_ATTRIB_x vertex attribute value
25501e04c3fSmrg */
2563464ebd5Sriastradhstatic void
2573464ebd5Sriastradhvbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
2587ec681f3Smrg                             GLuint attr, GLuint newSize, GLenum newType)
2597117f1b4Smrg{
2607ec681f3Smrg   struct gl_context *ctx = gl_context_from_vbo_exec(exec);
2617117f1b4Smrg   struct vbo_context *vbo = vbo_context(ctx);
2623464ebd5Sriastradh   const GLint lastcount = exec->vtx.vert_count;
26301e04c3fSmrg   fi_type *old_attrptr[VBO_ATTRIB_MAX];
2647ec681f3Smrg   const GLuint old_vtx_size_no_pos = exec->vtx.vertex_size_no_pos;
2653464ebd5Sriastradh   const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
2667ec681f3Smrg   const GLuint oldSize = exec->vtx.attr[attr].size;
2677117f1b4Smrg   GLuint i;
2687117f1b4Smrg
26901e04c3fSmrg   assert(attr < VBO_ATTRIB_MAX);
27001e04c3fSmrg
2717ec681f3Smrg   if (unlikely(!exec->vtx.buffer_ptr)) {
2727ec681f3Smrg      /* We should only hit this when use_buffer_objects=true */
2737ec681f3Smrg      assert(exec->vtx.bufferobj);
2747ec681f3Smrg      vbo_exec_vtx_map(exec);
2757ec681f3Smrg      assert(exec->vtx.buffer_ptr);
2767ec681f3Smrg   }
2777ec681f3Smrg
2787117f1b4Smrg   /* Run pipeline on current vertices, copy wrapped vertices
2797117f1b4Smrg    * to exec->vtx.copied.
2807117f1b4Smrg    */
28101e04c3fSmrg   vbo_exec_wrap_buffers(exec);
2827117f1b4Smrg
2833464ebd5Sriastradh   if (unlikely(exec->vtx.copied.nr)) {
2843464ebd5Sriastradh      /* We're in the middle of a primitive, keep the old vertex
2853464ebd5Sriastradh       * format around to be able to translate the copied vertices to
2863464ebd5Sriastradh       * the new format.
2873464ebd5Sriastradh       */
2883464ebd5Sriastradh      memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
2893464ebd5Sriastradh   }
2907117f1b4Smrg
2917117f1b4Smrg   /* Heuristic: Attempt to isolate attributes received outside
2927117f1b4Smrg    * begin/end so that they don't bloat the vertices.
2937117f1b4Smrg    */
294af69d88dSmrg   if (!_mesa_inside_begin_end(ctx) &&
2953464ebd5Sriastradh       !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
29601e04c3fSmrg      vbo_exec_copy_to_current(exec);
29701e04c3fSmrg      vbo_reset_all_attr(exec);
2987117f1b4Smrg   }
2997117f1b4Smrg
3007117f1b4Smrg   /* Fix up sizes:
3017117f1b4Smrg    */
3027ec681f3Smrg   exec->vtx.attr[attr].size = newSize;
3037ec681f3Smrg   exec->vtx.attr[attr].active_size = newSize;
3047ec681f3Smrg   exec->vtx.attr[attr].type = newType;
3053464ebd5Sriastradh   exec->vtx.vertex_size += newSize - oldSize;
3067ec681f3Smrg   exec->vtx.vertex_size_no_pos = exec->vtx.vertex_size - exec->vtx.attr[0].size;
30701e04c3fSmrg   exec->vtx.max_vert = vbo_compute_max_verts(exec);
3087117f1b4Smrg   exec->vtx.vert_count = 0;
3094a49301eSmrg   exec->vtx.buffer_ptr = exec->vtx.buffer_map;
31001e04c3fSmrg   exec->vtx.enabled |= BITFIELD64_BIT(attr);
3117117f1b4Smrg
3127ec681f3Smrg   if (attr != 0) {
3137ec681f3Smrg      if (unlikely(oldSize)) {
3147ec681f3Smrg         unsigned offset = exec->vtx.attrptr[attr] - exec->vtx.vertex;
3157ec681f3Smrg
3167ec681f3Smrg         /* If there are attribs after the resized attrib... */
3177ec681f3Smrg         if (offset + oldSize < old_vtx_size_no_pos) {
3187ec681f3Smrg            int size_diff = newSize - oldSize;
3197ec681f3Smrg            fi_type *old_first = exec->vtx.attrptr[attr] + oldSize;
3207ec681f3Smrg            fi_type *new_first = exec->vtx.attrptr[attr] + newSize;
3217ec681f3Smrg            fi_type *old_last = exec->vtx.vertex + old_vtx_size_no_pos - 1;
3227ec681f3Smrg            fi_type *new_last = exec->vtx.vertex + exec->vtx.vertex_size_no_pos - 1;
3237ec681f3Smrg
3247ec681f3Smrg            if (size_diff < 0) {
3257ec681f3Smrg               /* Decreasing the size: Copy from first to last to move
3267ec681f3Smrg                * elements to the left.
3277ec681f3Smrg                */
3287ec681f3Smrg               fi_type *old_end = old_last + 1;
3297ec681f3Smrg               fi_type *old = old_first;
3307ec681f3Smrg               fi_type *new = new_first;
3317ec681f3Smrg
3327ec681f3Smrg               do {
3337ec681f3Smrg                  *new++ = *old++;
3347ec681f3Smrg               } while (old != old_end);
3357ec681f3Smrg            } else {
3367ec681f3Smrg               /* Increasing the size: Copy from last to first to move
3377ec681f3Smrg                * elements to the right.
3387ec681f3Smrg                */
3397ec681f3Smrg               fi_type *old_end = old_first - 1;
3407ec681f3Smrg               fi_type *old = old_last;
3417ec681f3Smrg               fi_type *new = new_last;
3427ec681f3Smrg
3437ec681f3Smrg               do {
3447ec681f3Smrg                  *new-- = *old--;
3457ec681f3Smrg               } while (old != old_end);
3467ec681f3Smrg            }
3477ec681f3Smrg
3487ec681f3Smrg            /* Update pointers to attribs, because we moved them. */
3497ec681f3Smrg            GLbitfield64 enabled = exec->vtx.enabled &
3507ec681f3Smrg                                   ~BITFIELD64_BIT(VBO_ATTRIB_POS) &
3517ec681f3Smrg                                   ~BITFIELD64_BIT(attr);
3527ec681f3Smrg            while (enabled) {
3537ec681f3Smrg               unsigned i = u_bit_scan64(&enabled);
3543464ebd5Sriastradh
3557ec681f3Smrg               if (exec->vtx.attrptr[i] > exec->vtx.attrptr[attr])
3567ec681f3Smrg                  exec->vtx.attrptr[i] += size_diff;
3577ec681f3Smrg            }
35801e04c3fSmrg         }
3597ec681f3Smrg      } else {
3607ec681f3Smrg         /* Just have to append the new attribute at the end */
3617ec681f3Smrg         exec->vtx.attrptr[attr] = exec->vtx.vertex +
3627ec681f3Smrg           exec->vtx.vertex_size_no_pos - newSize;
3637117f1b4Smrg      }
3643464ebd5Sriastradh   }
3657117f1b4Smrg
3667ec681f3Smrg   /* The position is always last. */
3677ec681f3Smrg   exec->vtx.attrptr[0] = exec->vtx.vertex + exec->vtx.vertex_size_no_pos;
3687ec681f3Smrg
3697117f1b4Smrg   /* Replay stored vertices to translate them
3707117f1b4Smrg    * to new format here.
3717117f1b4Smrg    *
3727117f1b4Smrg    * -- No need to replay - just copy piecewise
3737117f1b4Smrg    */
3743464ebd5Sriastradh   if (unlikely(exec->vtx.copied.nr)) {
37501e04c3fSmrg      fi_type *data = exec->vtx.copied.buffer;
37601e04c3fSmrg      fi_type *dest = exec->vtx.buffer_ptr;
3777117f1b4Smrg
3784a49301eSmrg      assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
3793464ebd5Sriastradh
3807117f1b4Smrg      for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
38101e04c3fSmrg         GLbitfield64 enabled = exec->vtx.enabled;
38201e04c3fSmrg         while (enabled) {
38301e04c3fSmrg            const int j = u_bit_scan64(&enabled);
3847ec681f3Smrg            GLuint sz = exec->vtx.attr[j].size;
38501e04c3fSmrg            GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
38601e04c3fSmrg            GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
38701e04c3fSmrg
38801e04c3fSmrg            assert(sz);
38901e04c3fSmrg
39001e04c3fSmrg            if (j == attr) {
39101e04c3fSmrg               if (oldSize) {
39201e04c3fSmrg                  fi_type tmp[4];
39301e04c3fSmrg                  COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
39401e04c3fSmrg                                              data + old_offset,
3957ec681f3Smrg                                              exec->vtx.attr[j].type);
39601e04c3fSmrg                  COPY_SZ_4V(dest + new_offset, newSize, tmp);
39701e04c3fSmrg               } else {
39801e04c3fSmrg                  fi_type *current = (fi_type *)vbo->current[j].Ptr;
39901e04c3fSmrg                  COPY_SZ_4V(dest + new_offset, sz, current);
40001e04c3fSmrg               }
40101e04c3fSmrg            }
40201e04c3fSmrg            else {
40301e04c3fSmrg               COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
40401e04c3fSmrg            }
40501e04c3fSmrg         }
40601e04c3fSmrg
40701e04c3fSmrg         data += old_vtx_size;
40801e04c3fSmrg         dest += exec->vtx.vertex_size;
4097117f1b4Smrg      }
4107117f1b4Smrg
4114a49301eSmrg      exec->vtx.buffer_ptr = dest;
4127117f1b4Smrg      exec->vtx.vert_count += exec->vtx.copied.nr;
4137117f1b4Smrg      exec->vtx.copied.nr = 0;
4147117f1b4Smrg   }
4157117f1b4Smrg}
4167117f1b4Smrg
4177117f1b4Smrg
4183464ebd5Sriastradh/**
4193464ebd5Sriastradh * This is when a vertex attribute transitions to a different size.
4203464ebd5Sriastradh * For example, we saw a bunch of glTexCoord2f() calls and now we got a
4213464ebd5Sriastradh * glTexCoord4f() call.  We promote the array from size=2 to size=4.
42201e04c3fSmrg * \param newSize  size of new vertex (number of 32-bit words).
42301e04c3fSmrg * \param attr  VBO_ATTRIB_x vertex attribute value
4243464ebd5Sriastradh */
4253464ebd5Sriastradhstatic void
42601e04c3fSmrgvbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr,
42701e04c3fSmrg                      GLuint newSize, GLenum newType)
4287117f1b4Smrg{
4297117f1b4Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
4307117f1b4Smrg
43101e04c3fSmrg   assert(attr < VBO_ATTRIB_MAX);
43201e04c3fSmrg
4337ec681f3Smrg   if (newSize > exec->vtx.attr[attr].size ||
4347ec681f3Smrg       newType != exec->vtx.attr[attr].type) {
4357117f1b4Smrg      /* New size is larger.  Need to flush existing vertices and get
4367117f1b4Smrg       * an enlarged vertex format.
4377117f1b4Smrg       */
4387ec681f3Smrg      vbo_exec_wrap_upgrade_vertex(exec, attr, newSize, newType);
4397117f1b4Smrg   }
4407ec681f3Smrg   else if (newSize < exec->vtx.attr[attr].active_size) {
4413464ebd5Sriastradh      GLuint i;
44201e04c3fSmrg      const fi_type *id =
4437ec681f3Smrg            vbo_get_default_vals_as_union(exec->vtx.attr[attr].type);
4447117f1b4Smrg
4457117f1b4Smrg      /* New size is smaller - just need to fill in some
4467117f1b4Smrg       * zeros.  Don't need to flush or wrap.
4477117f1b4Smrg       */
4487ec681f3Smrg      for (i = newSize; i <= exec->vtx.attr[attr].size; i++)
44901e04c3fSmrg         exec->vtx.attrptr[attr][i-1] = id[i-1];
4507117f1b4Smrg
4517ec681f3Smrg      exec->vtx.attr[attr].active_size = newSize;
4527ec681f3Smrg   }
45301e04c3fSmrg}
45401e04c3fSmrg
45501e04c3fSmrg
4568a1362adSmaya/**
4578a1362adSmaya * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
4588a1362adSmaya * It depends on a few things, including whether we're inside or outside
4598a1362adSmaya * of glBegin/glEnd.
4608a1362adSmaya */
4618a1362adSmayastatic inline bool
4628a1362adSmayais_vertex_position(const struct gl_context *ctx, GLuint index)
4638a1362adSmaya{
4648a1362adSmaya   return (index == 0 &&
4658a1362adSmaya           _mesa_attr_zero_aliases_vertex(ctx) &&
4668a1362adSmaya           _mesa_inside_begin_end(ctx));
4678a1362adSmaya}
4688a1362adSmaya
4697ec681f3Smrg/* Write a 64-bit value into a 32-bit pointer by preserving endianness. */
4707ec681f3Smrg#if UTIL_ARCH_LITTLE_ENDIAN
4717ec681f3Smrg   #define SET_64BIT(dst32, u64) do { \
4727ec681f3Smrg         *(dst32)++ = (u64); \
4737ec681f3Smrg         *(dst32)++ = (uint64_t)(u64) >> 32; \
4747ec681f3Smrg      } while (0)
4757ec681f3Smrg#else
4767ec681f3Smrg   #define SET_64BIT(dst32, u64) do { \
4777ec681f3Smrg         *(dst32)++ = (uint64_t)(u64) >> 32; \
4787ec681f3Smrg         *(dst32)++ = (u64); \
4797ec681f3Smrg      } while (0)
4807ec681f3Smrg#endif
4817ec681f3Smrg
4828a1362adSmaya
4833464ebd5Sriastradh/**
4843464ebd5Sriastradh * This macro is used to implement all the glVertex, glColor, glTexCoord,
4853464ebd5Sriastradh * glVertexAttrib, etc functions.
48601e04c3fSmrg * \param A  VBO_ATTRIB_x attribute index
48701e04c3fSmrg * \param N  attribute size (1..4)
48801e04c3fSmrg * \param T  type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
4897ec681f3Smrg * \param C  cast type (uint32_t or uint64_t)
49001e04c3fSmrg * \param V0, V1, v2, V3  attribute value
4917117f1b4Smrg */
49201e04c3fSmrg#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                          \
49301e04c3fSmrgdo {                                                                    \
49401e04c3fSmrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;             \
49501e04c3fSmrg   int sz = (sizeof(C) / sizeof(GLfloat));                              \
49601e04c3fSmrg                                                                        \
49701e04c3fSmrg   assert(sz == 1 || sz == 2);                                          \
4987ec681f3Smrg   /* store a copy of the attribute in exec except for glVertex */      \
4997ec681f3Smrg   if ((A) != 0) {                                                      \
5007ec681f3Smrg      /* Check if attribute size or type is changing. */                \
5017ec681f3Smrg      if (unlikely(exec->vtx.attr[A].active_size != N * sz ||           \
5027ec681f3Smrg                   exec->vtx.attr[A].type != T)) {                      \
5037ec681f3Smrg         vbo_exec_fixup_vertex(ctx, A, N * sz, T);                      \
5047ec681f3Smrg      }                                                                 \
50501e04c3fSmrg                                                                        \
50601e04c3fSmrg      C *dest = (C *)exec->vtx.attrptr[A];                              \
50701e04c3fSmrg      if (N>0) dest[0] = V0;                                            \
50801e04c3fSmrg      if (N>1) dest[1] = V1;                                            \
50901e04c3fSmrg      if (N>2) dest[2] = V2;                                            \
51001e04c3fSmrg      if (N>3) dest[3] = V3;                                            \
5117ec681f3Smrg      assert(exec->vtx.attr[A].type == T);                              \
51201e04c3fSmrg                                                                        \
5137ec681f3Smrg      /* we now have accumulated a per-vertex attribute */              \
5147ec681f3Smrg      ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;                    \
5157ec681f3Smrg   } else {                                                             \
51601e04c3fSmrg      /* This is a glVertex call */                                     \
5177ec681f3Smrg      int size = exec->vtx.attr[0].size;                                \
51801e04c3fSmrg                                                                        \
5197ec681f3Smrg      /* Check if attribute size or type is changing. */                \
5207ec681f3Smrg      if (unlikely(size < N * sz ||                                     \
5217ec681f3Smrg                   exec->vtx.attr[0].type != T)) {                      \
5227ec681f3Smrg         vbo_exec_wrap_upgrade_vertex(exec, 0, N * sz, T);              \
52301e04c3fSmrg      }                                                                 \
52401e04c3fSmrg                                                                        \
5257ec681f3Smrg      uint32_t *dst = (uint32_t *)exec->vtx.buffer_ptr;                 \
5267ec681f3Smrg      uint32_t *src = (uint32_t *)exec->vtx.vertex;                     \
5277ec681f3Smrg      unsigned vertex_size_no_pos = exec->vtx.vertex_size_no_pos;       \
52801e04c3fSmrg                                                                        \
5297ec681f3Smrg      /* Copy over attributes from exec. */                             \
5307ec681f3Smrg      for (unsigned i = 0; i < vertex_size_no_pos; i++)                 \
5317ec681f3Smrg         *dst++ = *src++;                                               \
53201e04c3fSmrg                                                                        \
5337ec681f3Smrg      /* Store the position, which is always last and can have 32 or */ \
5347ec681f3Smrg      /* 64 bits per channel. */                                        \
5357ec681f3Smrg      if (sizeof(C) == 4) {                                             \
5367ec681f3Smrg         if (N > 0) *dst++ = V0;                                        \
5377ec681f3Smrg         if (N > 1) *dst++ = V1;                                        \
5387ec681f3Smrg         if (N > 2) *dst++ = V2;                                        \
5397ec681f3Smrg         if (N > 3) *dst++ = V3;                                        \
54001e04c3fSmrg                                                                        \
5417ec681f3Smrg         if (unlikely(N < size)) {                                      \
5427ec681f3Smrg            if (N < 2 && size >= 2) *dst++ = V1;                        \
5437ec681f3Smrg            if (N < 3 && size >= 3) *dst++ = V2;                        \
5447ec681f3Smrg            if (N < 4 && size >= 4) *dst++ = V3;                        \
5457ec681f3Smrg         }                                                              \
5467ec681f3Smrg      } else {                                                          \
5477ec681f3Smrg         /* 64 bits: dst can be unaligned, so copy each 4-byte word */  \
5487ec681f3Smrg         /* separately */                                               \
5497ec681f3Smrg         if (N > 0) SET_64BIT(dst, V0);                                 \
5507ec681f3Smrg         if (N > 1) SET_64BIT(dst, V1);                                 \
5517ec681f3Smrg         if (N > 2) SET_64BIT(dst, V2);                                 \
5527ec681f3Smrg         if (N > 3) SET_64BIT(dst, V3);                                 \
5537ec681f3Smrg                                                                        \
5547ec681f3Smrg         if (unlikely(N * 2 < size)) {                                  \
5557ec681f3Smrg            if (N < 2 && size >= 4) SET_64BIT(dst, V1);                 \
5567ec681f3Smrg            if (N < 3 && size >= 6) SET_64BIT(dst, V2);                 \
5577ec681f3Smrg            if (N < 4 && size >= 8) SET_64BIT(dst, V3);                 \
5587ec681f3Smrg         }                                                              \
5597ec681f3Smrg      }                                                                 \
56001e04c3fSmrg                                                                        \
5617ec681f3Smrg      /* dst now points at the beginning of the next vertex */          \
5627ec681f3Smrg      exec->vtx.buffer_ptr = (fi_type*)dst;                             \
5637ec681f3Smrg                                                                        \
5647ec681f3Smrg      /* Don't set FLUSH_UPDATE_CURRENT because */                      \
5657ec681f3Smrg      /* Current.Attrib[VBO_ATTRIB_POS] is never used. */               \
5667ec681f3Smrg                                                                        \
5677ec681f3Smrg      if (unlikely(++exec->vtx.vert_count >= exec->vtx.max_vert))       \
56801e04c3fSmrg         vbo_exec_vtx_wrap(exec);                                       \
56901e04c3fSmrg   }                                                                    \
5707117f1b4Smrg} while (0)
5717117f1b4Smrg
5727117f1b4Smrg
57301e04c3fSmrg#undef ERROR
57401e04c3fSmrg#define ERROR(err) _mesa_error(ctx, err, __func__)
5757ec681f3Smrg#define TAG(x) vbo_exec_##x
5767117f1b4Smrg
5777117f1b4Smrg#include "vbo_attrib_tmp.h"
5787117f1b4Smrg
5797117f1b4Smrg
5807117f1b4Smrg
581af69d88dSmrg/**
582af69d88dSmrg * Execute a glMaterial call.  Note that if GL_COLOR_MATERIAL is enabled,
583af69d88dSmrg * this may be a (partial) no-op.
584af69d88dSmrg */
585af69d88dSmrgstatic void GLAPIENTRY
5867ec681f3Smrgvbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
587af69d88dSmrg{
588af69d88dSmrg   GLbitfield updateMats;
589af69d88dSmrg   GET_CURRENT_CONTEXT(ctx);
590af69d88dSmrg
591af69d88dSmrg   /* This function should be a no-op when it tries to update material
592af69d88dSmrg    * attributes which are currently tracking glColor via glColorMaterial.
593af69d88dSmrg    * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
594af69d88dSmrg    * indicating which material attributes can actually be updated below.
595af69d88dSmrg    */
596af69d88dSmrg   if (ctx->Light.ColorMaterialEnabled) {
597af69d88dSmrg      updateMats = ~ctx->Light._ColorMaterialBitmask;
598af69d88dSmrg   }
599af69d88dSmrg   else {
600af69d88dSmrg      /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
601af69d88dSmrg      updateMats = ALL_MATERIAL_BITS;
602af69d88dSmrg   }
603af69d88dSmrg
604af69d88dSmrg   if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
605af69d88dSmrg      updateMats &= FRONT_MATERIAL_BITS;
606af69d88dSmrg   }
607af69d88dSmrg   else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
608af69d88dSmrg      updateMats &= BACK_MATERIAL_BITS;
609af69d88dSmrg   }
610af69d88dSmrg   else if (face != GL_FRONT_AND_BACK) {
611af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
612af69d88dSmrg      return;
613af69d88dSmrg   }
614af69d88dSmrg
615af69d88dSmrg   switch (pname) {
616af69d88dSmrg   case GL_EMISSION:
617af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_EMISSION)
618af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
619af69d88dSmrg      if (updateMats & MAT_BIT_BACK_EMISSION)
620af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
621af69d88dSmrg      break;
622af69d88dSmrg   case GL_AMBIENT:
623af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_AMBIENT)
624af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
625af69d88dSmrg      if (updateMats & MAT_BIT_BACK_AMBIENT)
626af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
627af69d88dSmrg      break;
628af69d88dSmrg   case GL_DIFFUSE:
629af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_DIFFUSE)
630af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
631af69d88dSmrg      if (updateMats & MAT_BIT_BACK_DIFFUSE)
632af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
633af69d88dSmrg      break;
634af69d88dSmrg   case GL_SPECULAR:
635af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_SPECULAR)
636af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
637af69d88dSmrg      if (updateMats & MAT_BIT_BACK_SPECULAR)
638af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
639af69d88dSmrg      break;
640af69d88dSmrg   case GL_SHININESS:
641af69d88dSmrg      if (*params < 0 || *params > ctx->Const.MaxShininess) {
642af69d88dSmrg         _mesa_error(ctx, GL_INVALID_VALUE,
643af69d88dSmrg                     "glMaterial(invalid shininess: %f out range [0, %f])",
64401e04c3fSmrg                     *params, ctx->Const.MaxShininess);
645af69d88dSmrg         return;
646af69d88dSmrg      }
647af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_SHININESS)
648af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
649af69d88dSmrg      if (updateMats & MAT_BIT_BACK_SHININESS)
650af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
651af69d88dSmrg      break;
652af69d88dSmrg   case GL_COLOR_INDEXES:
653af69d88dSmrg      if (ctx->API != API_OPENGL_COMPAT) {
654af69d88dSmrg         _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
655af69d88dSmrg         return;
656af69d88dSmrg      }
657af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_INDEXES)
658af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
659af69d88dSmrg      if (updateMats & MAT_BIT_BACK_INDEXES)
660af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
661af69d88dSmrg      break;
662af69d88dSmrg   case GL_AMBIENT_AND_DIFFUSE:
663af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_AMBIENT)
664af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
665af69d88dSmrg      if (updateMats & MAT_BIT_FRONT_DIFFUSE)
666af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
667af69d88dSmrg      if (updateMats & MAT_BIT_BACK_AMBIENT)
668af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
669af69d88dSmrg      if (updateMats & MAT_BIT_BACK_DIFFUSE)
670af69d88dSmrg         MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
671af69d88dSmrg      break;
672af69d88dSmrg   default:
673af69d88dSmrg      _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
674af69d88dSmrg      return;
675af69d88dSmrg   }
676af69d88dSmrg}
677af69d88dSmrg
678af69d88dSmrg
679af69d88dSmrg/**
680af69d88dSmrg * Flush (draw) vertices.
6817ec681f3Smrg *
6827ec681f3Smrg * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
683af69d88dSmrg */
684af69d88dSmrgstatic void
6857ec681f3Smrgvbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, unsigned flags)
686af69d88dSmrg{
6877ec681f3Smrg   struct gl_context *ctx = gl_context_from_vbo_exec(exec);
6887ec681f3Smrg
6897ec681f3Smrg   if (flags & FLUSH_STORED_VERTICES) {
6907ec681f3Smrg      if (exec->vtx.vert_count) {
6917ec681f3Smrg         vbo_exec_vtx_flush(exec);
6927ec681f3Smrg      }
693af69d88dSmrg
6947ec681f3Smrg      if (exec->vtx.vertex_size) {
6957ec681f3Smrg         vbo_exec_copy_to_current(exec);
6967ec681f3Smrg         vbo_reset_all_attr(exec);
6977ec681f3Smrg      }
6987ec681f3Smrg
6997ec681f3Smrg      /* All done. */
7007ec681f3Smrg      ctx->Driver.NeedFlush = 0;
7017ec681f3Smrg   } else {
7027ec681f3Smrg      assert(flags == FLUSH_UPDATE_CURRENT);
7037ec681f3Smrg
7047ec681f3Smrg      /* Note that the vertex size is unchanged.
7057ec681f3Smrg       * (vbo_reset_all_attr isn't called)
7067ec681f3Smrg       */
70701e04c3fSmrg      vbo_exec_copy_to_current(exec);
7087ec681f3Smrg
7097ec681f3Smrg      /* Only FLUSH_UPDATE_CURRENT is done. */
7107ec681f3Smrg      ctx->Driver.NeedFlush = ~FLUSH_UPDATE_CURRENT;
711af69d88dSmrg   }
712af69d88dSmrg}
7137117f1b4Smrg
7144a49301eSmrg
71501e04c3fSmrgstatic void GLAPIENTRY
71601e04c3fSmrgvbo_exec_EvalCoord1f(GLfloat u)
7177117f1b4Smrg{
71801e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
7197117f1b4Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
7207117f1b4Smrg
7217117f1b4Smrg   {
7227117f1b4Smrg      GLint i;
72301e04c3fSmrg      if (exec->eval.recalculate_maps)
72401e04c3fSmrg         vbo_exec_eval_update(exec);
7257117f1b4Smrg
7267117f1b4Smrg      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
72701e04c3fSmrg         if (exec->eval.map1[i].map)
7287ec681f3Smrg            if (exec->vtx.attr[i].active_size != exec->eval.map1[i].sz)
72901e04c3fSmrg               vbo_exec_fixup_vertex(ctx, i, exec->eval.map1[i].sz, GL_FLOAT);
7307117f1b4Smrg      }
7317117f1b4Smrg   }
7327117f1b4Smrg
73301e04c3fSmrg   memcpy(exec->vtx.copied.buffer, exec->vtx.vertex,
73401e04c3fSmrg          exec->vtx.vertex_size * sizeof(GLfloat));
7357117f1b4Smrg
73601e04c3fSmrg   vbo_exec_do_EvalCoord1f(exec, u);
7377117f1b4Smrg
73801e04c3fSmrg   memcpy(exec->vtx.vertex, exec->vtx.copied.buffer,
73901e04c3fSmrg          exec->vtx.vertex_size * sizeof(GLfloat));
7407117f1b4Smrg}
7417117f1b4Smrg
74201e04c3fSmrg
74301e04c3fSmrgstatic void GLAPIENTRY
74401e04c3fSmrgvbo_exec_EvalCoord2f(GLfloat u, GLfloat v)
7457117f1b4Smrg{
74601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
7477117f1b4Smrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
7487117f1b4Smrg
7497117f1b4Smrg   {
7507117f1b4Smrg      GLint i;
75101e04c3fSmrg      if (exec->eval.recalculate_maps)
75201e04c3fSmrg         vbo_exec_eval_update(exec);
7537117f1b4Smrg
7547117f1b4Smrg      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
75501e04c3fSmrg         if (exec->eval.map2[i].map)
7567ec681f3Smrg            if (exec->vtx.attr[i].active_size != exec->eval.map2[i].sz)
75701e04c3fSmrg               vbo_exec_fixup_vertex(ctx, i, exec->eval.map2[i].sz, GL_FLOAT);
7587117f1b4Smrg      }
7597117f1b4Smrg
76001e04c3fSmrg      if (ctx->Eval.AutoNormal)
7617ec681f3Smrg         if (exec->vtx.attr[VBO_ATTRIB_NORMAL].active_size != 3)
76201e04c3fSmrg            vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT);
7637117f1b4Smrg   }
7647117f1b4Smrg
76501e04c3fSmrg   memcpy(exec->vtx.copied.buffer, exec->vtx.vertex,
76601e04c3fSmrg          exec->vtx.vertex_size * sizeof(GLfloat));
7677117f1b4Smrg
76801e04c3fSmrg   vbo_exec_do_EvalCoord2f(exec, u, v);
7697117f1b4Smrg
77001e04c3fSmrg   memcpy(exec->vtx.vertex, exec->vtx.copied.buffer,
77101e04c3fSmrg          exec->vtx.vertex_size * sizeof(GLfloat));
7727117f1b4Smrg}
7737117f1b4Smrg
77401e04c3fSmrg
77501e04c3fSmrgstatic void GLAPIENTRY
77601e04c3fSmrgvbo_exec_EvalCoord1fv(const GLfloat *u)
7777117f1b4Smrg{
77801e04c3fSmrg   vbo_exec_EvalCoord1f(u[0]);
7797117f1b4Smrg}
7807117f1b4Smrg
78101e04c3fSmrg
78201e04c3fSmrgstatic void GLAPIENTRY
78301e04c3fSmrgvbo_exec_EvalCoord2fv(const GLfloat *u)
7847117f1b4Smrg{
78501e04c3fSmrg   vbo_exec_EvalCoord2f(u[0], u[1]);
7867117f1b4Smrg}
7877117f1b4Smrg
78801e04c3fSmrg
78901e04c3fSmrgstatic void GLAPIENTRY
79001e04c3fSmrgvbo_exec_EvalPoint1(GLint i)
7917117f1b4Smrg{
79201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
7937117f1b4Smrg   GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
79401e04c3fSmrg                 (GLfloat) ctx->Eval.MapGrid1un);
7957117f1b4Smrg   GLfloat u = i * du + ctx->Eval.MapGrid1u1;
7967117f1b4Smrg
79701e04c3fSmrg   vbo_exec_EvalCoord1f(u);
7987117f1b4Smrg}
7997117f1b4Smrg
8007117f1b4Smrg
80101e04c3fSmrgstatic void GLAPIENTRY
80201e04c3fSmrgvbo_exec_EvalPoint2(GLint i, GLint j)
8037117f1b4Smrg{
80401e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
80501e04c3fSmrg   GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
80601e04c3fSmrg                 (GLfloat) ctx->Eval.MapGrid2un);
80701e04c3fSmrg   GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
80801e04c3fSmrg                 (GLfloat) ctx->Eval.MapGrid2vn);
8097117f1b4Smrg   GLfloat u = i * du + ctx->Eval.MapGrid2u1;
8107117f1b4Smrg   GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
8117117f1b4Smrg
81201e04c3fSmrg   vbo_exec_EvalCoord2f(u, v);
8137117f1b4Smrg}
8147117f1b4Smrg
8157117f1b4Smrg
8163464ebd5Sriastradh/**
817af69d88dSmrg * Called via glBegin.
8183464ebd5Sriastradh */
81901e04c3fSmrgstatic void GLAPIENTRY
82001e04c3fSmrgvbo_exec_Begin(GLenum mode)
8213464ebd5Sriastradh{
82201e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
82301e04c3fSmrg   struct vbo_context *vbo = vbo_context(ctx);
82401e04c3fSmrg   struct vbo_exec_context *exec = &vbo->exec;
825af69d88dSmrg   int i;
826af69d88dSmrg
827af69d88dSmrg   if (_mesa_inside_begin_end(ctx)) {
828af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
829af69d88dSmrg      return;
8303464ebd5Sriastradh   }
8313464ebd5Sriastradh
8327ec681f3Smrg   if (ctx->NewState)
83301e04c3fSmrg      _mesa_update_state(ctx);
834af69d88dSmrg
8357ec681f3Smrg   GLenum error = _mesa_valid_prim_mode(ctx, mode);
8367ec681f3Smrg   if (error != GL_NO_ERROR) {
8377ec681f3Smrg      _mesa_error(ctx, error, "glBegin");
838af69d88dSmrg      return;
839af69d88dSmrg   }
840af69d88dSmrg
84101e04c3fSmrg   /* Heuristic: attempt to isolate attributes occurring outside
842af69d88dSmrg    * begin/end pairs.
8437ec681f3Smrg    *
8447ec681f3Smrg    * Use FLUSH_STORED_VERTICES, because it updates current attribs and
8457ec681f3Smrg    * sets vertex_size to 0. (FLUSH_UPDATE_CURRENT doesn't change vertex_size)
846af69d88dSmrg    */
8477ec681f3Smrg   if (exec->vtx.vertex_size && !exec->vtx.attr[VBO_ATTRIB_POS].size)
8487ec681f3Smrg      vbo_exec_FlushVertices_internal(exec, FLUSH_STORED_VERTICES);
849af69d88dSmrg
850af69d88dSmrg   i = exec->vtx.prim_count++;
8517ec681f3Smrg   exec->vtx.mode[i] = mode;
8527ec681f3Smrg   exec->vtx.draw[i].start = exec->vtx.vert_count;
8537ec681f3Smrg   exec->vtx.markers[i].begin = 1;
854af69d88dSmrg
855af69d88dSmrg   ctx->Driver.CurrentExecPrimitive = mode;
856af69d88dSmrg
857af69d88dSmrg   ctx->Exec = ctx->BeginEnd;
8588a1362adSmaya
859af69d88dSmrg   /* We may have been called from a display list, in which case we should
860af69d88dSmrg    * leave dlist.c's dispatch table in place.
861af69d88dSmrg    */
8628a1362adSmaya   if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
8638a1362adSmaya      ctx->CurrentServerDispatch = ctx->Exec;
8648a1362adSmaya   } else if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) {
8658a1362adSmaya      ctx->CurrentClientDispatch = ctx->Exec;
86601e04c3fSmrg      _glapi_set_dispatch(ctx->CurrentClientDispatch);
867af69d88dSmrg   } else {
86801e04c3fSmrg      assert(ctx->CurrentClientDispatch == ctx->Save);
8693464ebd5Sriastradh   }
8703464ebd5Sriastradh}
8713464ebd5Sriastradh
8723464ebd5Sriastradh
8734a49301eSmrg/**
874af69d88dSmrg * Try to merge / concatenate the two most recent VBO primitives.
8757117f1b4Smrg */
876af69d88dSmrgstatic void
877af69d88dSmrgtry_vbo_merge(struct vbo_exec_context *exec)
8787117f1b4Smrg{
8797ec681f3Smrg   unsigned cur = exec->vtx.prim_count - 1;
8807117f1b4Smrg
881af69d88dSmrg   assert(exec->vtx.prim_count >= 1);
8827117f1b4Smrg
8837ec681f3Smrg   vbo_try_prim_conversion(&exec->vtx.mode[cur], &exec->vtx.draw[cur].count);
8847117f1b4Smrg
885af69d88dSmrg   if (exec->vtx.prim_count >= 2) {
8867ec681f3Smrg      struct gl_context *ctx = gl_context_from_vbo_exec(exec);
8877ec681f3Smrg      unsigned prev = cur - 1;
8887ec681f3Smrg
8897ec681f3Smrg      if (vbo_merge_draws(ctx, false,
8907ec681f3Smrg                          exec->vtx.mode[prev],
8917ec681f3Smrg                          exec->vtx.mode[cur],
8927ec681f3Smrg                          exec->vtx.draw[prev].start,
8937ec681f3Smrg                          exec->vtx.draw[cur].start,
8947ec681f3Smrg                          &exec->vtx.draw[prev].count,
8957ec681f3Smrg                          exec->vtx.draw[cur].count,
8967ec681f3Smrg                          0, 0,
8977ec681f3Smrg                          &exec->vtx.markers[prev].end,
8987ec681f3Smrg                          exec->vtx.markers[cur].begin,
8997ec681f3Smrg                          exec->vtx.markers[cur].end))
900af69d88dSmrg         exec->vtx.prim_count--;  /* drop the last primitive */
9017117f1b4Smrg   }
9027117f1b4Smrg}
9037117f1b4Smrg
9044a49301eSmrg
9054a49301eSmrg/**
9064a49301eSmrg * Called via glEnd.
9074a49301eSmrg */
90801e04c3fSmrgstatic void GLAPIENTRY
90901e04c3fSmrgvbo_exec_End(void)
9107117f1b4Smrg{
91101e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
912af69d88dSmrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
9137117f1b4Smrg
914af69d88dSmrg   if (!_mesa_inside_begin_end(ctx)) {
915af69d88dSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
916af69d88dSmrg      return;
917af69d88dSmrg   }
9187117f1b4Smrg
919af69d88dSmrg   ctx->Exec = ctx->OutsideBeginEnd;
9208a1362adSmaya
9218a1362adSmaya   if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
9228a1362adSmaya      ctx->CurrentServerDispatch = ctx->Exec;
9238a1362adSmaya   } else if (ctx->CurrentClientDispatch == ctx->BeginEnd) {
9248a1362adSmaya      ctx->CurrentClientDispatch = ctx->Exec;
92501e04c3fSmrg      _glapi_set_dispatch(ctx->CurrentClientDispatch);
926af69d88dSmrg   }
9273464ebd5Sriastradh
928af69d88dSmrg   if (exec->vtx.prim_count > 0) {
929af69d88dSmrg      /* close off current primitive */
9307ec681f3Smrg      unsigned last = exec->vtx.prim_count - 1;
9317ec681f3Smrg      struct pipe_draw_start_count_bias *last_draw = &exec->vtx.draw[last];
9327ec681f3Smrg      unsigned count = exec->vtx.vert_count - last_draw->start;
93301e04c3fSmrg
9347ec681f3Smrg      last_draw->count = count;
9357ec681f3Smrg      exec->vtx.markers[last].end = 1;
9367ec681f3Smrg
9377ec681f3Smrg      if (count)
9387ec681f3Smrg         ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
93901e04c3fSmrg
94001e04c3fSmrg      /* Special handling for GL_LINE_LOOP */
9417ec681f3Smrg      if (exec->vtx.mode[last] == GL_LINE_LOOP &&
9427ec681f3Smrg          exec->vtx.markers[last].begin == 0) {
94301e04c3fSmrg         /* We're finishing drawing a line loop.  Append 0th vertex onto
94401e04c3fSmrg          * end of vertex buffer so we can draw it as a line strip.
94501e04c3fSmrg          */
94601e04c3fSmrg         const fi_type *src = exec->vtx.buffer_map +
9477ec681f3Smrg            last_draw->start * exec->vtx.vertex_size;
94801e04c3fSmrg         fi_type *dst = exec->vtx.buffer_map +
94901e04c3fSmrg            exec->vtx.vert_count * exec->vtx.vertex_size;
95001e04c3fSmrg
95101e04c3fSmrg         /* copy 0th vertex to end of buffer */
95201e04c3fSmrg         memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
9537117f1b4Smrg
9547ec681f3Smrg         last_draw->start++;  /* skip vertex0 */
9557ec681f3Smrg         /* note that the count stays unchanged */
9567ec681f3Smrg         exec->vtx.mode[last] = GL_LINE_STRIP;
95701e04c3fSmrg
95801e04c3fSmrg         /* Increment the vertex count so the next primitive doesn't
95901e04c3fSmrg          * overwrite the last vertex which we just added.
96001e04c3fSmrg          */
96101e04c3fSmrg         exec->vtx.vert_count++;
96201e04c3fSmrg         exec->vtx.buffer_ptr += exec->vtx.vertex_size;
96301e04c3fSmrg      }
9647117f1b4Smrg
965af69d88dSmrg      try_vbo_merge(exec);
966af69d88dSmrg   }
967af69d88dSmrg
968af69d88dSmrg   ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
969af69d88dSmrg
970af69d88dSmrg   if (exec->vtx.prim_count == VBO_MAX_PRIM)
9717ec681f3Smrg      vbo_exec_vtx_flush(exec);
972af69d88dSmrg
973af69d88dSmrg   if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
974af69d88dSmrg      _mesa_flush(ctx);
9757117f1b4Smrg   }
9767117f1b4Smrg}
9777117f1b4Smrg
9787117f1b4Smrg
9793464ebd5Sriastradh/**
9803464ebd5Sriastradh * Called via glPrimitiveRestartNV()
9813464ebd5Sriastradh */
9823464ebd5Sriastradhstatic void GLAPIENTRY
9833464ebd5Sriastradhvbo_exec_PrimitiveRestartNV(void)
9843464ebd5Sriastradh{
9853464ebd5Sriastradh   GLenum curPrim;
98601e04c3fSmrg   GET_CURRENT_CONTEXT(ctx);
9873464ebd5Sriastradh
9883464ebd5Sriastradh   curPrim = ctx->Driver.CurrentExecPrimitive;
9893464ebd5Sriastradh
9903464ebd5Sriastradh   if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
99101e04c3fSmrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV");
9923464ebd5Sriastradh   }
9933464ebd5Sriastradh   else {
9943464ebd5Sriastradh      vbo_exec_End();
9953464ebd5Sriastradh      vbo_exec_Begin(curPrim);
9963464ebd5Sriastradh   }
9973464ebd5Sriastradh}
9983464ebd5Sriastradh
9993464ebd5Sriastradh
100001e04c3fSmrgstatic void
100101e04c3fSmrgvbo_exec_vtxfmt_init(struct vbo_exec_context *exec)
10027117f1b4Smrg{
10037ec681f3Smrg   struct gl_context *ctx = gl_context_from_vbo_exec(exec);
10047117f1b4Smrg   GLvertexformat *vfmt = &exec->vtxfmt;
10057117f1b4Smrg
10067ec681f3Smrg#define NAME_AE(x) _ae_##x
10077ec681f3Smrg#define NAME_CALLLIST(x) _mesa_##x
10087ec681f3Smrg#define NAME(x) vbo_exec_##x
10097ec681f3Smrg#define NAME_ES(x) _es_##x
10107117f1b4Smrg
10117ec681f3Smrg#include "vbo_init_tmp.h"
10127117f1b4Smrg}
10137117f1b4Smrg
10147117f1b4Smrg
10157ec681f3Smrgstatic void
10167ec681f3Smrgvbo_reset_all_attr(struct vbo_exec_context *exec)
1017c1f859d4Smrg{
10187ec681f3Smrg   while (exec->vtx.enabled) {
10197ec681f3Smrg      const int i = u_bit_scan64(&exec->vtx.enabled);
1020c1f859d4Smrg
10217ec681f3Smrg      /* Reset the vertex attribute by setting its size to zero. */
10227ec681f3Smrg      exec->vtx.attr[i].size = 0;
10237ec681f3Smrg      exec->vtx.attr[i].type = GL_FLOAT;
10247ec681f3Smrg      exec->vtx.attr[i].active_size = 0;
10257ec681f3Smrg      exec->vtx.attrptr[i] = NULL;
1026af69d88dSmrg   }
1027c1f859d4Smrg
10287ec681f3Smrg   exec->vtx.vertex_size = 0;
10293464ebd5Sriastradh}
10303464ebd5Sriastradh
1031c1f859d4Smrg
103201e04c3fSmrgvoid
10337ec681f3Smrgvbo_exec_vtx_init(struct vbo_exec_context *exec, bool use_buffer_objects)
10347117f1b4Smrg{
10357ec681f3Smrg   struct gl_context *ctx = gl_context_from_vbo_exec(exec);
10367117f1b4Smrg
10377ec681f3Smrg   if (use_buffer_objects) {
10387ec681f3Smrg      /* Use buffer objects for immediate mode. */
10397ec681f3Smrg      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
10407ec681f3Smrg      exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, IMM_BUFFER_NAME);
10417ec681f3Smrg   } else {
10427ec681f3Smrg      /* Use allocated memory for immediate mode. */
10437ec681f3Smrg      exec->vtx.bufferobj = NULL;
10447ec681f3Smrg      exec->vtx.buffer_map =
10457ec681f3Smrg         align_malloc(ctx->Const.glBeginEndBufferSize, 64);
10467ec681f3Smrg      exec->vtx.buffer_ptr = exec->vtx.buffer_map;
10477ec681f3Smrg   }
10484a49301eSmrg
104901e04c3fSmrg   vbo_exec_vtxfmt_init(exec);
10507ec681f3Smrg   _mesa_noop_vtxfmt_init(ctx, &exec->vtxfmt_noop);
10517117f1b4Smrg
10527ec681f3Smrg   exec->vtx.enabled = u_bit_consecutive64(0, VBO_ATTRIB_MAX); /* reset all */
10537ec681f3Smrg   vbo_reset_all_attr(exec);
10543464ebd5Sriastradh
10557ec681f3Smrg   exec->vtx.info.instance_count = 1;
10567ec681f3Smrg   exec->vtx.info.max_index = ~0;
10577117f1b4Smrg}
10587117f1b4Smrg
10597117f1b4Smrg
106001e04c3fSmrgvoid
106101e04c3fSmrgvbo_exec_vtx_destroy(struct vbo_exec_context *exec)
10627117f1b4Smrg{
10634a49301eSmrg   /* using a real VBO for vertex data */
10647ec681f3Smrg   struct gl_context *ctx = gl_context_from_vbo_exec(exec);
10654a49301eSmrg
10664a49301eSmrg   /* True VBOs should already be unmapped
10674a49301eSmrg    */
10684a49301eSmrg   if (exec->vtx.buffer_map) {
10697ec681f3Smrg      assert(!exec->vtx.bufferobj ||
10704a49301eSmrg             exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
10717ec681f3Smrg      if (!exec->vtx.bufferobj) {
10727ec681f3Smrg         align_free(exec->vtx.buffer_map);
1073c1f859d4Smrg         exec->vtx.buffer_map = NULL;
10744a49301eSmrg         exec->vtx.buffer_ptr = NULL;
1075c1f859d4Smrg      }
10767117f1b4Smrg   }
10777117f1b4Smrg
10783464ebd5Sriastradh   /* Free the vertex buffer.  Unmap first if needed.
10794a49301eSmrg    */
10807ec681f3Smrg   if (exec->vtx.bufferobj &&
10817ec681f3Smrg       _mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
1082af69d88dSmrg      ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
10833464ebd5Sriastradh   }
10844a49301eSmrg   _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
10854a49301eSmrg}
10867117f1b4Smrg
10877117f1b4Smrg
10883464ebd5Sriastradh/**
108901e04c3fSmrg * If inside glBegin()/glEnd(), it should assert(0).  Otherwise, if
109001e04c3fSmrg * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
109101e04c3fSmrg * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
109201e04c3fSmrg * __struct gl_contextRec::Current and gl_light_attrib::Material
109301e04c3fSmrg *
109401e04c3fSmrg * Note that the default T&L engine never clears the
109501e04c3fSmrg * FLUSH_UPDATE_CURRENT bit, even after performing the update.
109601e04c3fSmrg *
10974a49301eSmrg * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
10984a49301eSmrg */
109901e04c3fSmrgvoid
110001e04c3fSmrgvbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags)
11014a49301eSmrg{
11024a49301eSmrg   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
11034a49301eSmrg
11047ec681f3Smrg#ifndef NDEBUG
11054a49301eSmrg   /* debug check: make sure we don't get called recursively */
11064a49301eSmrg   exec->flush_call_depth++;
11074a49301eSmrg   assert(exec->flush_call_depth == 1);
11084a49301eSmrg#endif
11094a49301eSmrg
1110af69d88dSmrg   if (_mesa_inside_begin_end(ctx)) {
11113464ebd5Sriastradh      /* We've had glBegin but not glEnd! */
11127ec681f3Smrg#ifndef NDEBUG
11134a49301eSmrg      exec->flush_call_depth--;
11144a49301eSmrg      assert(exec->flush_call_depth == 0);
11154a49301eSmrg#endif
11164a49301eSmrg      return;
11174a49301eSmrg   }
11187117f1b4Smrg
11197ec681f3Smrg   /* Flush (draw). */
11207ec681f3Smrg   vbo_exec_FlushVertices_internal(exec, flags);
11214a49301eSmrg
11227ec681f3Smrg#ifndef NDEBUG
11234a49301eSmrg   exec->flush_call_depth--;
11244a49301eSmrg   assert(exec->flush_call_depth == 0);
11254a49301eSmrg#endif
11267117f1b4Smrg}
11277117f1b4Smrg
11287117f1b4Smrg
11294a49301eSmrgvoid GLAPIENTRY
11303464ebd5Sriastradh_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
11314a49301eSmrg{
11327ec681f3Smrg   vbo_exec_Color4f(r, g, b, a);
11334a49301eSmrg}
11344a49301eSmrg
11354a49301eSmrg
11364a49301eSmrgvoid GLAPIENTRY
11373464ebd5Sriastradh_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
11384a49301eSmrg{
11397ec681f3Smrg   vbo_exec_Normal3f(x, y, z);
11404a49301eSmrg}
11414a49301eSmrg
11424a49301eSmrg
11434a49301eSmrgvoid GLAPIENTRY
11443464ebd5Sriastradh_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
11454a49301eSmrg{
11467ec681f3Smrg   vbo_exec_MultiTexCoord4f(target, s, t, r, q);
11474a49301eSmrg}
11484a49301eSmrg
11493464ebd5Sriastradh
11504a49301eSmrgvoid GLAPIENTRY
11513464ebd5Sriastradh_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
11524a49301eSmrg{
11537ec681f3Smrg   vbo_exec_Materialfv(face, pname, params);
11544a49301eSmrg}
11554a49301eSmrg
11564a49301eSmrg
11574a49301eSmrgvoid GLAPIENTRY
11583464ebd5Sriastradh_es_Materialf(GLenum face, GLenum pname, GLfloat param)
11593464ebd5Sriastradh{
11603464ebd5Sriastradh   GLfloat p[4];
11613464ebd5Sriastradh   p[0] = param;
11623464ebd5Sriastradh   p[1] = p[2] = p[3] = 0.0F;
11637ec681f3Smrg   vbo_exec_Materialfv(face, pname, p);
11643464ebd5Sriastradh}
11653464ebd5Sriastradh
11663464ebd5Sriastradh
11673464ebd5Sriastradh/**
11683464ebd5Sriastradh * A special version of glVertexAttrib4f that does not treat index 0 as
11693464ebd5Sriastradh * VBO_ATTRIB_POS.
11703464ebd5Sriastradh */
11713464ebd5Sriastradhstatic void
11723464ebd5SriastradhVertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
11733464ebd5Sriastradh{
11743464ebd5Sriastradh   GET_CURRENT_CONTEXT(ctx);
11753464ebd5Sriastradh   if (index < MAX_VERTEX_GENERIC_ATTRIBS)
117601e04c3fSmrg      ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
11773464ebd5Sriastradh   else
11783464ebd5Sriastradh      ERROR(GL_INVALID_VALUE);
11793464ebd5Sriastradh}
11803464ebd5Sriastradh
11813464ebd5Sriastradhvoid GLAPIENTRY
11823464ebd5Sriastradh_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
11833464ebd5Sriastradh{
11843464ebd5Sriastradh   VertexAttrib4f_nopos(index, x, y, z, w);
11853464ebd5Sriastradh}
11863464ebd5Sriastradh
11873464ebd5Sriastradh
11883464ebd5Sriastradhvoid GLAPIENTRY
11893464ebd5Sriastradh_es_VertexAttrib1f(GLuint indx, GLfloat x)
11903464ebd5Sriastradh{
11913464ebd5Sriastradh   VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
11923464ebd5Sriastradh}
11933464ebd5Sriastradh
11943464ebd5Sriastradh
11953464ebd5Sriastradhvoid GLAPIENTRY
11963464ebd5Sriastradh_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
11973464ebd5Sriastradh{
11983464ebd5Sriastradh   VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
11993464ebd5Sriastradh}
12003464ebd5Sriastradh
12013464ebd5Sriastradh
12023464ebd5Sriastradhvoid GLAPIENTRY
12033464ebd5Sriastradh_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
12043464ebd5Sriastradh{
12053464ebd5Sriastradh   VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
12063464ebd5Sriastradh}
12073464ebd5Sriastradh
12083464ebd5Sriastradh
12093464ebd5Sriastradhvoid GLAPIENTRY
12103464ebd5Sriastradh_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
12113464ebd5Sriastradh{
12123464ebd5Sriastradh   VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
12133464ebd5Sriastradh}
12143464ebd5Sriastradh
12153464ebd5Sriastradh
12163464ebd5Sriastradhvoid GLAPIENTRY
12173464ebd5Sriastradh_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
12183464ebd5Sriastradh{
12193464ebd5Sriastradh   VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
12203464ebd5Sriastradh}
12213464ebd5Sriastradh
12223464ebd5Sriastradh
12233464ebd5Sriastradhvoid GLAPIENTRY
12243464ebd5Sriastradh_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
12253464ebd5Sriastradh{
12263464ebd5Sriastradh   VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
12273464ebd5Sriastradh}
12283464ebd5Sriastradh
12293464ebd5Sriastradh
12303464ebd5Sriastradhvoid GLAPIENTRY
12313464ebd5Sriastradh_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
12324a49301eSmrg{
12333464ebd5Sriastradh   VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
12344a49301eSmrg}
1235