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@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/draw_validate.h"
44 #include "main/dispatch.h"
45 #include "util/bitscan.h"
46 #include "util/u_memory.h"
47 
48 #include "vbo_noop.h"
49 #include "vbo_private.h"
50 
51 
52 /** ID/name for immediate-mode VBO */
53 #define IMM_BUFFER_NAME 0xaabbccdd
54 
55 
56 static void GLAPIENTRY
57 vbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params);
58 
59 static void GLAPIENTRY
60 vbo_exec_EvalCoord1f(GLfloat u);
61 
62 static void GLAPIENTRY
63 vbo_exec_EvalCoord2f(GLfloat u, GLfloat v);
64 
65 
66 static void
67 vbo_reset_all_attr(struct vbo_exec_context *exec);
68 
69 
70 /**
71  * Close off the last primitive, execute the buffer, restart the
72  * primitive.  This is called when we fill a vertex buffer before
73  * hitting glEnd.
74  */
75 static void
vbo_exec_wrap_buffers(struct vbo_exec_context * exec)76 vbo_exec_wrap_buffers(struct vbo_exec_context *exec)
77 {
78    if (exec->vtx.prim_count == 0) {
79       exec->vtx.copied.nr = 0;
80       exec->vtx.vert_count = 0;
81       exec->vtx.buffer_ptr = exec->vtx.buffer_map;
82    }
83    else {
84       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
85       const GLuint last_begin = last_prim->begin;
86       GLuint last_count;
87 
88       if (_mesa_inside_begin_end(exec->ctx)) {
89          last_prim->count = exec->vtx.vert_count - last_prim->start;
90       }
91 
92       last_count = last_prim->count;
93 
94       /* Special handling for wrapping GL_LINE_LOOP */
95       if (last_prim->mode == GL_LINE_LOOP &&
96           last_count > 0 &&
97           !last_prim->end) {
98          /* draw this section of the incomplete line loop as a line strip */
99          last_prim->mode = GL_LINE_STRIP;
100          if (!last_prim->begin) {
101             /* This is not the first section of the line loop, so don't
102              * draw the 0th vertex.  We're saving it until we draw the
103              * very last section of the loop.
104              */
105             last_prim->start++;
106             last_prim->count--;
107          }
108       }
109 
110       /* Execute the buffer and save copied vertices.
111        */
112       if (exec->vtx.vert_count)
113          vbo_exec_vtx_flush(exec);
114       else {
115          exec->vtx.prim_count = 0;
116          exec->vtx.copied.nr = 0;
117       }
118 
119       /* Emit a glBegin to start the new list.
120        */
121       assert(exec->vtx.prim_count == 0);
122 
123       if (_mesa_inside_begin_end(exec->ctx)) {
124          exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
125          exec->vtx.prim[0].begin = 0;
126          exec->vtx.prim[0].end = 0;
127          exec->vtx.prim[0].start = 0;
128          exec->vtx.prim[0].count = 0;
129          exec->vtx.prim_count++;
130 
131          if (exec->vtx.copied.nr == last_count)
132             exec->vtx.prim[0].begin = last_begin;
133       }
134    }
135 }
136 
137 
138 /**
139  * Deal with buffer wrapping where provoked by the vertex buffer
140  * filling up, as opposed to upgrade_vertex().
141  */
142 static void
vbo_exec_vtx_wrap(struct vbo_exec_context * exec)143 vbo_exec_vtx_wrap(struct vbo_exec_context *exec)
144 {
145    unsigned numComponents;
146 
147    /* Run pipeline on current vertices, copy wrapped vertices
148     * to exec->vtx.copied.
149     */
150    vbo_exec_wrap_buffers(exec);
151 
152    if (!exec->vtx.buffer_ptr) {
153       /* probably ran out of memory earlier when allocating the VBO */
154       return;
155    }
156 
157    /* Copy stored stored vertices to start of new list.
158     */
159    assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
160 
161    numComponents = exec->vtx.copied.nr * exec->vtx.vertex_size;
162    memcpy(exec->vtx.buffer_ptr,
163           exec->vtx.copied.buffer,
164           numComponents * sizeof(fi_type));
165    exec->vtx.buffer_ptr += numComponents;
166    exec->vtx.vert_count += exec->vtx.copied.nr;
167 
168    exec->vtx.copied.nr = 0;
169 }
170 
171 
172 /**
173  * Copy the active vertex's values to the ctx->Current fields.
174  */
175 static void
vbo_exec_copy_to_current(struct vbo_exec_context * exec)176 vbo_exec_copy_to_current(struct vbo_exec_context *exec)
177 {
178    struct gl_context *ctx = exec->ctx;
179    struct vbo_context *vbo = vbo_context(ctx);
180    GLbitfield64 enabled = exec->vtx.enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS));
181 
182    while (enabled) {
183       const int i = u_bit_scan64(&enabled);
184 
185       /* Note: the exec->vtx.current[i] pointers point into the
186        * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
187        */
188       GLfloat *current = (GLfloat *)vbo->current[i].Ptr;
189       fi_type tmp[8]; /* space for doubles */
190       int dmul = 1;
191 
192       if (exec->vtx.attr[i].type == GL_DOUBLE ||
193           exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB)
194          dmul = 2;
195 
196       assert(exec->vtx.attr[i].size);
197 
198       if (exec->vtx.attr[i].type == GL_DOUBLE ||
199           exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB) {
200          memset(tmp, 0, sizeof(tmp));
201          memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attr[i].size * sizeof(GLfloat));
202       } else {
203          COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
204                                      exec->vtx.attr[i].size,
205                                      exec->vtx.attrptr[i],
206                                      exec->vtx.attr[i].type);
207       }
208 
209       if (exec->vtx.attr[i].type != vbo->current[i].Format.Type ||
210           memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
211          memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul);
212 
213          /* Given that we explicitly state size here, there is no need
214           * for the COPY_CLEAN above, could just copy 16 bytes and be
215           * done.  The only problem is when Mesa accesses ctx->Current
216           * directly.
217           */
218          /* Size here is in components - not bytes */
219          vbo_set_vertex_format(&vbo->current[i].Format,
220                                exec->vtx.attr[i].size / dmul,
221                                exec->vtx.attr[i].type);
222 
223          /* This triggers rather too much recalculation of Mesa state
224           * that doesn't get used (eg light positions).
225           */
226          if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
227              i <= VBO_ATTRIB_MAT_BACK_INDEXES)
228             ctx->NewState |= _NEW_LIGHT;
229 
230          ctx->NewState |= _NEW_CURRENT_ATTRIB;
231       }
232    }
233 
234    /* Colormaterial -- this kindof sucks.
235     */
236    if (ctx->Light.ColorMaterialEnabled &&
237        exec->vtx.attr[VBO_ATTRIB_COLOR0].size) {
238       _mesa_update_color_material(ctx,
239                                   ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
240    }
241 }
242 
243 
244 /**
245  * Flush existing data, set new attrib size, replay copied vertices.
246  * This is called when we transition from a small vertex attribute size
247  * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
248  * We need to go back over the previous 2-component texcoords and insert
249  * zero and one values.
250  * \param attr  VBO_ATTRIB_x vertex attribute value
251  */
252 static void
vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context * exec,GLuint attr,GLuint newSize,GLenum newType)253 vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
254                              GLuint attr, GLuint newSize, GLenum newType)
255 {
256    struct gl_context *ctx = exec->ctx;
257    struct vbo_context *vbo = vbo_context(ctx);
258    const GLint lastcount = exec->vtx.vert_count;
259    fi_type *old_attrptr[VBO_ATTRIB_MAX];
260    const GLuint old_vtx_size_no_pos = exec->vtx.vertex_size_no_pos;
261    const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
262    const GLuint oldSize = exec->vtx.attr[attr].size;
263    GLuint i;
264 
265    assert(attr < VBO_ATTRIB_MAX);
266 
267    /* Run pipeline on current vertices, copy wrapped vertices
268     * to exec->vtx.copied.
269     */
270    vbo_exec_wrap_buffers(exec);
271 
272    if (unlikely(exec->vtx.copied.nr)) {
273       /* We're in the middle of a primitive, keep the old vertex
274        * format around to be able to translate the copied vertices to
275        * the new format.
276        */
277       memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
278    }
279 
280    /* Heuristic: Attempt to isolate attributes received outside
281     * begin/end so that they don't bloat the vertices.
282     */
283    if (!_mesa_inside_begin_end(ctx) &&
284        !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
285       vbo_exec_copy_to_current(exec);
286       vbo_reset_all_attr(exec);
287    }
288 
289    /* Fix up sizes:
290     */
291    exec->vtx.attr[attr].size = newSize;
292    exec->vtx.attr[attr].active_size = newSize;
293    exec->vtx.attr[attr].type = newType;
294    exec->vtx.vertex_size += newSize - oldSize;
295    exec->vtx.vertex_size_no_pos = exec->vtx.vertex_size - exec->vtx.attr[0].size;
296    exec->vtx.max_vert = vbo_compute_max_verts(exec);
297    exec->vtx.vert_count = 0;
298    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
299    exec->vtx.enabled |= BITFIELD64_BIT(attr);
300 
301    if (attr != 0) {
302       if (unlikely(oldSize)) {
303          unsigned offset = exec->vtx.attrptr[attr] - exec->vtx.vertex;
304 
305          /* If there are attribs after the resized attrib... */
306          if (offset + oldSize < old_vtx_size_no_pos) {
307             int size_diff = newSize - oldSize;
308             fi_type *old_first = exec->vtx.attrptr[attr] + oldSize;
309             fi_type *new_first = exec->vtx.attrptr[attr] + newSize;
310             fi_type *old_last = exec->vtx.vertex + old_vtx_size_no_pos - 1;
311             fi_type *new_last = exec->vtx.vertex + exec->vtx.vertex_size_no_pos - 1;
312 
313             if (size_diff < 0) {
314                /* Decreasing the size: Copy from first to last to move
315                 * elements to the left.
316                 */
317                fi_type *old_end = old_last + 1;
318                fi_type *old = old_first;
319                fi_type *new = new_first;
320 
321                do {
322                   *new++ = *old++;
323                } while (old != old_end);
324             } else {
325                /* Increasing the size: Copy from last to first to move
326                 * elements to the right.
327                 */
328                fi_type *old_end = old_first - 1;
329                fi_type *old = old_last;
330                fi_type *new = new_last;
331 
332                do {
333                   *new-- = *old--;
334                } while (old != old_end);
335             }
336 
337             /* Update pointers to attribs, because we moved them. */
338             GLbitfield64 enabled = exec->vtx.enabled &
339                                    ~BITFIELD64_BIT(VBO_ATTRIB_POS) &
340                                    ~BITFIELD64_BIT(attr);
341             while (enabled) {
342                unsigned i = u_bit_scan64(&enabled);
343 
344                if (exec->vtx.attrptr[i] > exec->vtx.attrptr[attr])
345                   exec->vtx.attrptr[i] += size_diff;
346             }
347          }
348       } else {
349          /* Just have to append the new attribute at the end */
350          exec->vtx.attrptr[attr] = exec->vtx.vertex +
351            exec->vtx.vertex_size_no_pos - newSize;
352       }
353    }
354 
355    /* The position is always last. */
356    exec->vtx.attrptr[0] = exec->vtx.vertex + exec->vtx.vertex_size_no_pos;
357 
358    /* Replay stored vertices to translate them
359     * to new format here.
360     *
361     * -- No need to replay - just copy piecewise
362     */
363    if (unlikely(exec->vtx.copied.nr)) {
364       fi_type *data = exec->vtx.copied.buffer;
365       fi_type *dest = exec->vtx.buffer_ptr;
366 
367       assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
368 
369       for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
370          GLbitfield64 enabled = exec->vtx.enabled;
371          while (enabled) {
372             const int j = u_bit_scan64(&enabled);
373             GLuint sz = exec->vtx.attr[j].size;
374             GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
375             GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
376 
377             assert(sz);
378 
379             if (j == attr) {
380                if (oldSize) {
381                   fi_type tmp[4];
382                   COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
383                                               data + old_offset,
384                                               exec->vtx.attr[j].type);
385                   COPY_SZ_4V(dest + new_offset, newSize, tmp);
386                } else {
387                   fi_type *current = (fi_type *)vbo->current[j].Ptr;
388                   COPY_SZ_4V(dest + new_offset, sz, current);
389                }
390             }
391             else {
392                COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
393             }
394          }
395 
396          data += old_vtx_size;
397          dest += exec->vtx.vertex_size;
398       }
399 
400       exec->vtx.buffer_ptr = dest;
401       exec->vtx.vert_count += exec->vtx.copied.nr;
402       exec->vtx.copied.nr = 0;
403    }
404 }
405 
406 
407 /**
408  * This is when a vertex attribute transitions to a different size.
409  * For example, we saw a bunch of glTexCoord2f() calls and now we got a
410  * glTexCoord4f() call.  We promote the array from size=2 to size=4.
411  * \param newSize  size of new vertex (number of 32-bit words).
412  * \param attr  VBO_ATTRIB_x vertex attribute value
413  */
414 static void
vbo_exec_fixup_vertex(struct gl_context * ctx,GLuint attr,GLuint newSize,GLenum newType)415 vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr,
416                       GLuint newSize, GLenum newType)
417 {
418    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
419 
420    assert(attr < VBO_ATTRIB_MAX);
421 
422    if (newSize > exec->vtx.attr[attr].size ||
423        newType != exec->vtx.attr[attr].type) {
424       /* New size is larger.  Need to flush existing vertices and get
425        * an enlarged vertex format.
426        */
427       vbo_exec_wrap_upgrade_vertex(exec, attr, newSize, newType);
428    }
429    else if (newSize < exec->vtx.attr[attr].active_size) {
430       GLuint i;
431       const fi_type *id =
432             vbo_get_default_vals_as_union(exec->vtx.attr[attr].type);
433 
434       /* New size is smaller - just need to fill in some
435        * zeros.  Don't need to flush or wrap.
436        */
437       for (i = newSize; i <= exec->vtx.attr[attr].size; i++)
438          exec->vtx.attrptr[attr][i-1] = id[i-1];
439 
440       exec->vtx.attr[attr].active_size = newSize;
441    }
442 }
443 
444 
445 /**
446  * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex?
447  * It depends on a few things, including whether we're inside or outside
448  * of glBegin/glEnd.
449  */
450 static inline bool
is_vertex_position(const struct gl_context * ctx,GLuint index)451 is_vertex_position(const struct gl_context *ctx, GLuint index)
452 {
453    return (index == 0 &&
454            _mesa_attr_zero_aliases_vertex(ctx) &&
455            _mesa_inside_begin_end(ctx));
456 }
457 
458 /* Write a 64-bit value into a 32-bit pointer by preserving endianness. */
459 #if UTIL_ARCH_LITTLE_ENDIAN
460    #define SET_64BIT(dst32, u64) do { \
461          *(dst32)++ = (u64); \
462          *(dst32)++ = (uint64_t)(u64) >> 32; \
463       } while (0)
464 #else
465    #define SET_64BIT(dst32, u64) do { \
466          *(dst32)++ = (uint64_t)(u64) >> 32; \
467          *(dst32)++ = (u64); \
468       } while (0)
469 #endif
470 
471 
472 /**
473  * This macro is used to implement all the glVertex, glColor, glTexCoord,
474  * glVertexAttrib, etc functions.
475  * \param A  VBO_ATTRIB_x attribute index
476  * \param N  attribute size (1..4)
477  * \param T  type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
478  * \param C  cast type (uint32_t or uint64_t)
479  * \param V0, V1, v2, V3  attribute value
480  */
481 #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                          \
482 do {                                                                    \
483    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;             \
484    int sz = (sizeof(C) / sizeof(GLfloat));                              \
485                                                                         \
486    assert(sz == 1 || sz == 2);                                          \
487                                                                         \
488    /* store a copy of the attribute in exec except for glVertex */      \
489    if ((A) != 0) {                                                      \
490       /* Check if attribute size or type is changing. */                \
491       if (unlikely(exec->vtx.attr[A].active_size != N * sz ||           \
492                    exec->vtx.attr[A].type != T)) {                      \
493          vbo_exec_fixup_vertex(ctx, A, N * sz, T);                      \
494       }                                                                 \
495                                                                         \
496       C *dest = (C *)exec->vtx.attrptr[A];                              \
497       if (N>0) dest[0] = V0;                                            \
498       if (N>1) dest[1] = V1;                                            \
499       if (N>2) dest[2] = V2;                                            \
500       if (N>3) dest[3] = V3;                                            \
501       assert(exec->vtx.attr[A].type == T);                              \
502                                                                         \
503       /* we now have accumulated a per-vertex attribute */              \
504       ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;                    \
505    } else {                                                             \
506       /* This is a glVertex call */                                     \
507       int size = exec->vtx.attr[0].size;                                \
508                                                                         \
509       /* Check if attribute size or type is changing. */                \
510       if (unlikely(size < N * sz ||                                     \
511                    exec->vtx.attr[0].type != T)) {                      \
512          vbo_exec_wrap_upgrade_vertex(exec, 0, N * sz, T);              \
513       }                                                                 \
514                                                                         \
515       uint32_t *dst = (uint32_t *)exec->vtx.buffer_ptr;                 \
516       uint32_t *src = (uint32_t *)exec->vtx.vertex;                     \
517       unsigned vertex_size_no_pos = exec->vtx.vertex_size_no_pos;       \
518                                                                         \
519       /* Copy over attributes from exec. */                             \
520       for (unsigned i = 0; i < vertex_size_no_pos; i++)                 \
521          *dst++ = *src++;                                               \
522                                                                         \
523       /* Store the position, which is always last and can have 32 or */ \
524       /* 64 bits per channel. */                                        \
525       if (sizeof(C) == 4) {                                             \
526          if (N > 0) *dst++ = V0;                                        \
527          if (N > 1) *dst++ = V1;                                        \
528          if (N > 2) *dst++ = V2;                                        \
529          if (N > 3) *dst++ = V3;                                        \
530                                                                         \
531          if (unlikely(N < size)) {                                      \
532             if (N < 2 && size >= 2) *dst++ = V1;                        \
533             if (N < 3 && size >= 3) *dst++ = V2;                        \
534             if (N < 4 && size >= 4) *dst++ = V3;                        \
535          }                                                              \
536       } else {                                                          \
537          /* 64 bits: dst can be unaligned, so copy each 4-byte word */  \
538          /* separately */                                               \
539          if (N > 0) SET_64BIT(dst, V0);                                 \
540          if (N > 1) SET_64BIT(dst, V1);                                 \
541          if (N > 2) SET_64BIT(dst, V2);                                 \
542          if (N > 3) SET_64BIT(dst, V3);                                 \
543                                                                         \
544          if (unlikely(N * 2 < size)) {                                  \
545             if (N < 2 && size >= 4) SET_64BIT(dst, V1);                 \
546             if (N < 3 && size >= 6) SET_64BIT(dst, V2);                 \
547             if (N < 4 && size >= 8) SET_64BIT(dst, V3);                 \
548          }                                                              \
549       }                                                                 \
550                                                                         \
551       /* dst now points at the beginning of the next vertex */          \
552       exec->vtx.buffer_ptr = (fi_type*)dst;                             \
553                                                                         \
554       /* Don't set FLUSH_UPDATE_CURRENT because */                      \
555       /* Current.Attrib[VBO_ATTRIB_POS] is never used. */               \
556                                                                         \
557       if (unlikely(++exec->vtx.vert_count >= exec->vtx.max_vert))       \
558          vbo_exec_vtx_wrap(exec);                                       \
559    }                                                                    \
560 } while (0)
561 
562 
563 #undef ERROR
564 #define ERROR(err) _mesa_error(ctx, err, __func__)
565 #define TAG(x) vbo_exec_##x
566 
567 #include "vbo_attrib_tmp.h"
568 
569 
570 
571 /**
572  * Execute a glMaterial call.  Note that if GL_COLOR_MATERIAL is enabled,
573  * this may be a (partial) no-op.
574  */
575 static void GLAPIENTRY
vbo_exec_Materialfv(GLenum face,GLenum pname,const GLfloat * params)576 vbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
577 {
578    GLbitfield updateMats;
579    GET_CURRENT_CONTEXT(ctx);
580 
581    /* This function should be a no-op when it tries to update material
582     * attributes which are currently tracking glColor via glColorMaterial.
583     * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
584     * indicating which material attributes can actually be updated below.
585     */
586    if (ctx->Light.ColorMaterialEnabled) {
587       updateMats = ~ctx->Light._ColorMaterialBitmask;
588    }
589    else {
590       /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
591       updateMats = ALL_MATERIAL_BITS;
592    }
593 
594    if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
595       updateMats &= FRONT_MATERIAL_BITS;
596    }
597    else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
598       updateMats &= BACK_MATERIAL_BITS;
599    }
600    else if (face != GL_FRONT_AND_BACK) {
601       _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
602       return;
603    }
604 
605    switch (pname) {
606    case GL_EMISSION:
607       if (updateMats & MAT_BIT_FRONT_EMISSION)
608          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
609       if (updateMats & MAT_BIT_BACK_EMISSION)
610          MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
611       break;
612    case GL_AMBIENT:
613       if (updateMats & MAT_BIT_FRONT_AMBIENT)
614          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
615       if (updateMats & MAT_BIT_BACK_AMBIENT)
616          MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
617       break;
618    case GL_DIFFUSE:
619       if (updateMats & MAT_BIT_FRONT_DIFFUSE)
620          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
621       if (updateMats & MAT_BIT_BACK_DIFFUSE)
622          MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
623       break;
624    case GL_SPECULAR:
625       if (updateMats & MAT_BIT_FRONT_SPECULAR)
626          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
627       if (updateMats & MAT_BIT_BACK_SPECULAR)
628          MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
629       break;
630    case GL_SHININESS:
631       if (*params < 0 || *params > ctx->Const.MaxShininess) {
632          _mesa_error(ctx, GL_INVALID_VALUE,
633                      "glMaterial(invalid shininess: %f out range [0, %f])",
634                      *params, ctx->Const.MaxShininess);
635          return;
636       }
637       if (updateMats & MAT_BIT_FRONT_SHININESS)
638          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
639       if (updateMats & MAT_BIT_BACK_SHININESS)
640          MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
641       break;
642    case GL_COLOR_INDEXES:
643       if (ctx->API != API_OPENGL_COMPAT) {
644          _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
645          return;
646       }
647       if (updateMats & MAT_BIT_FRONT_INDEXES)
648          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
649       if (updateMats & MAT_BIT_BACK_INDEXES)
650          MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
651       break;
652    case GL_AMBIENT_AND_DIFFUSE:
653       if (updateMats & MAT_BIT_FRONT_AMBIENT)
654          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
655       if (updateMats & MAT_BIT_FRONT_DIFFUSE)
656          MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
657       if (updateMats & MAT_BIT_BACK_AMBIENT)
658          MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
659       if (updateMats & MAT_BIT_BACK_DIFFUSE)
660          MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
661       break;
662    default:
663       _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
664       return;
665    }
666 }
667 
668 
669 /**
670  * Flush (draw) vertices.
671  *
672  * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
673  */
674 static void
vbo_exec_FlushVertices_internal(struct vbo_exec_context * exec,unsigned flags)675 vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, unsigned flags)
676 {
677    struct gl_context *ctx = exec->ctx;
678 
679    if (flags & FLUSH_STORED_VERTICES) {
680       if (exec->vtx.vert_count) {
681          vbo_exec_vtx_flush(exec);
682       }
683 
684       if (exec->vtx.vertex_size) {
685          vbo_exec_copy_to_current(exec);
686          vbo_reset_all_attr(exec);
687       }
688 
689       /* All done. */
690       ctx->Driver.NeedFlush = 0;
691    } else {
692       assert(flags == FLUSH_UPDATE_CURRENT);
693 
694       /* Note that the vertex size is unchanged.
695        * (vbo_reset_all_attr isn't called)
696        */
697       vbo_exec_copy_to_current(exec);
698 
699       /* Only FLUSH_UPDATE_CURRENT is done. */
700       ctx->Driver.NeedFlush = ~FLUSH_UPDATE_CURRENT;
701    }
702 }
703 
704 
705 static void GLAPIENTRY
vbo_exec_EvalCoord1f(GLfloat u)706 vbo_exec_EvalCoord1f(GLfloat u)
707 {
708    GET_CURRENT_CONTEXT(ctx);
709    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
710 
711    {
712       GLint i;
713       if (exec->eval.recalculate_maps)
714          vbo_exec_eval_update(exec);
715 
716       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
717          if (exec->eval.map1[i].map)
718             if (exec->vtx.attr[i].active_size != exec->eval.map1[i].sz)
719                vbo_exec_fixup_vertex(ctx, i, exec->eval.map1[i].sz, GL_FLOAT);
720       }
721    }
722 
723    memcpy(exec->vtx.copied.buffer, exec->vtx.vertex,
724           exec->vtx.vertex_size * sizeof(GLfloat));
725 
726    vbo_exec_do_EvalCoord1f(exec, u);
727 
728    memcpy(exec->vtx.vertex, exec->vtx.copied.buffer,
729           exec->vtx.vertex_size * sizeof(GLfloat));
730 }
731 
732 
733 static void GLAPIENTRY
vbo_exec_EvalCoord2f(GLfloat u,GLfloat v)734 vbo_exec_EvalCoord2f(GLfloat u, GLfloat v)
735 {
736    GET_CURRENT_CONTEXT(ctx);
737    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
738 
739    {
740       GLint i;
741       if (exec->eval.recalculate_maps)
742          vbo_exec_eval_update(exec);
743 
744       for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
745          if (exec->eval.map2[i].map)
746             if (exec->vtx.attr[i].active_size != exec->eval.map2[i].sz)
747                vbo_exec_fixup_vertex(ctx, i, exec->eval.map2[i].sz, GL_FLOAT);
748       }
749 
750       if (ctx->Eval.AutoNormal)
751          if (exec->vtx.attr[VBO_ATTRIB_NORMAL].active_size != 3)
752             vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT);
753    }
754 
755    memcpy(exec->vtx.copied.buffer, exec->vtx.vertex,
756           exec->vtx.vertex_size * sizeof(GLfloat));
757 
758    vbo_exec_do_EvalCoord2f(exec, u, v);
759 
760    memcpy(exec->vtx.vertex, exec->vtx.copied.buffer,
761           exec->vtx.vertex_size * sizeof(GLfloat));
762 }
763 
764 
765 static void GLAPIENTRY
vbo_exec_EvalCoord1fv(const GLfloat * u)766 vbo_exec_EvalCoord1fv(const GLfloat *u)
767 {
768    vbo_exec_EvalCoord1f(u[0]);
769 }
770 
771 
772 static void GLAPIENTRY
vbo_exec_EvalCoord2fv(const GLfloat * u)773 vbo_exec_EvalCoord2fv(const GLfloat *u)
774 {
775    vbo_exec_EvalCoord2f(u[0], u[1]);
776 }
777 
778 
779 static void GLAPIENTRY
vbo_exec_EvalPoint1(GLint i)780 vbo_exec_EvalPoint1(GLint i)
781 {
782    GET_CURRENT_CONTEXT(ctx);
783    GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
784                  (GLfloat) ctx->Eval.MapGrid1un);
785    GLfloat u = i * du + ctx->Eval.MapGrid1u1;
786 
787    vbo_exec_EvalCoord1f(u);
788 }
789 
790 
791 static void GLAPIENTRY
vbo_exec_EvalPoint2(GLint i,GLint j)792 vbo_exec_EvalPoint2(GLint i, GLint j)
793 {
794    GET_CURRENT_CONTEXT(ctx);
795    GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
796                  (GLfloat) ctx->Eval.MapGrid2un);
797    GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
798                  (GLfloat) ctx->Eval.MapGrid2vn);
799    GLfloat u = i * du + ctx->Eval.MapGrid2u1;
800    GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
801 
802    vbo_exec_EvalCoord2f(u, v);
803 }
804 
805 
806 /**
807  * Called via glBegin.
808  */
809 static void GLAPIENTRY
vbo_exec_Begin(GLenum mode)810 vbo_exec_Begin(GLenum mode)
811 {
812    GET_CURRENT_CONTEXT(ctx);
813    struct vbo_context *vbo = vbo_context(ctx);
814    struct vbo_exec_context *exec = &vbo->exec;
815    int i;
816 
817    if (_mesa_inside_begin_end(ctx)) {
818       _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
819       return;
820    }
821 
822    if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
823       return;
824    }
825 
826    if (!_mesa_valid_to_render(ctx, "glBegin")) {
827       return;
828    }
829 
830    /* Heuristic: attempt to isolate attributes occurring outside
831     * begin/end pairs.
832     *
833     * Use FLUSH_STORED_VERTICES, because it updates current attribs and
834     * sets vertex_size to 0. (FLUSH_UPDATE_CURRENT doesn't change vertex_size)
835     */
836    if (exec->vtx.vertex_size && !exec->vtx.attr[VBO_ATTRIB_POS].size)
837       vbo_exec_FlushVertices_internal(exec, FLUSH_STORED_VERTICES);
838 
839    i = exec->vtx.prim_count++;
840    exec->vtx.prim[i].mode = mode;
841    exec->vtx.prim[i].begin = 1;
842    exec->vtx.prim[i].end = 0;
843    exec->vtx.prim[i].start = exec->vtx.vert_count;
844    exec->vtx.prim[i].count = 0;
845 
846    ctx->Driver.CurrentExecPrimitive = mode;
847 
848    ctx->Exec = ctx->BeginEnd;
849 
850    /* We may have been called from a display list, in which case we should
851     * leave dlist.c's dispatch table in place.
852     */
853    if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
854       ctx->CurrentServerDispatch = ctx->Exec;
855    } else if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) {
856       ctx->CurrentClientDispatch = ctx->Exec;
857       _glapi_set_dispatch(ctx->CurrentClientDispatch);
858    } else {
859       assert(ctx->CurrentClientDispatch == ctx->Save);
860    }
861 }
862 
863 
864 /**
865  * Try to merge / concatenate the two most recent VBO primitives.
866  */
867 static void
try_vbo_merge(struct vbo_exec_context * exec)868 try_vbo_merge(struct vbo_exec_context *exec)
869 {
870    struct _mesa_prim *cur =  &exec->vtx.prim[exec->vtx.prim_count - 1];
871 
872    assert(exec->vtx.prim_count >= 1);
873 
874    vbo_try_prim_conversion(cur);
875 
876    if (exec->vtx.prim_count >= 2) {
877       struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
878       assert(prev == cur - 1);
879 
880       if (vbo_merge_draws(exec->ctx, false, prev, cur))
881          exec->vtx.prim_count--;  /* drop the last primitive */
882    }
883 }
884 
885 
886 /**
887  * Called via glEnd.
888  */
889 static void GLAPIENTRY
vbo_exec_End(void)890 vbo_exec_End(void)
891 {
892    GET_CURRENT_CONTEXT(ctx);
893    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
894 
895    if (!_mesa_inside_begin_end(ctx)) {
896       _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
897       return;
898    }
899 
900    ctx->Exec = ctx->OutsideBeginEnd;
901 
902    if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
903       ctx->CurrentServerDispatch = ctx->Exec;
904    } else if (ctx->CurrentClientDispatch == ctx->BeginEnd) {
905       ctx->CurrentClientDispatch = ctx->Exec;
906       _glapi_set_dispatch(ctx->CurrentClientDispatch);
907    }
908 
909    if (exec->vtx.prim_count > 0) {
910       /* close off current primitive */
911       struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
912       unsigned count = exec->vtx.vert_count - last_prim->start;
913 
914       last_prim->end = 1;
915       last_prim->count = count;
916 
917       if (count)
918          ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
919 
920       /* Special handling for GL_LINE_LOOP */
921       if (last_prim->mode == GL_LINE_LOOP && last_prim->begin == 0) {
922          /* We're finishing drawing a line loop.  Append 0th vertex onto
923           * end of vertex buffer so we can draw it as a line strip.
924           */
925          const fi_type *src = exec->vtx.buffer_map +
926             last_prim->start * exec->vtx.vertex_size;
927          fi_type *dst = exec->vtx.buffer_map +
928             exec->vtx.vert_count * exec->vtx.vertex_size;
929 
930          /* copy 0th vertex to end of buffer */
931          memcpy(dst, src, exec->vtx.vertex_size * sizeof(fi_type));
932 
933          last_prim->start++;  /* skip vertex0 */
934          /* note that last_prim->count stays unchanged */
935          last_prim->mode = GL_LINE_STRIP;
936 
937          /* Increment the vertex count so the next primitive doesn't
938           * overwrite the last vertex which we just added.
939           */
940          exec->vtx.vert_count++;
941          exec->vtx.buffer_ptr += exec->vtx.vertex_size;
942       }
943 
944       try_vbo_merge(exec);
945    }
946 
947    ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
948 
949    if (exec->vtx.prim_count == VBO_MAX_PRIM)
950       vbo_exec_vtx_flush(exec);
951 
952    if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
953       _mesa_flush(ctx);
954    }
955 }
956 
957 
958 /**
959  * Called via glPrimitiveRestartNV()
960  */
961 static void GLAPIENTRY
vbo_exec_PrimitiveRestartNV(void)962 vbo_exec_PrimitiveRestartNV(void)
963 {
964    GLenum curPrim;
965    GET_CURRENT_CONTEXT(ctx);
966 
967    curPrim = ctx->Driver.CurrentExecPrimitive;
968 
969    if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
970       _mesa_error(ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV");
971    }
972    else {
973       vbo_exec_End();
974       vbo_exec_Begin(curPrim);
975    }
976 }
977 
978 
979 static void
vbo_exec_vtxfmt_init(struct vbo_exec_context * exec)980 vbo_exec_vtxfmt_init(struct vbo_exec_context *exec)
981 {
982    struct gl_context *ctx = exec->ctx;
983    GLvertexformat *vfmt = &exec->vtxfmt;
984 
985 #define NAME_AE(x) _ae_##x
986 #define NAME_CALLLIST(x) _mesa_##x
987 #define NAME(x) vbo_exec_##x
988 #define NAME_ES(x) _es_##x
989 
990 #include "vbo_init_tmp.h"
991 }
992 
993 
994 static void
vbo_reset_all_attr(struct vbo_exec_context * exec)995 vbo_reset_all_attr(struct vbo_exec_context *exec)
996 {
997    while (exec->vtx.enabled) {
998       const int i = u_bit_scan64(&exec->vtx.enabled);
999 
1000       /* Reset the vertex attribute by setting its size to zero. */
1001       exec->vtx.attr[i].size = 0;
1002       exec->vtx.attr[i].type = GL_FLOAT;
1003       exec->vtx.attr[i].active_size = 0;
1004       exec->vtx.attrptr[i] = NULL;
1005    }
1006 
1007    exec->vtx.vertex_size = 0;
1008 }
1009 
1010 
1011 void
vbo_exec_vtx_init(struct vbo_exec_context * exec,bool use_buffer_objects)1012 vbo_exec_vtx_init(struct vbo_exec_context *exec, bool use_buffer_objects)
1013 {
1014    struct gl_context *ctx = exec->ctx;
1015 
1016    if (use_buffer_objects) {
1017       /* Use buffer objects for immediate mode. */
1018       struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1019 
1020       exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, IMM_BUFFER_NAME);
1021 
1022       /* Map the buffer. */
1023       vbo_exec_vtx_map(exec);
1024       assert(exec->vtx.buffer_ptr);
1025    } else {
1026       /* Use allocated memory for immediate mode. */
1027       exec->vtx.bufferobj = NULL;
1028       exec->vtx.buffer_map =
1029          align_malloc(ctx->Const.glBeginEndBufferSize, 64);
1030       exec->vtx.buffer_ptr = exec->vtx.buffer_map;
1031    }
1032 
1033    vbo_exec_vtxfmt_init(exec);
1034    _mesa_noop_vtxfmt_init(ctx, &exec->vtxfmt_noop);
1035 
1036    exec->vtx.enabled = u_bit_consecutive64(0, VBO_ATTRIB_MAX); /* reset all */
1037    vbo_reset_all_attr(exec);
1038 }
1039 
1040 
1041 void
vbo_exec_vtx_destroy(struct vbo_exec_context * exec)1042 vbo_exec_vtx_destroy(struct vbo_exec_context *exec)
1043 {
1044    /* using a real VBO for vertex data */
1045    struct gl_context *ctx = exec->ctx;
1046 
1047    /* True VBOs should already be unmapped
1048     */
1049    if (exec->vtx.buffer_map) {
1050       assert(!exec->vtx.bufferobj ||
1051              exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
1052       if (!exec->vtx.bufferobj) {
1053          align_free(exec->vtx.buffer_map);
1054          exec->vtx.buffer_map = NULL;
1055          exec->vtx.buffer_ptr = NULL;
1056       }
1057    }
1058 
1059    /* Free the vertex buffer.  Unmap first if needed.
1060     */
1061    if (exec->vtx.bufferobj &&
1062        _mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
1063       ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
1064    }
1065    _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
1066 }
1067 
1068 
1069 /**
1070  * If inside glBegin()/glEnd(), it should assert(0).  Otherwise, if
1071  * FLUSH_STORED_VERTICES bit in \p flags is set flushes any buffered
1072  * vertices, if FLUSH_UPDATE_CURRENT bit is set updates
1073  * __struct gl_contextRec::Current and gl_light_attrib::Material
1074  *
1075  * Note that the default T&L engine never clears the
1076  * FLUSH_UPDATE_CURRENT bit, even after performing the update.
1077  *
1078  * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
1079  */
1080 void
vbo_exec_FlushVertices(struct gl_context * ctx,GLuint flags)1081 vbo_exec_FlushVertices(struct gl_context *ctx, GLuint flags)
1082 {
1083    struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
1084 
1085 #ifndef NDEBUG
1086    /* debug check: make sure we don't get called recursively */
1087    exec->flush_call_depth++;
1088    assert(exec->flush_call_depth == 1);
1089 #endif
1090 
1091    if (_mesa_inside_begin_end(ctx)) {
1092       /* We've had glBegin but not glEnd! */
1093 #ifndef NDEBUG
1094       exec->flush_call_depth--;
1095       assert(exec->flush_call_depth == 0);
1096 #endif
1097       return;
1098    }
1099 
1100    /* Flush (draw). */
1101    vbo_exec_FlushVertices_internal(exec, flags);
1102 
1103 #ifndef NDEBUG
1104    exec->flush_call_depth--;
1105    assert(exec->flush_call_depth == 0);
1106 #endif
1107 }
1108 
1109 
1110 void GLAPIENTRY
_es_Color4f(GLfloat r,GLfloat g,GLfloat b,GLfloat a)1111 _es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1112 {
1113    vbo_exec_Color4f(r, g, b, a);
1114 }
1115 
1116 
1117 void GLAPIENTRY
_es_Normal3f(GLfloat x,GLfloat y,GLfloat z)1118 _es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1119 {
1120    vbo_exec_Normal3f(x, y, z);
1121 }
1122 
1123 
1124 void GLAPIENTRY
_es_MultiTexCoord4f(GLenum target,GLfloat s,GLfloat t,GLfloat r,GLfloat q)1125 _es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1126 {
1127    vbo_exec_MultiTexCoord4f(target, s, t, r, q);
1128 }
1129 
1130 
1131 void GLAPIENTRY
_es_Materialfv(GLenum face,GLenum pname,const GLfloat * params)1132 _es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1133 {
1134    vbo_exec_Materialfv(face, pname, params);
1135 }
1136 
1137 
1138 void GLAPIENTRY
_es_Materialf(GLenum face,GLenum pname,GLfloat param)1139 _es_Materialf(GLenum face, GLenum pname, GLfloat param)
1140 {
1141    GLfloat p[4];
1142    p[0] = param;
1143    p[1] = p[2] = p[3] = 0.0F;
1144    vbo_exec_Materialfv(face, pname, p);
1145 }
1146 
1147 
1148 /**
1149  * A special version of glVertexAttrib4f that does not treat index 0 as
1150  * VBO_ATTRIB_POS.
1151  */
1152 static void
VertexAttrib4f_nopos(GLuint index,GLfloat x,GLfloat y,GLfloat z,GLfloat w)1153 VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1154 {
1155    GET_CURRENT_CONTEXT(ctx);
1156    if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1157       ATTRF(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1158    else
1159       ERROR(GL_INVALID_VALUE);
1160 }
1161 
1162 void GLAPIENTRY
_es_VertexAttrib4f(GLuint index,GLfloat x,GLfloat y,GLfloat z,GLfloat w)1163 _es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1164 {
1165    VertexAttrib4f_nopos(index, x, y, z, w);
1166 }
1167 
1168 
1169 void GLAPIENTRY
_es_VertexAttrib1f(GLuint indx,GLfloat x)1170 _es_VertexAttrib1f(GLuint indx, GLfloat x)
1171 {
1172    VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1173 }
1174 
1175 
1176 void GLAPIENTRY
_es_VertexAttrib1fv(GLuint indx,const GLfloat * values)1177 _es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1178 {
1179    VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1180 }
1181 
1182 
1183 void GLAPIENTRY
_es_VertexAttrib2f(GLuint indx,GLfloat x,GLfloat y)1184 _es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1185 {
1186    VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1187 }
1188 
1189 
1190 void GLAPIENTRY
_es_VertexAttrib2fv(GLuint indx,const GLfloat * values)1191 _es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1192 {
1193    VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1194 }
1195 
1196 
1197 void GLAPIENTRY
_es_VertexAttrib3f(GLuint indx,GLfloat x,GLfloat y,GLfloat z)1198 _es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1199 {
1200    VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1201 }
1202 
1203 
1204 void GLAPIENTRY
_es_VertexAttrib3fv(GLuint indx,const GLfloat * values)1205 _es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1206 {
1207    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1208 }
1209 
1210 
1211 void GLAPIENTRY
_es_VertexAttrib4fv(GLuint indx,const GLfloat * values)1212 _es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1213 {
1214    VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1215 }
1216