vbo_exec_api.c revision 3464ebd5
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/mfeatures.h"
38#include "main/vtxfmt.h"
39#include "main/dlist.h"
40#include "main/eval.h"
41#include "main/state.h"
42#include "main/light.h"
43#include "main/api_arrayelt.h"
44#include "main/api_noop.h"
45#include "main/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/**
62 * Close off the last primitive, execute the buffer, restart the
63 * primitive.
64 */
65static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
66{
67   if (exec->vtx.prim_count == 0) {
68      exec->vtx.copied.nr = 0;
69      exec->vtx.vert_count = 0;
70      exec->vtx.buffer_ptr = exec->vtx.buffer_map;
71   }
72   else {
73      GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
74      GLuint last_count;
75
76      if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
77	 GLint i = exec->vtx.prim_count - 1;
78	 assert(i >= 0);
79	 exec->vtx.prim[i].count = (exec->vtx.vert_count -
80				    exec->vtx.prim[i].start);
81      }
82
83      last_count = exec->vtx.prim[exec->vtx.prim_count-1].count;
84
85      /* Execute the buffer and save copied vertices.
86       */
87      if (exec->vtx.vert_count)
88	 vbo_exec_vtx_flush( exec, GL_FALSE );
89      else {
90	 exec->vtx.prim_count = 0;
91	 exec->vtx.copied.nr = 0;
92      }
93
94      /* Emit a glBegin to start the new list.
95       */
96      assert(exec->vtx.prim_count == 0);
97
98      if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
99	 exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
100	 exec->vtx.prim[0].start = 0;
101	 exec->vtx.prim[0].count = 0;
102	 exec->vtx.prim_count++;
103
104	 if (exec->vtx.copied.nr == last_count)
105	    exec->vtx.prim[0].begin = last_begin;
106      }
107   }
108}
109
110
111/**
112 * Deal with buffer wrapping where provoked by the vertex buffer
113 * filling up, as opposed to upgrade_vertex().
114 */
115void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
116{
117   GLfloat *data = exec->vtx.copied.buffer;
118   GLuint i;
119
120   /* Run pipeline on current vertices, copy wrapped vertices
121    * to exec->vtx.copied.
122    */
123   vbo_exec_wrap_buffers( exec );
124
125   /* Copy stored stored vertices to start of new list.
126    */
127   assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
128
129   for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
130      memcpy( exec->vtx.buffer_ptr, data,
131	      exec->vtx.vertex_size * sizeof(GLfloat));
132      exec->vtx.buffer_ptr += exec->vtx.vertex_size;
133      data += exec->vtx.vertex_size;
134      exec->vtx.vert_count++;
135   }
136
137   exec->vtx.copied.nr = 0;
138}
139
140
141/**
142 * Copy the active vertex's values to the ctx->Current fields.
143 */
144static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
145{
146   struct gl_context *ctx = exec->ctx;
147   struct vbo_context *vbo = vbo_context(ctx);
148   GLuint i;
149
150   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
151      if (exec->vtx.attrsz[i]) {
152         /* Note: the exec->vtx.current[i] pointers point into the
153          * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
154          */
155	 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
156         GLfloat tmp[4];
157
158         COPY_CLEAN_4V(tmp,
159                       exec->vtx.attrsz[i],
160                       exec->vtx.attrptr[i]);
161
162         if (memcmp(current, tmp, sizeof(tmp)) != 0) {
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            assert(vbo->currval[i].Type == GL_FLOAT);
172            vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
173
174            /* This triggers rather too much recalculation of Mesa state
175             * that doesn't get used (eg light positions).
176             */
177            if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
178                i <= VBO_ATTRIB_MAT_BACK_INDEXES)
179               ctx->NewState |= _NEW_LIGHT;
180
181            ctx->NewState |= _NEW_CURRENT_ATTRIB;
182         }
183      }
184   }
185
186   /* Colormaterial -- this kindof sucks.
187    */
188   if (ctx->Light.ColorMaterialEnabled &&
189       exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
190      _mesa_update_color_material(ctx,
191				  ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
192   }
193}
194
195
196/**
197 * Copy current vertex attribute values into the current vertex.
198 */
199static void
200vbo_exec_copy_from_current(struct vbo_exec_context *exec)
201{
202   struct gl_context *ctx = exec->ctx;
203   struct vbo_context *vbo = vbo_context(ctx);
204   GLint i;
205
206   for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
207      const GLfloat *current = (GLfloat *) vbo->currval[i].Ptr;
208      switch (exec->vtx.attrsz[i]) {
209      case 4: exec->vtx.attrptr[i][3] = current[3];
210      case 3: exec->vtx.attrptr[i][2] = current[2];
211      case 2: exec->vtx.attrptr[i][1] = current[1];
212      case 1: exec->vtx.attrptr[i][0] = current[0];
213	 break;
214      }
215   }
216}
217
218
219/**
220 * Flush existing data, set new attrib size, replay copied vertices.
221 * This is called when we transition from a small vertex attribute size
222 * to a larger one.  Ex: glTexCoord2f -> glTexCoord4f.
223 * We need to go back over the previous 2-component texcoords and insert
224 * zero and one values.
225 */
226static void
227vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
228                             GLuint attr, GLuint newSize )
229{
230   struct gl_context *ctx = exec->ctx;
231   struct vbo_context *vbo = vbo_context(ctx);
232   const GLint lastcount = exec->vtx.vert_count;
233   GLfloat *old_attrptr[VBO_ATTRIB_MAX];
234   const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
235   const GLuint oldSize = exec->vtx.attrsz[attr];
236   GLuint i;
237
238   /* Run pipeline on current vertices, copy wrapped vertices
239    * to exec->vtx.copied.
240    */
241   vbo_exec_wrap_buffers( exec );
242
243   if (unlikely(exec->vtx.copied.nr)) {
244      /* We're in the middle of a primitive, keep the old vertex
245       * format around to be able to translate the copied vertices to
246       * the new format.
247       */
248      memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
249   }
250
251   if (unlikely(oldSize)) {
252      /* Do a COPY_TO_CURRENT to ensure back-copying works for the
253       * case when the attribute already exists in the vertex and is
254       * having its size increased.
255       */
256      vbo_exec_copy_to_current( exec );
257   }
258
259   /* Heuristic: Attempt to isolate attributes received outside
260    * begin/end so that they don't bloat the vertices.
261    */
262   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
263       !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
264      vbo_exec_copy_to_current( exec );
265      reset_attrfv( exec );
266   }
267
268   /* Fix up sizes:
269    */
270   exec->vtx.attrsz[attr] = newSize;
271   exec->vtx.vertex_size += newSize - oldSize;
272   exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
273                         (exec->vtx.vertex_size * sizeof(GLfloat)));
274   exec->vtx.vert_count = 0;
275   exec->vtx.buffer_ptr = exec->vtx.buffer_map;
276
277   if (unlikely(oldSize)) {
278      /* Size changed, recalculate all the attrptr[] values
279       */
280      GLfloat *tmp = exec->vtx.vertex;
281
282      for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
283	 if (exec->vtx.attrsz[i]) {
284	    exec->vtx.attrptr[i] = tmp;
285	    tmp += exec->vtx.attrsz[i];
286	 }
287	 else
288	    exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
289      }
290
291      /* Copy from current to repopulate the vertex with correct
292       * values.
293       */
294      vbo_exec_copy_from_current( exec );
295   }
296   else {
297      /* Just have to append the new attribute at the end */
298      exec->vtx.attrptr[attr] = exec->vtx.vertex +
299	 exec->vtx.vertex_size - newSize;
300   }
301
302   /* Replay stored vertices to translate them
303    * to new format here.
304    *
305    * -- No need to replay - just copy piecewise
306    */
307   if (unlikely(exec->vtx.copied.nr)) {
308      GLfloat *data = exec->vtx.copied.buffer;
309      GLfloat *dest = exec->vtx.buffer_ptr;
310      GLuint j;
311
312      assert(exec->vtx.buffer_ptr == exec->vtx.buffer_map);
313
314      for (i = 0 ; i < exec->vtx.copied.nr ; i++) {
315	 for (j = 0 ; j < VBO_ATTRIB_MAX ; j++) {
316	    GLuint sz = exec->vtx.attrsz[j];
317
318	    if (sz) {
319	       GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
320	       GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
321
322	       if (j == attr) {
323		  if (oldSize) {
324		     GLfloat tmp[4];
325		     COPY_CLEAN_4V(tmp, oldSize, data + old_offset);
326		     COPY_SZ_4V(dest + new_offset, newSize, tmp);
327		  } else {
328		     GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
329		     COPY_SZ_4V(dest + new_offset, sz, current);
330		  }
331	       }
332	       else {
333		  COPY_SZ_4V(dest + new_offset, sz, data + old_offset);
334	       }
335	    }
336	 }
337
338	 data += old_vtx_size;
339	 dest += exec->vtx.vertex_size;
340      }
341
342      exec->vtx.buffer_ptr = dest;
343      exec->vtx.vert_count += exec->vtx.copied.nr;
344      exec->vtx.copied.nr = 0;
345   }
346}
347
348
349/**
350 * This is when a vertex attribute transitions to a different size.
351 * For example, we saw a bunch of glTexCoord2f() calls and now we got a
352 * glTexCoord4f() call.  We promote the array from size=2 to size=4.
353 */
354static void
355vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
356{
357   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
358
359   if (newSize > exec->vtx.attrsz[attr]) {
360      /* New size is larger.  Need to flush existing vertices and get
361       * an enlarged vertex format.
362       */
363      vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
364   }
365   else if (newSize < exec->vtx.active_sz[attr]) {
366      static const GLfloat id[4] = { 0, 0, 0, 1 };
367      GLuint i;
368
369      /* New size is smaller - just need to fill in some
370       * zeros.  Don't need to flush or wrap.
371       */
372      for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
373	 exec->vtx.attrptr[attr][i-1] = id[i-1];
374   }
375
376   exec->vtx.active_sz[attr] = newSize;
377
378   /* Does setting NeedFlush belong here?  Necessitates resetting
379    * vtxfmt on each flush (otherwise flags won't get reset
380    * afterwards).
381    */
382   if (attr == 0)
383      ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
384}
385
386
387/**
388 * This macro is used to implement all the glVertex, glColor, glTexCoord,
389 * glVertexAttrib, etc functions.
390 */
391#define ATTR( A, N, V0, V1, V2, V3 )					\
392do {									\
393   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;		\
394									\
395   if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)))	\
396      ctx->Driver.BeginVertices( ctx );					\
397   									\
398   if (unlikely(exec->vtx.active_sz[A] != N))				\
399      vbo_exec_fixup_vertex(ctx, A, N);					\
400   									\
401   {									\
402      GLfloat *dest = exec->vtx.attrptr[A];				\
403      if (N>0) dest[0] = V0;						\
404      if (N>1) dest[1] = V1;						\
405      if (N>2) dest[2] = V2;						\
406      if (N>3) dest[3] = V3;						\
407   }									\
408									\
409   if ((A) == 0) {							\
410      /* This is a glVertex call */					\
411      GLuint i;								\
412									\
413      for (i = 0; i < exec->vtx.vertex_size; i++)			\
414	 exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i];			\
415									\
416      exec->vtx.buffer_ptr += exec->vtx.vertex_size;			\
417									\
418      /* Set FLUSH_STORED_VERTICES to indicate that there's now */	\
419      /* something to draw (not just updating a color or texcoord).*/	\
420      ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;			\
421									\
422      if (++exec->vtx.vert_count >= exec->vtx.max_vert)			\
423	 vbo_exec_vtx_wrap( exec );					\
424   }									\
425} while (0)
426
427
428#define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
429#define TAG(x) vbo_##x
430
431#include "vbo_attrib_tmp.h"
432
433
434#if FEATURE_beginend
435
436
437#if FEATURE_evaluators
438
439static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
440{
441   GET_CURRENT_CONTEXT( ctx );
442   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
443
444   {
445      GLint i;
446      if (exec->eval.recalculate_maps)
447	 vbo_exec_eval_update( exec );
448
449      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
450	 if (exec->eval.map1[i].map)
451	    if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
452	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
453      }
454   }
455
456
457   memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
458           exec->vtx.vertex_size * sizeof(GLfloat));
459
460   vbo_exec_do_EvalCoord1f( exec, u );
461
462   memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
463           exec->vtx.vertex_size * sizeof(GLfloat));
464}
465
466static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
467{
468   GET_CURRENT_CONTEXT( ctx );
469   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
470
471   {
472      GLint i;
473      if (exec->eval.recalculate_maps)
474	 vbo_exec_eval_update( exec );
475
476      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
477	 if (exec->eval.map2[i].map)
478	    if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
479	       vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
480      }
481
482      if (ctx->Eval.AutoNormal)
483	 if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
484	    vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 );
485   }
486
487   memcpy( exec->vtx.copied.buffer, exec->vtx.vertex,
488           exec->vtx.vertex_size * sizeof(GLfloat));
489
490   vbo_exec_do_EvalCoord2f( exec, u, v );
491
492   memcpy( exec->vtx.vertex, exec->vtx.copied.buffer,
493           exec->vtx.vertex_size * sizeof(GLfloat));
494}
495
496static void GLAPIENTRY vbo_exec_EvalCoord1fv( const GLfloat *u )
497{
498   vbo_exec_EvalCoord1f( u[0] );
499}
500
501static void GLAPIENTRY vbo_exec_EvalCoord2fv( const GLfloat *u )
502{
503   vbo_exec_EvalCoord2f( u[0], u[1] );
504}
505
506static void GLAPIENTRY vbo_exec_EvalPoint1( GLint i )
507{
508   GET_CURRENT_CONTEXT( ctx );
509   GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
510		 (GLfloat) ctx->Eval.MapGrid1un);
511   GLfloat u = i * du + ctx->Eval.MapGrid1u1;
512
513   vbo_exec_EvalCoord1f( u );
514}
515
516
517static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
518{
519   GET_CURRENT_CONTEXT( ctx );
520   GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
521		 (GLfloat) ctx->Eval.MapGrid2un);
522   GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
523		 (GLfloat) ctx->Eval.MapGrid2vn);
524   GLfloat u = i * du + ctx->Eval.MapGrid2u1;
525   GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
526
527   vbo_exec_EvalCoord2f( u, v );
528}
529
530/* use noop eval mesh */
531#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
532#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
533
534#endif /* FEATURE_evaluators */
535
536
537/**
538 * Flush (draw) vertices.
539 * \param  unmap - leave VBO unmapped after flushing?
540 */
541static void
542vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
543{
544   if (exec->vtx.vert_count || unmap) {
545      vbo_exec_vtx_flush( exec, unmap );
546   }
547
548   if (exec->vtx.vertex_size) {
549      vbo_exec_copy_to_current( exec );
550      reset_attrfv( exec );
551   }
552}
553
554
555/**
556 * Called via glBegin.
557 */
558static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
559{
560   GET_CURRENT_CONTEXT( ctx );
561
562   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
563      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
564      int i;
565
566      if (ctx->NewState) {
567	 _mesa_update_state( ctx );
568
569	 CALL_Begin(ctx->Exec, (mode));
570	 return;
571      }
572
573      if (!_mesa_valid_to_render(ctx, "glBegin")) {
574         return;
575      }
576
577      /* Heuristic: attempt to isolate attributes occuring outside
578       * begin/end pairs.
579       */
580      if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
581	 vbo_exec_FlushVertices_internal(exec, GL_FALSE);
582
583      i = exec->vtx.prim_count++;
584      exec->vtx.prim[i].mode = mode;
585      exec->vtx.prim[i].begin = 1;
586      exec->vtx.prim[i].end = 0;
587      exec->vtx.prim[i].indexed = 0;
588      exec->vtx.prim[i].weak = 0;
589      exec->vtx.prim[i].pad = 0;
590      exec->vtx.prim[i].start = exec->vtx.vert_count;
591      exec->vtx.prim[i].count = 0;
592      exec->vtx.prim[i].num_instances = 1;
593
594      ctx->Driver.CurrentExecPrimitive = mode;
595   }
596   else
597      _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
598
599}
600
601
602/**
603 * Called via glEnd.
604 */
605static void GLAPIENTRY vbo_exec_End( void )
606{
607   GET_CURRENT_CONTEXT( ctx );
608
609   if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
610      struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
611
612      if (exec->vtx.prim_count > 0) {
613         /* close off current primitive */
614         int idx = exec->vtx.vert_count;
615         int i = exec->vtx.prim_count - 1;
616
617         exec->vtx.prim[i].end = 1;
618         exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
619      }
620
621      ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
622
623      if (exec->vtx.prim_count == VBO_MAX_PRIM)
624	 vbo_exec_vtx_flush( exec, GL_FALSE );
625   }
626   else
627      _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
628}
629
630
631/**
632 * Called via glPrimitiveRestartNV()
633 */
634static void GLAPIENTRY
635vbo_exec_PrimitiveRestartNV(void)
636{
637   GLenum curPrim;
638   GET_CURRENT_CONTEXT( ctx );
639
640   curPrim = ctx->Driver.CurrentExecPrimitive;
641
642   if (curPrim == PRIM_OUTSIDE_BEGIN_END) {
643      _mesa_error( ctx, GL_INVALID_OPERATION, "glPrimitiveRestartNV" );
644   }
645   else {
646      vbo_exec_End();
647      vbo_exec_Begin(curPrim);
648   }
649}
650
651
652
653static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
654{
655   GLvertexformat *vfmt = &exec->vtxfmt;
656
657   _MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
658
659   vfmt->Begin = vbo_exec_Begin;
660   vfmt->End = vbo_exec_End;
661   vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
662
663   _MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
664   _MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
665
666   vfmt->Rectf = _mesa_noop_Rectf;
667
668   /* from attrib_tmp.h:
669    */
670   vfmt->Color3f = vbo_Color3f;
671   vfmt->Color3fv = vbo_Color3fv;
672   vfmt->Color4f = vbo_Color4f;
673   vfmt->Color4fv = vbo_Color4fv;
674   vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
675   vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
676   vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
677   vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
678   vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
679   vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
680   vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
681   vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
682   vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
683   vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
684   vfmt->Normal3f = vbo_Normal3f;
685   vfmt->Normal3fv = vbo_Normal3fv;
686   vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
687   vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
688   vfmt->TexCoord1f = vbo_TexCoord1f;
689   vfmt->TexCoord1fv = vbo_TexCoord1fv;
690   vfmt->TexCoord2f = vbo_TexCoord2f;
691   vfmt->TexCoord2fv = vbo_TexCoord2fv;
692   vfmt->TexCoord3f = vbo_TexCoord3f;
693   vfmt->TexCoord3fv = vbo_TexCoord3fv;
694   vfmt->TexCoord4f = vbo_TexCoord4f;
695   vfmt->TexCoord4fv = vbo_TexCoord4fv;
696   vfmt->Vertex2f = vbo_Vertex2f;
697   vfmt->Vertex2fv = vbo_Vertex2fv;
698   vfmt->Vertex3f = vbo_Vertex3f;
699   vfmt->Vertex3fv = vbo_Vertex3fv;
700   vfmt->Vertex4f = vbo_Vertex4f;
701   vfmt->Vertex4fv = vbo_Vertex4fv;
702
703   vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
704   vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
705   vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
706   vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
707   vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
708   vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
709   vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
710   vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
711
712   vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
713   vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
714   vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
715   vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
716   vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
717   vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
718   vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
719   vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
720
721   /* integer-valued */
722   vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
723   vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
724   vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
725   vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
726   vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
727   vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
728   vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
729
730   /* unsigned integer-valued */
731   vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
732   vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
733   vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
734   vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
735   vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
736   vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
737   vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
738
739   vfmt->Materialfv = vbo_Materialfv;
740
741   vfmt->EdgeFlag = vbo_EdgeFlag;
742   vfmt->Indexf = vbo_Indexf;
743   vfmt->Indexfv = vbo_Indexfv;
744
745}
746
747
748#else /* FEATURE_beginend */
749
750
751static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
752{
753   /* silence warnings */
754   (void) vbo_Color3f;
755   (void) vbo_Color3fv;
756   (void) vbo_Color4f;
757   (void) vbo_Color4fv;
758   (void) vbo_FogCoordfEXT;
759   (void) vbo_FogCoordfvEXT;
760   (void) vbo_MultiTexCoord1f;
761   (void) vbo_MultiTexCoord1fv;
762   (void) vbo_MultiTexCoord2f;
763   (void) vbo_MultiTexCoord2fv;
764   (void) vbo_MultiTexCoord3f;
765   (void) vbo_MultiTexCoord3fv;
766   (void) vbo_MultiTexCoord4f;
767   (void) vbo_MultiTexCoord4fv;
768   (void) vbo_Normal3f;
769   (void) vbo_Normal3fv;
770   (void) vbo_SecondaryColor3fEXT;
771   (void) vbo_SecondaryColor3fvEXT;
772   (void) vbo_TexCoord1f;
773   (void) vbo_TexCoord1fv;
774   (void) vbo_TexCoord2f;
775   (void) vbo_TexCoord2fv;
776   (void) vbo_TexCoord3f;
777   (void) vbo_TexCoord3fv;
778   (void) vbo_TexCoord4f;
779   (void) vbo_TexCoord4fv;
780   (void) vbo_Vertex2f;
781   (void) vbo_Vertex2fv;
782   (void) vbo_Vertex3f;
783   (void) vbo_Vertex3fv;
784   (void) vbo_Vertex4f;
785   (void) vbo_Vertex4fv;
786
787   (void) vbo_VertexAttrib1fARB;
788   (void) vbo_VertexAttrib1fvARB;
789   (void) vbo_VertexAttrib2fARB;
790   (void) vbo_VertexAttrib2fvARB;
791   (void) vbo_VertexAttrib3fARB;
792   (void) vbo_VertexAttrib3fvARB;
793   (void) vbo_VertexAttrib4fARB;
794   (void) vbo_VertexAttrib4fvARB;
795
796   (void) vbo_VertexAttrib1fNV;
797   (void) vbo_VertexAttrib1fvNV;
798   (void) vbo_VertexAttrib2fNV;
799   (void) vbo_VertexAttrib2fvNV;
800   (void) vbo_VertexAttrib3fNV;
801   (void) vbo_VertexAttrib3fvNV;
802   (void) vbo_VertexAttrib4fNV;
803   (void) vbo_VertexAttrib4fvNV;
804
805   (void) vbo_Materialfv;
806
807   (void) vbo_EdgeFlag;
808   (void) vbo_Indexf;
809   (void) vbo_Indexfv;
810}
811
812
813#endif /* FEATURE_beginend */
814
815
816/**
817 * Tell the VBO module to use a real OpenGL vertex buffer object to
818 * store accumulated immediate-mode vertex data.
819 * This replaces the malloced buffer which was created in
820 * vb_exec_vtx_init() below.
821 */
822void vbo_use_buffer_objects(struct gl_context *ctx)
823{
824   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
825   /* Any buffer name but 0 can be used here since this bufferobj won't
826    * go into the bufferobj hashtable.
827    */
828   GLuint bufName = IMM_BUFFER_NAME;
829   GLenum target = GL_ARRAY_BUFFER_ARB;
830   GLenum usage = GL_STREAM_DRAW_ARB;
831   GLsizei size = VBO_VERT_BUFFER_SIZE;
832
833   /* Make sure this func is only used once */
834   assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
835   if (exec->vtx.buffer_map) {
836      _mesa_align_free(exec->vtx.buffer_map);
837      exec->vtx.buffer_map = NULL;
838      exec->vtx.buffer_ptr = NULL;
839   }
840
841   /* Allocate a real buffer object now */
842   _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
843   exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
844   ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
845}
846
847
848/**
849 * If this function is called, all VBO buffers will be unmapped when
850 * we flush.
851 * Otherwise, if a simple command like glColor3f() is called and we flush,
852 * the current VBO may be left mapped.
853 */
854void
855vbo_always_unmap_buffers(struct gl_context *ctx)
856{
857   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
858   exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
859}
860
861
862void vbo_exec_vtx_init( struct vbo_exec_context *exec )
863{
864   struct gl_context *ctx = exec->ctx;
865   struct vbo_context *vbo = vbo_context(ctx);
866   GLuint i;
867
868   /* Allocate a buffer object.  Will just reuse this object
869    * continuously, unless vbo_use_buffer_objects() is called to enable
870    * use of real VBOs.
871    */
872   _mesa_reference_buffer_object(ctx,
873                                 &exec->vtx.bufferobj,
874                                 ctx->Shared->NullBufferObj);
875
876   ASSERT(!exec->vtx.buffer_map);
877   exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
878   exec->vtx.buffer_ptr = exec->vtx.buffer_map;
879
880   vbo_exec_vtxfmt_init( exec );
881
882   /* Hook our functions into the dispatch table.
883    */
884   _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt );
885
886   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
887      ASSERT(i < Elements(exec->vtx.attrsz));
888      exec->vtx.attrsz[i] = 0;
889      ASSERT(i < Elements(exec->vtx.active_sz));
890      exec->vtx.active_sz[i] = 0;
891   }
892   for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
893      ASSERT(i < Elements(exec->vtx.inputs));
894      ASSERT(i < Elements(exec->vtx.arrays));
895      exec->vtx.inputs[i] = &exec->vtx.arrays[i];
896   }
897
898   {
899      struct gl_client_array *arrays = exec->vtx.arrays;
900      unsigned i;
901
902      memcpy(arrays,      vbo->legacy_currval,  16 * sizeof(arrays[0]));
903      memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
904
905      for (i = 0; i < 16; ++i) {
906         arrays[i     ].BufferObj = NULL;
907         arrays[i + 16].BufferObj = NULL;
908         _mesa_reference_buffer_object(ctx, &arrays[i     ].BufferObj,
909                                       vbo->legacy_currval[i].BufferObj);
910         _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
911                                       vbo->generic_currval[i].BufferObj);
912      }
913   }
914
915   exec->vtx.vertex_size = 0;
916
917   exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
918}
919
920
921void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
922{
923   /* using a real VBO for vertex data */
924   struct gl_context *ctx = exec->ctx;
925   unsigned i;
926
927   /* True VBOs should already be unmapped
928    */
929   if (exec->vtx.buffer_map) {
930      ASSERT(exec->vtx.bufferobj->Name == 0 ||
931             exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
932      if (exec->vtx.bufferobj->Name == 0) {
933         _mesa_align_free(exec->vtx.buffer_map);
934         exec->vtx.buffer_map = NULL;
935         exec->vtx.buffer_ptr = NULL;
936      }
937   }
938
939   /* Drop any outstanding reference to the vertex buffer
940    */
941   for (i = 0; i < Elements(exec->vtx.arrays); i++) {
942      _mesa_reference_buffer_object(ctx,
943                                    &exec->vtx.arrays[i].BufferObj,
944                                    NULL);
945   }
946
947   /* Free the vertex buffer.  Unmap first if needed.
948    */
949   if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
950      ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
951   }
952   _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
953}
954
955
956/**
957 * Called upon first glVertex, glColor, glTexCoord, etc.
958 */
959void vbo_exec_BeginVertices( struct gl_context *ctx )
960{
961   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
962
963   vbo_exec_vtx_map( exec );
964
965   assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
966   assert(exec->begin_vertices_flags);
967
968   ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
969}
970
971
972/**
973 * Called via ctx->Driver.FlushVertices()
974 * \param flags  bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
975 */
976void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
977{
978   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
979
980#ifdef DEBUG
981   /* debug check: make sure we don't get called recursively */
982   exec->flush_call_depth++;
983   assert(exec->flush_call_depth == 1);
984#endif
985
986   if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
987      /* We've had glBegin but not glEnd! */
988#ifdef DEBUG
989      exec->flush_call_depth--;
990      assert(exec->flush_call_depth == 0);
991#endif
992      return;
993   }
994
995   /* Flush (draw), and make sure VBO is left unmapped when done */
996   vbo_exec_FlushVertices_internal(exec, GL_TRUE);
997
998   /* Need to do this to ensure BeginVertices gets called again:
999    */
1000   ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
1001
1002#ifdef DEBUG
1003   exec->flush_call_depth--;
1004   assert(exec->flush_call_depth == 0);
1005#endif
1006}
1007
1008
1009static void reset_attrfv( struct vbo_exec_context *exec )
1010{
1011   GLuint i;
1012
1013   for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
1014      exec->vtx.attrsz[i] = 0;
1015      exec->vtx.active_sz[i] = 0;
1016   }
1017
1018   exec->vtx.vertex_size = 0;
1019}
1020
1021
1022void GLAPIENTRY
1023_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
1024{
1025   vbo_Color4f(r, g, b, a);
1026}
1027
1028
1029void GLAPIENTRY
1030_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
1031{
1032   vbo_Normal3f(x, y, z);
1033}
1034
1035
1036void GLAPIENTRY
1037_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
1038{
1039   vbo_MultiTexCoord4f(target, s, t, r, q);
1040}
1041
1042
1043void GLAPIENTRY
1044_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
1045{
1046   vbo_Materialfv(face, pname, params);
1047}
1048
1049
1050void GLAPIENTRY
1051_es_Materialf(GLenum face, GLenum pname, GLfloat param)
1052{
1053   GLfloat p[4];
1054   p[0] = param;
1055   p[1] = p[2] = p[3] = 0.0F;
1056   vbo_Materialfv(face, pname, p);
1057}
1058
1059
1060/**
1061 * A special version of glVertexAttrib4f that does not treat index 0 as
1062 * VBO_ATTRIB_POS.
1063 */
1064static void
1065VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1066{
1067   GET_CURRENT_CONTEXT(ctx);
1068   if (index < MAX_VERTEX_GENERIC_ATTRIBS)
1069      ATTR(VBO_ATTRIB_GENERIC0 + index, 4, x, y, z, w);
1070   else
1071      ERROR(GL_INVALID_VALUE);
1072}
1073
1074void GLAPIENTRY
1075_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
1076{
1077   VertexAttrib4f_nopos(index, x, y, z, w);
1078}
1079
1080
1081void GLAPIENTRY
1082_es_VertexAttrib1f(GLuint indx, GLfloat x)
1083{
1084   VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
1085}
1086
1087
1088void GLAPIENTRY
1089_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
1090{
1091   VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
1092}
1093
1094
1095void GLAPIENTRY
1096_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
1097{
1098   VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
1099}
1100
1101
1102void GLAPIENTRY
1103_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
1104{
1105   VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
1106}
1107
1108
1109void GLAPIENTRY
1110_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
1111{
1112   VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
1113}
1114
1115
1116void GLAPIENTRY
1117_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
1118{
1119   VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
1120}
1121
1122
1123void GLAPIENTRY
1124_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
1125{
1126   VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
1127}
1128