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