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