Expose true constant arrays in parseData, load them at link time for GLSL. trunk
authorRyan C. Gordon <icculus@icculus.org>
Thu, 31 Jul 2008 17:48:36 -0400
branchtrunk
changeset 438 73492129c1af
parent 437 a97a9b21087b
child 439 4713376cb94a
Expose true constant arrays in parseData, load them at link time for GLSL.
mojoshader.c
mojoshader.h
mojoshader_opengl.c
testparse.c
--- a/mojoshader.c	Thu Jul 31 17:43:38 2008 -0400
+++ b/mojoshader.c	Thu Jul 31 17:48:36 2008 -0400
@@ -2377,25 +2377,10 @@
     else
 #endif
     {
-        // stock GLSL 1.0 can't do constant arrays, so make a global array
-        //  and assign all entries at the start of the mainline...
+        // stock GLSL 1.0 can't do constant arrays, so make a uniform array
+        //  and have the OpenGL glue assign it at link time. Lame!
         push_output(ctx, &ctx->globals);
-        output_line(ctx, "vec4 %s[%d];", varname, size);
-        pop_output(ctx);
-
-        push_output(ctx, &ctx->mainline_intro);
-        ctx->indent++;
-        for (i = 0; i < size; i++)
-        {
-            while (clist->constant.type != MOJOSHADER_UNIFORM_FLOAT)
-                clist = clist->next;
-            assert(clist->constant.index == (base + i));
-            cstr = get_GLSL_varname(ctx, REG_TYPE_CONST, clist->constant.index);
-            output_line(ctx, "%s[%d] = %s;", varname, i, cstr);
-            clist = clist->next;
-            ctx->scratchidx = origscratch;
-        } // for
-        ctx->indent--;
+        output_line(ctx, "uniform vec4 %s[%d];", varname, size);
         pop_output(ctx);
     } // else
 } // emit_GLSL_const_array
@@ -7112,7 +7097,7 @@
         int written = 0;
         for (var = ctx->variables; var != NULL; var = var->next)
         {
-            if ((!var->constant) && (var->used))
+            if (var->used)
             {
                 const char *name = ctx->profile->get_const_array_varname(ctx,
                                                       var->index, var->count);
@@ -7123,6 +7108,7 @@
                     wptr->type = MOJOSHADER_UNIFORM_FLOAT;
                     wptr->index = var->index;
                     wptr->array_count = var->count;
+                    wptr->constant = (var->constant != NULL) ? 1 : 0;
                     wptr->name = namecpy;
                     wptr++;
                     written++;
--- a/mojoshader.h	Thu Jul 31 17:43:38 2008 -0400
+++ b/mojoshader.h	Thu Jul 31 17:48:36 2008 -0400
@@ -92,6 +92,10 @@
  *  just a single uniform. To be extra difficult, you'll need to fill in the
  *  correct values from the MOJOSHADER_constant data into the appropriate
  *  parts of the array, overriding the constant register file. Fun!
+ * (constant) says whether this is a constant array; these need to be loaded
+ *  once at creation time, from the constant list and not ever updated from
+ *  the constant register file. This is a workaround for limitations in some
+ *  profiles.
  * (name) is a profile-specific variable name; it may be NULL if it isn't
  *  applicable to the requested profile.
  */
@@ -100,6 +104,7 @@
     MOJOSHADER_uniformType type;
     int index;
     int array_count;
+    int constant;
     const char *name;
 } MOJOSHADER_uniform;
 
--- a/mojoshader_opengl.c	Thu Jul 31 17:43:38 2008 -0400
+++ b/mojoshader_opengl.c	Thu Jul 31 17:48:36 2008 -0400
@@ -196,6 +196,7 @@
     void (*profileUniform4iv)(const MOJOSHADER_parseData *, GLint, GLsizei, GLint *);
     void (*profileUniform1i)(const MOJOSHADER_parseData *, GLint, GLint);
     void (*profileSetSampler)(GLint loc, GLuint sampler);
+    int (*profileMustLoadConstantArrays)(void);
 };
 
 
@@ -259,6 +260,8 @@
 } // glsl_shader_type
 
 
+static int impl_GLSL_MustLoadConstantArrays(void) { return 1; }
+
 static int impl_GLSL_MaxUniforms(MOJOSHADER_shaderType shader_type)
 {
     GLenum pname = GL_NONE;
@@ -407,6 +410,7 @@
     return GL_NONE;
 } // arb1_shader_type
 
+static int impl_ARB1_MustLoadConstantArrays(void) { return 0; }
 
 static int impl_ARB1_MaxUniforms(MOJOSHADER_shaderType shader_type)
 {
@@ -942,6 +946,7 @@
         ctx->profileUniform4iv = impl_GLSL_Uniform4iv;
         ctx->profileUniform1i = impl_GLSL_Uniform1i;
         ctx->profileSetSampler = impl_GLSL_SetSampler;
+        ctx->profileMustLoadConstantArrays = impl_GLSL_MustLoadConstantArrays;
     } // if
 #endif
 
@@ -964,6 +969,7 @@
         ctx->profileUniform4iv = impl_ARB1_Uniform4iv;
         ctx->profileUniform1i = impl_ARB1_Uniform1i;
         ctx->profileSetSampler = impl_ARB1_SetSampler;
+        ctx->profileMustLoadConstantArrays = impl_ARB1_MustLoadConstantArrays;
 
         // GL_NV_gpu_program4 has integer uniform loading support.
         if (strcmp(profile, MOJOSHADER_PROFILE_NV4) == 0)
@@ -988,6 +994,7 @@
     assert(ctx->profileUniform4iv != NULL);
     assert(ctx->profileUniform1i != NULL);
     assert(ctx->profileSetSampler != NULL);
+    assert(ctx->profileMustLoadConstantArrays != NULL);
 
     retval = ctx;
     ctx = current_ctx;
@@ -1097,24 +1104,59 @@
 } // program_unref
 
 
+static void fill_constant_array(GLfloat *f, const int base, const int size,
+                                const MOJOSHADER_parseData *pd)
+{
+    int i;
+    int filled = 0;
+    for (i = 0; i < pd->constant_count; i++)
+    {
+        const MOJOSHADER_constant *c = &pd->constants[i];
+        if (c->type != MOJOSHADER_UNIFORM_FLOAT)
+            continue;
+        else if (c->index < base)
+            continue;
+        else if (c->index >= (base+size))
+            continue;
+        memcpy(&f[(c->index-base) * 4], &c->value.f, sizeof (c->value.f));
+        filled++;
+    } // for
+
+    assert(filled == size);
+} // fill_constant_array
+
+
 static void lookup_uniforms(MOJOSHADER_glProgram *program,
                             MOJOSHADER_glShader *shader)
 {
     const MOJOSHADER_parseData *pd = shader->parseData;
-    const MOJOSHADER_uniform *u = pd->uniforms;
     const MOJOSHADER_shaderType shader_type = pd->shader_type;
     int i;
 
     for (i = 0; i < pd->uniform_count; i++)
     {
+        const MOJOSHADER_uniform *u = &pd->uniforms[i];
         const GLint loc = ctx->profileGetUniformLocation(program, shader, i);
         if (loc != -1)  // maybe the Uniform was optimized out?
         {
-            UniformMap *map = &program->uniforms[program->uniform_count];
-            map->shader_type = shader_type;
-            map->uniform = &u[i];
-            map->location = (GLuint) loc;
-            program->uniform_count++;
+            // only do constants once, at link time. These aren't changed ever.
+            if ( (u->constant) && (ctx->profileMustLoadConstantArrays()) )
+            {
+                const int base = u->index;
+                const int size = u->array_count;
+                GLfloat *f = (GLfloat *) alloca(sizeof (GLfloat) * size * 4);
+                fill_constant_array(f, base, size, pd);
+                ctx->profileUseProgramObject(program);
+                ctx->profileUniform4fv(pd, loc, size, f);
+            } // if
+            else
+            {
+                UniformMap *map = &program->uniforms[program->uniform_count];
+                map->shader_type = shader_type;
+                map->uniform = u;
+                map->location = (GLuint) loc;
+                program->uniform_count++;
+            } // else
         } // if
     } // for
 } // lookup_uniforms
@@ -1177,6 +1219,8 @@
         const MOJOSHADER_uniform *u = map->uniform;
         const int size = u->array_count;
 
+        assert(!u->constant);
+
         if (size == 0)
             continue;  // nothing to see here.
 
@@ -1506,6 +1550,8 @@
         GLint *regi;
         GLint *regb;
 
+        assert(!u->constant);
+
         if (shader_type == MOJOSHADER_TYPE_VERTEX)
         {
             pd = ctx->bound_program->vertex->parseData;
--- a/testparse.c	Thu Jul 31 17:43:38 2008 -0400
+++ b/testparse.c	Thu Jul 31 17:48:36 2008 -0400
@@ -141,6 +141,7 @@
                 static const char *typenames[] = { "float", "int", "bool" };
                 const MOJOSHADER_uniform *u = &pd->uniforms[i];
                 const char *arrayof = "";
+                const char *constant = u->constant ? "const " : "";
                 char arrayrange[64] = { '\0' };
                 if (u->array_count > 0)
                 {
@@ -149,8 +150,8 @@
                              u->array_count);
                 } // if
 
-                printf("    * %d: %s%s%s", u->index, arrayof, arrayrange,
-                        typenames[(int) u->type]);
+                printf("    * %d: %s%s%s%s", u->index, constant, arrayof,
+                        arrayrange, typenames[(int) u->type]);
                 if (u->name != NULL)
                     printf(" (\"%s\")", u->name);
                 printf("\n");