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