vbo_exec_api.c revision 4e9c8166b064de4eed38e385880cd491e6d8d9c4
1/**************************************************************************
2
3Copyright 2002 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/context.h"
35#include "main/macros.h"
36#include "main/vtxfmt.h"
37#include "main/dlist.h"
38#include "main/state.h"
39#include "main/light.h"
40#include "main/api_arrayelt.h"
41#include "main/api_noop.h"
42#include "glapi/dispatch.h"
43
44#include "vbo_context.h"
45
46#ifdef ERROR
47#undef ERROR
48#endif
49
50
51static void reset_attrfv( struct vbo_exec_context *exec );
52
53
54/* Close off the last primitive, execute the buffer, restart the
55 * primitive.
56 */
57static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
58{
59   if (exec->vtx.prim_count == 0) {
60      exec->vtx.copied.nr = 0;
61      exec->vtx.vert_count = 0;
62      exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
63   }
64   else {
65      GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
66      GLuint last_count;
67
68      if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
69	 GLint i = exec->vtx.prim_count - 1;
70	 assert(i >= 0);
71	 exec->vtx.prim[i].count = (exec->vtx.vert_count -
72				    exec->vtx.prim[i].start);
73      }
74
75      last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
76
77      /* Execute the buffer and save copied vertices.
78       */
79      if (exec->vtx.vert_count)
80	 vbo_exec_vtx_flush( exec );
81      else {
82	 exec->vtx.prim_count = 0;
83	 exec->vtx.copied.nr = 0;
84      }
85
86      /* Emit a glBegin to start the new list.
87       */
88      assert(exec->vtx.prim_count == 0);
89
90      if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
91	 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
92	 exec->vtx.prim[0].start = 0;
93	 exec->vtx.prim[0].count = 0;
94	 exec->vtx.prim_count++;
95
96	 if (exec->vtx.copied.nr == last_count)
97	    exec->vtx.prim[0].begin = last_begin;
98      }
99   }
100}
101
102
103/* Deal with buffer wrapping where provoked by the vertex buffer
104 * filling up, as opposed to upgrade_vertex().
105 */
106void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
107{
108   GLfloat *data = exec->vtx.copied.buffer;
109   GLuint i;
110
111   /* Run pipeline on current vertices, copy wrapped vertices
112    * to exec->vtx.copied.
113    */
114   vbo_exec_wrap_buffers( exec );
115
116   /* Copy stored stored vertices to start of new list.
117    */
118   assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
119
120   for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
121      _mesa_memcpy( exec->vtx.vbptr, data,
122		    exec->vtx.vertex_size * sizeof(GLfloat));
123      exec->vtx.vbptr += exec->vtx.vertex_size;
124      data += exec->vtx.vertex_size;
125      exec->vtx.vert_count++;
126   }
127
128   exec->vtx.copied.nr = 0;
129}
130
131
132/*
133 * Copy the active vertex's values to the ctx->Current fields.
134 */
135static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
136{
137   GLcontext *ctx = exec->ctx;
138   struct vbo_context *vbo = vbo_context(ctx);
139   GLuint i;
140
141   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
142      if (exec->vtx.attrsz[i]) {
143	 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
144
145         /* Note: the exec->vtx.current[i] pointers point into the
146          * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
147          */
148	 COPY_CLEAN_4V(current,
149		       exec->vtx.attrsz[i],
150		       exec->vtx.attrptr[i]);
151
152
153	 /* Given that we explicitly state size here, there is no need
154	  * for the COPY_CLEAN above, could just copy 16 bytes and be
155	  * done.  The only problem is when Mesa accesses ctx->Current
156	  * directly.
157	  */
158	 vbo->currval[i].Size = exec->vtx.attrsz[i];
159
160	 /* This triggers rather too much recalculation of Mesa state
161	  * that doesn't get used (eg light positions).
162	  */
163	 if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
164	     i <= VBO_ATTRIB_MAT_BACK_INDEXES)
165	    ctx->NewState |= _NEW_LIGHT;
166      }
167   }
168
169   /* Colormaterial -- this kindof sucks.
170    */
171   if (ctx->Light.ColorMaterialEnabled &&
172       exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
173      _mesa_update_color_material(ctx,
174				  ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
175   }
176
177   ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
178}
179
180
181static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
182{
183   GLcontext *ctx = exec->ctx;
184   struct vbo_context *vbo = vbo_context(ctx);
185   GLint i;
186
187   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
188      const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
189      switch (exec->vtx.attrsz[i]) {
190      case 4: exec->vtx.attrptr[i][3] = current[3];
191      case 3: exec->vtx.attrptr[i][2] = current[2];
192      case 2: exec->vtx.attrptr[i][1] = current[1];
193      case 1: exec->vtx.attrptr[i][0] = current[0];
194	 break;
195      }
196   }
197
198   ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
199}
200
201
202/* Flush existing data, set new attrib size, replay copied vertices.
203 */
204static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
205					  GLuint attr,
206					  GLuint newsz )
207{
208   GLcontext *ctx = exec->ctx;
209   struct vbo_context *vbo = vbo_context(ctx);
210   GLint lastcount = exec->vtx.vert_count;
211   GLfloat *tmp;
212   GLuint oldsz;
213   GLuint i;
214
215   /* Run pipeline on current vertices, copy wrapped vertices
216    * to exec->vtx.copied.
217    */
218   vbo_exec_wrap_buffers( exec );
219
220
221   /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
222    * when the attribute already exists in the vertex and is having
223    * its size increased.
224    */
225   vbo_exec_copy_to_current( exec );
226
227
228   /* Heuristic: Attempt to isolate attributes received outside
229    * begin/end so that they don't bloat the vertices.
230    */
231   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
232       exec->vtx.attrsz[attr] == 0 &&
233       lastcount > 8 &&
234       exec->vtx.vertex_size) {
235      reset_attrfv( exec );
236   }
237
238   /* Fix up sizes:
239    */
240   oldsz = exec->vtx.attrsz[attr];
241   exec->vtx.attrsz[attr] = newsz;
242
243   exec->vtx.vertex_size += newsz - oldsz;
244   exec->vtx.max_vert = VBO_VERT_BUFFER_SIZE / exec->vtx.vertex_size;
245   exec->vtx.vert_count = 0;
246   exec->vtx.vbptr = (GLfloat *)exec->vtx.buffer_map;
247
248
249   /* Recalculate all the attrptr[] values
250    */
251   for (i = 0, tmp = exec->vtx.vertex ; i < VBO_ATTRIB_MAX ; i++) {
252      if (exec->vtx.attrsz[i]) {
253	 exec->vtx.attrptr[i] = tmp;
254	 tmp += exec->vtx.attrsz[i];
255      }
256      else
257	 exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
258   }
259
260   /* Copy from current to repopulate the vertex with correct values.
261    */
262   vbo_exec_copy_from_current( exec );
263
264   /* Replay stored vertices to translate them
265    * to new format here.
266    *
267    * -- No need to replay - just copy piecewise
268    */
269   if (exec->vtx.copied.nr)
270   {
271      GLfloat *data = exec->vtx.copied.buffer;
272      GLfloat *dest = exec->vtx.vbptr;
273      GLuint j;
274
275      assert(exec->vtx.vbptr == (GLfloat *)exec->vtx.buffer_map);
276
277      for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
278	 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
279	    if (exec->vtx.attrsz[j]) {
280	       if (j == attr) {
281		  if (oldsz) {
282		     COPY_CLEAN_4V( dest, oldsz, data );
283		     data += oldsz;
284		     dest += newsz;
285		  } else {
286		     const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr;
287		     COPY_SZ_4V( dest, newsz, current );
288		     dest += newsz;
289		  }
290	       }
291	       else {
292		  GLuint sz = exec->vtx.attrsz[j];
293		  COPY_SZ_4V( dest, sz, data );
294		  dest += sz;
295		  data += sz;
296	       }
297	    }
298	 }
299      }
300
301      exec->vtx.vbptr = dest;
302      exec->vtx.vert_count += exec->vtx.copied.nr;
303      exec->vtx.copied.nr = 0;
304   }
305}
306
307
308static void vbo_exec_fixup_vertex( GLcontext *ctx,
309				   GLuint attr, GLuint sz )
310{
311   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
312   int i;
313
314   if (sz > exec->vtx.attrsz[attr]) {
315      /* New size is larger.  Need to flush existing vertices and get
316       * an enlarged vertex format.
317       */
318      vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
319   }
320   else if (sz < exec->vtx.active_sz[attr]) {
321      static const GLfloat id[4] = { 0, 0, 0, 1 };
322
323      /* New size is smaller - just need to fill in some
324       * zeros.  Don't need to flush or wrap.
325       */
326      for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
327	 exec->vtx.attrptr[attr][i-1] = id[i-1];
328   }
329
330   exec->vtx.active_sz[attr] = sz;
331
332   /* Does setting NeedFlush belong here?  Necessitates resetting
333    * vtxfmt on each flush (otherwise flags won't get reset
334    * afterwards).
335    */
336   if (attr == 0)
337      exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
338   else
339      exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
340}
341
342
343
344
345/*
346 */
347#define ATTR( A, N, V0, V1, V2, V3 )				\
348do {								\
349   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;	\
350								\
351   if (exec->vtx.active_sz[A] != N)				\
352      vbo_exec_fixup_vertex(ctx, A, N);			\
353								\
354   {								\
355      GLfloat *dest = exec->vtx.attrptr[A];			\
356      if (N>0) dest[0] = V0;					\
357      if (N>1) dest[1] = V1;					\
358      if (N>2) dest[2] = V2;					\
359      if (N>3) dest[3] = V3;					\
360   }								\
361								\
362   if ((A) == 0) {						\
363      GLuint i;							\
364								\
365      for (i = 0; i < exec->vtx.vertex_size; i++)		\
366	 exec->vtx.vbptr[i] = exec->vtx.vertex[i];		\
367								\
368      exec->vtx.vbptr += exec->vtx.vertex_size;			\
369      exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;	\
370								\
371      if (++exec->vtx.vert_count >= exec->vtx.max_vert)		\
372	 vbo_exec_vtx_wrap( exec );				\
373   }								\
374} while (0)
375
376
377#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
378#define TAG(x) vbo_##x
379
380#include "vbo_attrib_tmp.h"
381
382
383
384
385
386/* Eval
387 */
388static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
389{
390   GET_CURRENT_CONTEXT( ctx );
391   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
392
393   {
394      GLint i;
395      if (exec->eval.recalculate_maps)
396	 vbo_exec_eval_update( exec );
397
398      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
399	 if (exec->eval.map1[i].map)
400	    if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
401	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
402      }
403   }
404
405
406   _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
407                 exec->vtx.vertex_size * sizeof(GLfloat));
408
409   vbo_exec_do_EvalCoord1f( exec, u );
410
411   _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
412                 exec->vtx.vertex_size * sizeof(GLfloat));
413}
414
415static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
416{
417   GET_CURRENT_CONTEXT( ctx );
418   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
419
420   {
421      GLint i;
422      if (exec->eval.recalculate_maps)
423	 vbo_exec_eval_update( exec );
424
425      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
426	 if (exec->eval.map2[i].map)
427	    if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
428	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
429      }
430
431      if (ctx->Eval.AutoNormal)
432	 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
433	    vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
434   }
435
436   _mesa_memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
437                 exec->vtx.vertex_size * sizeof(GLfloat));
438
439   vbo_exec_do_EvalCoord2f( exec, u, v );
440
441   _mesa_memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
442                 exec->vtx.vertex_size * sizeof(GLfloat));
443}
444
445static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
446{
447   vbo_exec_EvalCoord1f( u[0] );
448}
449
450static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
451{
452   vbo_exec_EvalCoord2f( u[0], u[1] );
453}
454
455static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
456{
457   GET_CURRENT_CONTEXT( ctx );
458   GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
459		 (GLfloat) ctx->Eval.MapGrid1un);
460   GLfloat u = i * du + ctx->Eval.MapGrid1u1;
461
462   vbo_exec_EvalCoord1f( u );
463}
464
465
466static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
467{
468   GET_CURRENT_CONTEXT( ctx );
469   GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
470		 (GLfloat) ctx->Eval.MapGrid2un);
471   GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
472		 (GLfloat) ctx->Eval.MapGrid2vn);
473   GLfloat u = i * du + ctx->Eval.MapGrid2u1;
474   GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
475
476   vbo_exec_EvalCoord2f( u, v );
477}
478
479
480/**
481 * Check if programs/shaders are enabled and valid at glBegin time.
482 */
483GLboolean
484vbo_validate_shaders(GLcontext *ctx)
485{
486   if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
487       (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
488      return GL_FALSE;
489   }
490   if (ctx->Shader.CurrentProgram && !ctx->Shader.CurrentProgram->LinkStatus) {
491      return GL_FALSE;
492   }
493   return GL_TRUE;
494}
495
496
497/* Build a list of primitives on the fly.  Keep
498 * ctx->Driver.CurrentExecPrimitive uptodate as well.
499 */
500static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
501{
502   GET_CURRENT_CONTEXT( ctx );
503
504   if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
505      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
506      int i;
507
508      if (ctx->NewState) {
509	 _mesa_update_state( ctx );
510
511	 CALL_Begin(ctx->Exec, (mode));
512	 return;
513      }
514
515      if (!vbo_validate_shaders(ctx)) {
516         _mesa_error(ctx, GL_INVALID_OPERATION,
517                     "glBegin (invalid vertex/fragment program)");
518         return;
519      }
520
521      /* Heuristic: attempt to isolate attributes occuring outside
522       * begin/end pairs.
523       */
524      if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
525	 vbo_exec_FlushVertices( ctx, ~0 );
526
527      i = exec->vtx.prim_count++;
528      exec->vtx.prim[i].mode = mode;
529      exec->vtx.prim[i].begin = 1;
530      exec->vtx.prim[i].end = 0;
531      exec->vtx.prim[i].indexed = 0;
532      exec->vtx.prim[i].weak = 0;
533      exec->vtx.prim[i].pad = 0;
534      exec->vtx.prim[i].start = exec->vtx.vert_count;
535      exec->vtx.prim[i].count = 0;
536
537      ctx->Driver.CurrentExecPrimitive = mode;
538   }
539   else
540      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
541
542}
543
544static void GLAPIENTRY vbo_exec_End( void )
545{
546   GET_CURRENT_CONTEXT( ctx );
547
548   if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
549      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
550      int idx = exec->vtx.vert_count;
551      int i = exec->vtx.prim_count - 1;
552
553      exec->vtx.prim[i].end = 1;
554      exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
555
556      ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
557
558      if (exec->vtx.prim_count == VBO_MAX_PRIM)
559	 vbo_exec_vtx_flush( exec );
560   }
561   else
562      _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
563}
564
565
566static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
567{
568   GLvertexformat *vfmt = &exec->vtxfmt;
569
570   vfmt->ArrayElement = _ae_loopback_array_elt;	        /* generic helper */
571   vfmt->Begin = vbo_exec_Begin;
572   vfmt->CallList = _mesa_CallList;
573   vfmt->CallLists = _mesa_CallLists;
574   vfmt->End = vbo_exec_End;
575   vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
576   vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
577   vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
578   vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
579   vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
580   vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
581
582   vfmt->Rectf = _mesa_noop_Rectf;
583   vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
584   vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
585
586
587   /* from attrib_tmp.h:
588    */
589   vfmt->Color3f = vbo_Color3f;
590   vfmt->Color3fv = vbo_Color3fv;
591   vfmt->Color4f = vbo_Color4f;
592   vfmt->Color4fv = vbo_Color4fv;
593   vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
594   vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
595   vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
596   vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
597   vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
598   vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
599   vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
600   vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
601   vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
602   vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
603   vfmt->Normal3f = vbo_Normal3f;
604   vfmt->Normal3fv = vbo_Normal3fv;
605   vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
606   vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
607   vfmt->TexCoord1f = vbo_TexCoord1f;
608   vfmt->TexCoord1fv = vbo_TexCoord1fv;
609   vfmt->TexCoord2f = vbo_TexCoord2f;
610   vfmt->TexCoord2fv = vbo_TexCoord2fv;
611   vfmt->TexCoord3f = vbo_TexCoord3f;
612   vfmt->TexCoord3fv = vbo_TexCoord3fv;
613   vfmt->TexCoord4f = vbo_TexCoord4f;
614   vfmt->TexCoord4fv = vbo_TexCoord4fv;
615   vfmt->Vertex2f = vbo_Vertex2f;
616   vfmt->Vertex2fv = vbo_Vertex2fv;
617   vfmt->Vertex3f = vbo_Vertex3f;
618   vfmt->Vertex3fv = vbo_Vertex3fv;
619   vfmt->Vertex4f = vbo_Vertex4f;
620   vfmt->Vertex4fv = vbo_Vertex4fv;
621
622   vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
623   vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
624   vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
625   vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
626   vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
627   vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
628   vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
629   vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
630
631   vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
632   vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
633   vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
634   vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
635   vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
636   vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
637   vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
638   vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
639
640   vfmt->Materialfv = vbo_Materialfv;
641
642   vfmt->EdgeFlag = vbo_EdgeFlag;
643   vfmt->Indexf = vbo_Indexf;
644   vfmt->Indexfv = vbo_Indexfv;
645
646}
647
648
649void vbo_exec_vtx_init( struct vbo_exec_context *exec )
650{
651   GLcontext *ctx = exec->ctx;
652   struct vbo_context *vbo = vbo_context(ctx);
653   GLuint i;
654
655   /* Allocate a buffer object.  Will just reuse this object
656    * continuously.
657    */
658   exec->vtx.bufferobj = ctx->Array.NullBufferObj;
659   exec->vtx.buffer_map = ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE * sizeof(GLfloat), 64);
660
661   vbo_exec_vtxfmt_init( exec );
662
663   /* Hook our functions into the dispatch table.
664    */
665   _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
666
667   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
668      exec->vtx.attrsz[i] = 0;
669      exec->vtx.active_sz[i] = 0;
670      exec->vtx.inputs[i] = &exec->vtx.arrays[i];
671   }
672
673   {
674      struct gl_client_array *arrays = exec->vtx.arrays;
675      memcpy(arrays,      vbo->legacy_currval,  16 * sizeof(arrays[0]));
676      memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
677   }
678
679   exec->vtx.vertex_size = 0;
680}
681
682
683void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
684{
685   if (exec->vtx.buffer_map) {
686      ALIGN_FREE(exec->vtx.buffer_map);
687      exec->vtx.buffer_map = NULL;
688   }
689}
690
691
692void vbo_exec_FlushVertices( GLcontext *ctx, GLuint flags )
693{
694   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
695
696   if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
697      return;
698
699   if (exec->vtx.vert_count) {
700      vbo_exec_vtx_flush( exec );
701   }
702
703   if (exec->vtx.vertex_size) {
704      vbo_exec_copy_to_current( exec );
705      reset_attrfv( exec );
706   }
707
708   exec->ctx->Driver.NeedFlush = 0;
709}
710
711
712static void reset_attrfv( struct vbo_exec_context *exec )
713{
714   GLuint i;
715
716   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
717      exec->vtx.attrsz[i] = 0;
718      exec->vtx.active_sz[i] = 0;
719   }
720
721   exec->vtx.vertex_size = 0;
722}
723
724