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