Cell: generalize the batch buffer code for vertex buffers...
[mesa.git] / src / mesa / vbo / vbo_exec_api.c
index c764c4d8b63e109ec7379c34a515ff82bca6e773..b7f4d8a3075ffd82b3b6fe31f97533b87e74f2e6 100644 (file)
@@ -30,19 +30,24 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
  *   Keith Whitwell <keith@tungstengraphics.com>
  */
 
-#include "glheader.h"
-#include "context.h"
-#include "macros.h"
-#include "vtxfmt.h"
-#include "dlist.h"
-#include "state.h"
-#include "light.h"
-#include "api_arrayelt.h"
-#include "api_noop.h"
-#include "dispatch.h"
+#include "main/glheader.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/vtxfmt.h"
+#include "main/dlist.h"
+#include "main/state.h"
+#include "main/light.h"
+#include "main/api_arrayelt.h"
+#include "main/api_noop.h"
+#include "glapi/dispatch.h"
 
 #include "vbo_context.h"
 
+#ifdef ERROR
+#undef ERROR
+#endif
+
+
 static void reset_attrfv( struct vbo_exec_context *exec );
 
 
@@ -130,17 +135,28 @@ void vbo_exec_vtx_wrap( struct vbo_exec_context *exec )
 static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
 {
    GLcontext *ctx = exec->ctx;
+   struct vbo_context *vbo = vbo_context(ctx);
    GLuint i;
 
    for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
       if (exec->vtx.attrsz[i]) {
+        GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+
          /* Note: the exec->vtx.current[i] pointers point into the
           * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
           */
-        COPY_CLEAN_4V(exec->vtx.current[i]
+        COPY_CLEAN_4V(current
                       exec->vtx.attrsz[i], 
                       exec->vtx.attrptr[i]);
 
+        
+        /* Given that we explicitly state size here, there is no need
+         * for the COPY_CLEAN above, could just copy 16 bytes and be
+         * done.  The only problem is when Mesa accesses ctx->Current
+         * directly.
+         */
+        vbo->currval[i].Size = exec->vtx.attrsz[i];
+
         /* This triggers rather too much recalculation of Mesa state
          * that doesn't get used (eg light positions).
          */
@@ -150,19 +166,6 @@ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
       }
    }
 
-   /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
-    * will trash adjacent memory!)
-    */
-   if (exec->vtx.attrsz[VBO_ATTRIB_INDEX]) {
-      ctx->Current.Index = exec->vtx.attrptr[VBO_ATTRIB_INDEX][0];
-   }
-
-   /* Edgeflag requires additional treatment:
-    */
-   if (exec->vtx.attrsz[VBO_ATTRIB_EDGEFLAG]) {
-      ctx->Current.EdgeFlag = (exec->vtx.CurrentFloatEdgeFlag == 1.0);
-   }
-
    /* Colormaterial -- this kindof sucks.
     */
    if (ctx->Light.ColorMaterialEnabled &&
@@ -178,21 +181,19 @@ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
 static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
 {
    GLcontext *ctx = exec->ctx;
+   struct vbo_context *vbo = vbo_context(ctx);
    GLint i;
 
-   /* Edgeflag requires additional treatment:
-    */
-   exec->vtx.CurrentFloatEdgeFlag = 
-      (GLfloat)ctx->Current.EdgeFlag;
-   
-   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) 
+   for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
+      const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
       switch (exec->vtx.attrsz[i]) {
-      case 4: exec->vtx.attrptr[i][3] = exec->vtx.current[i][3];
-      case 3: exec->vtx.attrptr[i][2] = exec->vtx.current[i][2];
-      case 2: exec->vtx.attrptr[i][1] = exec->vtx.current[i][1];
-      case 1: exec->vtx.attrptr[i][0] = exec->vtx.current[i][0];
+      case 4: exec->vtx.attrptr[i][3] = current[3];
+      case 3: exec->vtx.attrptr[i][2] = current[2];
+      case 2: exec->vtx.attrptr[i][1] = current[1];
+      case 1: exec->vtx.attrptr[i][0] = current[0];
         break;
       }
+   }
 
    ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
 }
@@ -205,6 +206,7 @@ static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
                                          GLuint newsz )
 {
    GLcontext *ctx = exec->ctx;
+   struct vbo_context *vbo = vbo_context(ctx);
    GLint lastcount = exec->vtx.vert_count;
    GLfloat *tmp;
    GLuint oldsz;
@@ -281,7 +283,8 @@ static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
                     data += oldsz;
                     dest += newsz;
                  } else {
-                    COPY_SZ_4V( dest, newsz, exec->vtx.current[j] );
+                    const GLfloat *current = (const GLfloat *)vbo->currval[j].Ptr;
+                    COPY_SZ_4V( dest, newsz, current );
                     dest += newsz;
                  }
               }
@@ -392,7 +395,7 @@ static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
       if (exec->eval.recalculate_maps) 
         vbo_exec_eval_update( exec );
 
-      for (i = 0 ; i <= VBO_ATTRIB_INDEX ; i++) {
+      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
         if (exec->eval.map1[i].map) 
            if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
               vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz );
@@ -419,7 +422,7 @@ static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v )
       if (exec->eval.recalculate_maps) 
         vbo_exec_eval_update( exec );
 
-      for (i = 0 ; i <= VBO_ATTRIB_INDEX ; i++) {
+      for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
         if (exec->eval.map2[i].map) 
            if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
               vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz );
@@ -488,6 +491,7 @@ static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
       if (ctx->NewState) {
         _mesa_update_state( ctx );
 
+         /* XXX also need to check if shader enabled, but invalid */
          if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
             (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
             _mesa_error(ctx, GL_INVALID_OPERATION,
@@ -627,36 +631,54 @@ static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
 }
 
 
-static void vbo_exec_current_init( struct vbo_exec_context *exec ) 
+/**
+ * Tell the VBO module to use a real OpenGL vertex buffer object to
+ * store accumulated immediate-mode vertex data.
+ * This replaces the malloced buffer which was created in
+ * vb_exec_vtx_init() below.
+ */
+void vbo_use_buffer_objects(GLcontext *ctx)
 {
-   GLcontext *ctx = exec->ctx;
-   GLint i;
-
-   /* setup the pointers for the typical 16 vertex attributes */
-   for (i = 0; i < VBO_ATTRIB_FIRST_MATERIAL; i++) 
-      exec->vtx.current[i] = ctx->Current.Attrib[i];
+   struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+   /* Any buffer name but 0 can be used here since this bufferobj won't
+    * go into the bufferobj hashtable.
+    */
+   GLuint bufName = 0xaabbccdd;
+   GLenum target = GL_ARRAY_BUFFER_ARB;
+   GLenum access = GL_READ_WRITE_ARB;
+   GLenum usage = GL_STREAM_DRAW_ARB;
+   GLsizei size = VBO_VERT_BUFFER_SIZE * sizeof(GLfloat);
+
+   /* Make sure this func is only used once */
+   assert(exec->vtx.bufferobj == ctx->Array.NullBufferObj);
+   if (exec->vtx.buffer_map) {
+      _mesa_align_free(exec->vtx.buffer_map);
+   }
 
-   /* setup pointers for the 12 material attributes */
-   for (i = 0; i < MAT_ATTRIB_MAX; i++)
-      exec->vtx.current[VBO_ATTRIB_FIRST_MATERIAL + i] = 
-        ctx->Light.Material.Attrib[i];
+   /* Allocate a real buffer object now */
+   exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
+   ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
 
-   exec->vtx.current[VBO_ATTRIB_INDEX] = &ctx->Current.Index;
-   exec->vtx.current[VBO_ATTRIB_EDGEFLAG] = &exec->vtx.CurrentFloatEdgeFlag;
+   /* and map it */
+   exec->vtx.buffer_map
+      = ctx->Driver.MapBuffer(ctx, target, access, exec->vtx.bufferobj);
 }
 
+
+
 void vbo_exec_vtx_init( struct vbo_exec_context *exec )
 {
    GLcontext *ctx = exec->ctx;
+   struct vbo_context *vbo = vbo_context(ctx);
    GLuint i;
 
    /* Allocate a buffer object.  Will just reuse this object
-    * continuously.
+    * continuously, unless vbo_use_buffer_objects() is called to enable
+    * use of real VBOs.
     */
    exec->vtx.bufferobj = ctx->Array.NullBufferObj;
    exec->vtx.buffer_map = ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE * sizeof(GLfloat), 64);
 
-   vbo_exec_current_init( exec );
    vbo_exec_vtxfmt_init( exec );
 
    /* Hook our functions into the dispatch table.
@@ -668,16 +690,30 @@ void vbo_exec_vtx_init( struct vbo_exec_context *exec )
       exec->vtx.active_sz[i] = 0;
       exec->vtx.inputs[i] = &exec->vtx.arrays[i];
    }
+   
+   {
+      struct gl_client_array *arrays = exec->vtx.arrays;
+      memcpy(arrays,      vbo->legacy_currval,  16 * sizeof(arrays[0]));
+      memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
+   }
+
    exec->vtx.vertex_size = 0;
 }
 
 
 void vbo_exec_vtx_destroy( struct vbo_exec_context *exec )
 {
-   if (exec->vtx.buffer_map) {
-      ALIGN_FREE(exec->vtx.buffer_map);
-      exec->vtx.buffer_map = NULL;
+   GLcontext *ctx = exec->ctx;
+   if (exec->vtx.bufferobj->Name) {
+      ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER_ARB, exec->vtx.bufferobj);
+      ctx->Driver.DeleteBuffer(ctx, exec->vtx.bufferobj);
+      exec->vtx.bufferobj = NULL;
+   }
+   else {
+      if (exec->vtx.buffer_map) {
+         ALIGN_FREE(exec->vtx.buffer_map);
+         exec->vtx.buffer_map = NULL;
+      }
    }
 }