mojoshader_opengl.c
changeset 775 2c93dcb14687
parent 774 9ac0e5ad0205
child 791 2a7dffefabd5
--- a/mojoshader_opengl.c	Thu Aug 13 22:51:40 2009 -0400
+++ b/mojoshader_opengl.c	Sat Aug 15 03:44:36 2009 -0400
@@ -131,6 +131,11 @@
     // This increments every time we change the register files.
     uint32 generation;
 
+    // This tells us which vertex attribute arrays we have enabled.
+    int max_attrs;
+    uint8 want_attr[32];
+    uint8 have_attr[32];
+
     // GL stuff...
     int opengl_major;
     int opengl_minor;
@@ -1067,6 +1072,7 @@
 {
     MOJOSHADER_glContext *retval = NULL;
     MOJOSHADER_glContext *current_ctx = ctx;
+
     ctx = NULL;
 
     if (m == NULL) m = MOJOSHADER_internal_malloc;
@@ -1406,7 +1412,7 @@
 } // lookup_samplers
 
 
-static void lookup_attributes(MOJOSHADER_glProgram *program)
+static int lookup_attributes(MOJOSHADER_glProgram *program)
 {
     int i;
     const MOJOSHADER_parseData *pd = program->vertex->parseData;
@@ -1421,8 +1427,16 @@
             map->attribute = &a[i];
             map->location = (GLuint) loc;
             program->attribute_count++;
+
+            if (loc > STATICARRAYLEN(ctx->want_attr))
+            {
+                assert(0 && "Static array is too small.");  // laziness fail.
+                return 0;
+            } // if
         } // if
     } // for
+
+    return 1;
 } // lookup_attributes
 
 
@@ -1503,7 +1517,8 @@
                 goto link_program_fail;
 
             memset(retval->attributes, '\0', len);
-            lookup_attributes(retval);
+            if (!lookup_attributes(retval))
+                goto link_program_fail;
         } // if
 
         if (!lookup_uniforms(retval, vshader, &bound))
@@ -1557,30 +1572,18 @@
 void MOJOSHADER_glBindProgram(MOJOSHADER_glProgram *program)
 {
     GLuint handle = 0;
-    int i;
 
     if (program == ctx->bound_program)
         return;  // nothing to do.
 
-    // Disable any client-side arrays the current program could have used.
-    // !!! FIXME: don't disable yet...see which ones get reused, and disable
-    // !!! FIXME:  only what we don't need in MOJOSHADER_glProgramReady().
-    if (ctx->bound_program != NULL)
-    {
-        const int count = ctx->bound_program->attribute_count;
-        for (i = 0; i < count; i++)
-        {
-            const AttributeMap *map = &ctx->bound_program->attributes[i];
-            ctx->glDisableVertexAttribArray(map->location);
-        } // if
-    } // for
-
     if (program != NULL)
     {
         handle = program->handle;
         program->refcount++;
     } // if
 
+    memset(ctx->want_attr, '\0', sizeof (ctx->want_attr[0]) * ctx->max_attrs);
+
     ctx->profileUseProgramObject(program);
     program_unref(ctx->bound_program);
     ctx->bound_program = program;
@@ -1741,13 +1744,46 @@
     if (i == count)
         return;  // nothing to do, this shader doesn't use this stream.
 
-    // these happen to work in both ARB1 and GLSL, but if something alien
+    // this happens to work in both ARB1 and GLSL, but if something alien
     //  shows up, we'll have to split these into profile*() functions.
     ctx->glVertexAttribPointer(gl_index, size, gl_type, norm, stride, ptr);
-    ctx->glEnableVertexAttribArray(gl_index);
+
+    // flag this array as in use, so we can enable it later.
+    ctx->want_attr[gl_index] = 1;
+    if (ctx->max_attrs < gl_index)
+        ctx->max_attrs = gl_index;
 } // MOJOSHADER_glSetVertexAttribute
 
 
+static void update_enabled_arrays(void)
+{
+    int highest_enabled = 0;
+    int i;
+
+    // Enable/disable vertex arrays to match our needs.
+    // this happens to work in both ARB1 and GLSL, but if something alien
+    //  shows up, we'll have to split these into profile*() functions.
+    for (i = 0; i <= ctx->max_attrs; i++)
+    {
+        const int want = (const int) ctx->want_attr[i];
+        const int have = (const int) ctx->have_attr[i];
+        if (want != have)
+        {
+            if (want)
+                ctx->glEnableVertexAttribArray(i);
+            else
+                ctx->glDisableVertexAttribArray(i);
+            ctx->have_attr[i] = ctx->want_attr[i];
+        } // if
+
+        if (want)
+            highest_enabled = i;
+    } // for
+
+    ctx->max_attrs = highest_enabled;  // trim unneeded iterations next time.
+} // update_enabled_arrays
+
+
 void MOJOSHADER_glProgramReady(void)
 {
     MOJOSHADER_glProgram *program = ctx->bound_program;
@@ -1755,6 +1791,9 @@
     if (program == NULL)
         return;  // nothing to do.
 
+    // Toggle vertex attribute arrays on/off, based on our needs.
+    update_enabled_arrays();
+
     // push Uniforms to the program from our register files...
     if ((program->uniform_count) && (program->generation != ctx->generation))
     {
@@ -1855,6 +1894,7 @@
     MOJOSHADER_glContext *current_ctx = ctx;
     ctx = _ctx;
     MOJOSHADER_glBindProgram(NULL);
+    update_enabled_arrays();  // disables all vertex arrays.
     lookup_entry_points(NULL);
     Free(ctx);
     ctx = ((current_ctx == _ctx) ? NULL : current_ctx);