Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / vbo / vbo_exec_api.c
index c30fd18e2d656ba42a48020ed25c6c7d6b9dc691..a6ce26ffed860573edb729a6c17216ca1fb335ae 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
 
-Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
+Copyright 2002-2008 Tungsten Graphics Inc., Cedar Park, Texas.
 
 All Rights Reserved.
 
@@ -30,19 +30,27 @@ 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/bufferobj.h"
+#include "main/context.h"
+#include "main/macros.h"
+#include "main/vtxfmt.h"
+#if FEATURE_dlist
+#include "main/dlist.h"
+#endif
+#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 );
 
 
@@ -60,7 +68,7 @@ static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
       GLuint last_begin = exec->vtx.prim[exec->vtx.prim_count-1].begin;
       GLuint last_count;
 
-      if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+      if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
         GLint i = exec->vtx.prim_count - 1;
         assert(i >= 0);
         exec->vtx.prim[i].count = (exec->vtx.vert_count - 
@@ -82,7 +90,7 @@ static void vbo_exec_wrap_buffers( struct vbo_exec_context *exec )
        */
       assert(exec->vtx.prim_count == 0);
 
-      if (exec->ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+      if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
         exec->vtx.prim[0].mode = exec->ctx->Driver.CurrentExecPrimitive;
         exec->vtx.prim[0].start = 0;
         exec->vtx.prim[0].count = 0;
@@ -135,29 +143,37 @@ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec )
 
    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(current, 
-                      exec->vtx.attrsz[i], 
-                      exec->vtx.attrptr[i]);
+        GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+         GLfloat tmp[4];
+
+         COPY_CLEAN_4V(tmp, 
+                       exec->vtx.attrsz[i], 
+                       exec->vtx.attrptr[i]);
+         
+         if (memcmp(current, tmp, sizeof(tmp)) != 0)
+         { 
+            memcpy(current, tmp, sizeof(tmp));
 
         
-        /* 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).
-         */
-        if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
-            i <= VBO_ATTRIB_MAT_BACK_INDEXES)
-           ctx->NewState |= _NEW_LIGHT;
+            /* 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).
+             */
+            if (i >= VBO_ATTRIB_MAT_FRONT_AMBIENT &&
+                i <= VBO_ATTRIB_MAT_BACK_INDEXES)
+               ctx->NewState |= _NEW_LIGHT;
+            
+            ctx->NewState |= _NEW_CURRENT_ATTRIB;
+         }
       }
    }
 
@@ -390,7 +406,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 );
@@ -417,7 +433,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 );
@@ -472,6 +488,23 @@ static void GLAPIENTRY vbo_exec_EvalPoint2( GLint i, GLint j )
 }
 
 
+/**
+ * Check if programs/shaders are enabled and valid at glBegin time.
+ */
+GLboolean 
+vbo_validate_shaders(GLcontext *ctx)
+{
+   if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+       (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+      return GL_FALSE;
+   }
+   if (ctx->Shader.CurrentProgram && !ctx->Shader.CurrentProgram->LinkStatus) {
+      return GL_FALSE;
+   }
+   return GL_TRUE;
+}
+
+
 /* Build a list of primitives on the fly.  Keep
  * ctx->Driver.CurrentExecPrimitive uptodate as well.
  */
@@ -479,25 +512,23 @@ static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
 {
    GET_CURRENT_CONTEXT( ctx ); 
 
-   if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+   if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
       struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
       int i;
 
       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,
-                        "glBegin (invalid vertex/fragment program)");
-            return;
-         }
-
         CALL_Begin(ctx->Exec, (mode));
         return;
       }
 
+      if (!vbo_validate_shaders(ctx)) {
+         _mesa_error(ctx, GL_INVALID_OPERATION,
+                     "glBegin (invalid vertex/fragment program)");
+         return;
+      }
+
       /* Heuristic: attempt to isolate attributes occuring outside
        * begin/end pairs.
        */
@@ -525,7 +556,7 @@ static void GLAPIENTRY vbo_exec_End( void )
 {
    GET_CURRENT_CONTEXT( ctx ); 
 
-   if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+   if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
       struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
       int idx = exec->vtx.vert_count;
       int i = exec->vtx.prim_count - 1;
@@ -533,7 +564,7 @@ static void GLAPIENTRY vbo_exec_End( void )
       exec->vtx.prim[i].end = 1; 
       exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
 
-      ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+      ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
 
       if (exec->vtx.prim_count == VBO_MAX_PRIM)
         vbo_exec_vtx_flush( exec );    
@@ -549,8 +580,10 @@ static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
 
    vfmt->ArrayElement = _ae_loopback_array_elt;                /* generic helper */
    vfmt->Begin = vbo_exec_Begin;
+#if FEATURE_dlist
    vfmt->CallList = _mesa_CallList;
    vfmt->CallLists = _mesa_CallLists;
+#endif
    vfmt->End = vbo_exec_End;
    vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
    vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
@@ -626,6 +659,41 @@ static void vbo_exec_vtxfmt_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)
+{
+   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);
+   }
+
+   /* 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);
+
+   /* 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;
@@ -633,11 +701,15 @@ void vbo_exec_vtx_init( struct vbo_exec_context *exec )
    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);
+   _mesa_reference_buffer_object(ctx,
+                                 &exec->vtx.bufferobj,
+                                 ctx->Array.NullBufferObj);
 
+   ASSERT(!exec->vtx.buffer_map);
+   exec->vtx.buffer_map = ALIGN_MALLOC(VBO_VERT_BUFFER_SIZE * sizeof(GLfloat), 64);
    vbo_exec_vtxfmt_init( exec );
 
    /* Hook our functions into the dispatch table.
@@ -662,9 +734,17 @@ void vbo_exec_vtx_init( struct vbo_exec_context *exec )
 
 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;
+   if (exec->vtx.bufferobj->Name) {
+      /* using a real VBO for vertex data */
+      GLcontext *ctx = exec->ctx;
+      _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
+   }
+   else {
+      /* just using malloc'd space for vertex data */
+      if (exec->vtx.buffer_map) {
+         ALIGN_FREE(exec->vtx.buffer_map);
+         exec->vtx.buffer_map = NULL;
+      }
    }
 }
 
@@ -701,3 +781,36 @@ static void reset_attrfv( struct vbo_exec_context *exec )
    exec->vtx.vertex_size = 0;
 }
       
+
+void GLAPIENTRY
+_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+{
+   vbo_Color4f(r, g, b, a);
+}
+
+
+void GLAPIENTRY
+_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
+{
+   vbo_Normal3f(x, y, z);
+}
+
+
+void GLAPIENTRY
+_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+   vbo_MultiTexCoord4f(target, s, t, r, q);
+}
+
+void GLAPIENTRY
+_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+   vbo_Materialfv(face, pname, params);
+}
+
+
+void GLAPIENTRY
+_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   vbo_VertexAttrib4fARB(index, x, y, z, w);
+}