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