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