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