Hopefully sorted out the reported uniform/attribute mess. trunk
authorRyan C. Gordon <icculus@icculus.org>
Sat, 19 Apr 2008 03:58:57 -0400
branchtrunk
changeset 148 645003ec6623
parent 147 98043daf5027
child 149 07c73dfc1475
Hopefully sorted out the reported uniform/attribute mess. This removes output registers from the attribute list, since those aren't something the application should bind. Also, the bulk of this work is setting up a new namespace for samplers.
mojoshader.c
mojoshader.h
testparse.c
--- a/mojoshader.c	Sat Apr 19 02:29:41 2008 -0400
+++ b/mojoshader.c	Sat Apr 19 03:58:57 2008 -0400
@@ -120,6 +120,13 @@
     REG_TYPE_MAX = 19
 } RegisterType;
 
+typedef enum
+{
+    TEXTURE_TYPE_2D = 2,
+    TEXTURE_TYPE_CUBE = 3,
+    TEXTURE_TYPE_VOLUME = 4,
+} TextureType;
+
 // predeclare.
 typedef struct Context Context;
 
@@ -144,6 +151,9 @@
 // one emit function for uniforms in each profile.
 typedef void (*emit_uniform)(Context *ctx, RegisterType regtype, int regnum);
 
+// one emit function for samplers in each profile.
+typedef void (*emit_sampler)(Context *ctx, int stage, TextureType ttype);
+
 // one emit function for attributes in each profile.
 typedef void (*emit_attribute)(Context *ctx, RegisterType regtype, int regnum,
                                MOJOSHADER_usage usage, int index, int wmask);
@@ -162,6 +172,7 @@
     emit_comment comment_emitter;
     emit_global global_emitter;
     emit_uniform uniform_emitter;
+    emit_sampler sampler_emitter;
     emit_attribute attribute_emitter;
     emit_finalize finalize_emitter;
 } Profile;
@@ -181,13 +192,6 @@
     MISCTYPE_TYPE_MAX = 1
 } MiscTypeType;
 
-typedef enum
-{
-    TEXTURE_TYPE_2D = 2,
-    TEXTURE_TYPE_CUBE = 3,
-    TEXTURE_TYPE_VOLUME = 4,
-} TextureType;
-
 
 // A simple linked list of strings, so we can build the final output without
 //  realloc()ing for each new line, and easily insert lines into the middle
@@ -335,6 +339,8 @@
     RegisterList uniforms;
     int attribute_count;
     RegisterList attributes;
+    int sampler_count;
+    RegisterList samplers;
 };
 
 
@@ -679,6 +685,13 @@
     item->writemask = writemask;
 } // add_attribute_register
 
+static inline void add_sampler(Context *ctx, const RegisterType rtype,
+                               const int regnum, const TextureType ttype)
+{
+    RegisterList *item = reglist_insert(ctx, &ctx->samplers, rtype, regnum);
+    item->index = (int) ttype;
+} // add_sampler
+
 
 static inline int replicate_swizzle(const int swizzle)
 {
@@ -1066,6 +1079,12 @@
 } // emit_D3D_uniform
 
 
+static void emit_D3D_sampler(Context *ctx, int stage, TextureType ttype)
+{
+    // no-op.
+} // emit_D3D_sampler
+
+
 static void emit_D3D_attribute(Context *ctx, RegisterType regtype, int regnum,
                                MOJOSHADER_usage usage, int index, int wmask)
 {
@@ -1352,11 +1371,11 @@
     const DestArgInfo *arg = &ctx->dest_args[0];
     const char *usage_str = "";
     char index_str[16] = { '\0' };
-    const uint32 usage = ctx->dwords[0];
 
     if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX)
     {
         const uint32 index = ctx->dwords[1];
+    const uint32 usage = ctx->dwords[0];
         usage_str = usagestrs[usage];
         if (index != 0)
             snprintf(index_str, sizeof (index_str), "%u", (uint) index);
@@ -1366,7 +1385,8 @@
     {
         if (arg->regtype == REG_TYPE_SAMPLER)
         {
-            switch ((const TextureType) usage)
+            const TextureType ttype = (const TextureType) ctx->dwords[0];
+            switch (ttype)
             {
                 case TEXTURE_TYPE_2D: usage_str = "_2d"; break;
                 case TEXTURE_TYPE_CUBE: usage_str = "_cube"; break;
@@ -1442,6 +1462,7 @@
 static void emit_PASSTHROUGH_finalize(Context *ctx) {}
 static void emit_PASSTHROUGH_global(Context *ctx, RegisterType t, int n) {}
 static void emit_PASSTHROUGH_uniform(Context *ctx, RegisterType t, int n) {}
+static void emit_PASSTHROUGH_sampler(Context *ctx, int s, TextureType ttype) {}
 static void emit_PASSTHROUGH_comment(Context *ctx, const char *str) {}
 static void emit_PASSTHROUGH_attribute(Context *ctx, RegisterType t, int n,
                                        MOJOSHADER_usage u, int i, int w) {}
@@ -1895,6 +1916,20 @@
     pop_output(ctx);
 } // emit_GLSL_uniform
 
+static void emit_GLSL_sampler(Context *ctx, int stage, TextureType ttype)
+{
+    push_output(ctx, &ctx->globals);
+    if (ttype == TEXTURE_TYPE_2D)
+        output_line(ctx, "uniform sampler2D s%d;", stage);
+    else if (ttype == TEXTURE_TYPE_CUBE)
+        output_line(ctx, "uniform samplerCube s%d;", stage);
+    else if (ttype == TEXTURE_TYPE_VOLUME)
+        output_line(ctx, "uniform sampler3D s%d;", stage);
+    else
+        fail(ctx, "BUG: we used a sampler we don't know how to define.");
+    pop_output(ctx);
+} // emit_GLSL_sampler
+
 static void emit_GLSL_attribute(Context *ctx, RegisterType regtype, int regnum,
                                 MOJOSHADER_usage usage, int index, int wmask)
 {
@@ -2391,7 +2426,7 @@
 
 static void emit_GLSL_DCL(Context *ctx)
 {
-    // no-op. We do our work at the end in emit_attribute() implementation.
+    // no-op. We do this in our emit_attribute() and emit_uniform().
 } // emit_GLSL_DCL
 
 static void emit_GLSL_POW(Context *ctx)
@@ -2834,6 +2869,7 @@
     emit_##prof##_comment, \
     emit_##prof##_global, \
     emit_##prof##_uniform, \
+    emit_##prof##_sampler, \
     emit_##prof##_attribute, \
     emit_##prof##_finalize, \
 },
@@ -3313,8 +3349,6 @@
     const DestArgInfo *arg = &ctx->dest_args[0];
     const RegisterType regtype = arg->regtype;
     const int regnum = arg->regnum;
-    const uint32 usage = ctx->dwords[0];
-    int index = 0;
 
     // parse_args_DCL() does a lot of state checking before we get here.
 
@@ -3322,19 +3356,23 @@
 
     if (ctx->shader_type == MOJOSHADER_TYPE_VERTEX)
     {
-        index = ctx->dwords[1];
-        if (usage >= ((const uint32) MOJOSHADER_USAGE_TOTAL))
+        const MOJOSHADER_usage usage = (const MOJOSHADER_usage) ctx->dwords[0];
+        const int index = ctx->dwords[1];
+        const int writemask = arg->writemask;
+        if (usage >= MOJOSHADER_USAGE_TOTAL)
         {
             fail(ctx, "unknown DCL usage");
             return;
         } // if
+        add_attribute_register(ctx, regtype, regnum, usage, index, writemask);
     } // if
 
     else if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL)
     {
         if (regtype == REG_TYPE_SAMPLER)
         {
-            switch ((const TextureType) usage)
+            const TextureType ttype = (const TextureType) ctx->dwords[0];
+            switch (ttype)
             {
                 case TEXTURE_TYPE_2D:
                 case TEXTURE_TYPE_CUBE:
@@ -3344,8 +3382,8 @@
                     fail(ctx, "unknown sampler texture type");
                     return;
             } // switch
+            add_sampler(ctx, regtype, regnum, ttype);
         } // if
-
     } // else if
 
     else
@@ -3354,8 +3392,6 @@
     } // else
 
     set_defined_register(ctx, regtype, regnum);
-    add_attribute_register(ctx, regtype, regnum, (MOJOSHADER_usage) usage,
-                            index, arg->writemask);
 } // state_DCL
 
 static void state_FRC(Context *ctx)
@@ -4111,6 +4147,7 @@
         free_reglist(f, d, ctx->defined_registers.next);
         free_reglist(f, d, ctx->uniforms.next);
         free_reglist(f, d, ctx->attributes.next);
+        free_reglist(f, d, ctx->samplers.next);
         if ((ctx->failstr != NULL) && (ctx->failstr != out_of_mem_str))
             f((void *) ctx->failstr, d);
         f(ctx, d);
@@ -4231,14 +4268,60 @@
 } // build_uniforms
 
 
-static MOJOSHADER_attribute *build_attributes(Context *ctx)
-{
-    if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL)
+static MOJOSHADER_sampler *build_samplers(Context *ctx)
+{
+    MOJOSHADER_sampler *retval = (MOJOSHADER_sampler *)
+                Malloc(ctx, sizeof (MOJOSHADER_sampler) * ctx->sampler_count);
+
+    if (retval == NULL)
+        out_of_memory(ctx);
+    else
     {
-        if (ctx->attribute_count > 0)
-            fail(ctx, "BUG: pixel shader shouldn't have vertex attributes");
-        return NULL;  // nothing to do for pixel shaders.
-    } // if
+        RegisterList *item = ctx->samplers.next;
+        MOJOSHADER_samplerType type = MOJOSHADER_SAMPLER_2D;
+        int i;
+
+        for (i = 0; i < ctx->sampler_count; i++)
+        {
+            if (item == NULL)
+            {
+                fail(ctx, "BUG: mismatched sampler list and count");
+                break;
+            } // if
+
+            assert(item->regtype == REG_TYPE_SAMPLER);
+            switch ((const TextureType) item->index)
+            {
+                case TEXTURE_TYPE_2D:
+                    type = MOJOSHADER_SAMPLER_2D;
+                    break;
+
+                case TEXTURE_TYPE_CUBE:
+                    type = MOJOSHADER_SAMPLER_CUBE;
+                    break;
+
+                case TEXTURE_TYPE_VOLUME:
+                    type = MOJOSHADER_SAMPLER_VOLUME;
+                    break;
+
+                default:
+                    fail(ctx, "Unknown sampler type");
+                    break;
+            } // switch
+
+            retval[i].type = type;
+            retval[i].index = item->regnum;
+            item = item->next;
+        } // while
+    } // else
+
+    return retval;
+} // build_samplers
+
+
+static MOJOSHADER_attribute *build_attributes(Context *ctx, int *_count)
+{
+    *_count = 0;
 
     if (ctx->attribute_count == 0)
         return NULL;  // nothing to do.
@@ -4251,6 +4334,9 @@
     else
     {
         RegisterList *item = ctx->attributes.next;
+        MOJOSHADER_attribute *wptr = retval;
+        int is_output = 0;
+        int count = 0;
         int i;
 
         for (i = 0; i < ctx->attribute_count; i++)
@@ -4261,23 +4347,54 @@
                 break;
             } // if
 
-            retval[i].usage = item->usage;
-            retval[i].index = item->index;
+            switch (item->regtype)
+            {
+                case REG_TYPE_RASTOUT:
+                case REG_TYPE_ATTROUT:
+                case REG_TYPE_TEXCRDOUT:
+                case REG_TYPE_COLOROUT:
+                case REG_TYPE_DEPTHOUT:
+                    is_output = 1;
+                    break;
+                default:
+                    is_output = 0;
+                    break;
+            } // switch
+
+            if (!is_output)
+            {
+                wptr->usage = item->usage;
+                wptr->index = item->index;
+                wptr++;
+                count++;
+            } // if
+
             item = item->next;
         } // while
+
+        if (ctx->shader_type == MOJOSHADER_TYPE_PIXEL)
+        {
+            if (count > 0)
+                fail(ctx, "BUG: pixel shader shouldn't have vertex attributes");
+            Free(ctx, retval);
+            return NULL;  // nothing to do for pixel shaders.
+        } // if
+
+        *_count = count;
     } // else
 
     return retval;
 } // build_attributes
 
 
-
 static MOJOSHADER_parseData *build_parsedata(Context *ctx)
 {
     char *output = NULL;
     MOJOSHADER_uniform *uniforms = NULL;
     MOJOSHADER_attribute *attributes = NULL;
+    MOJOSHADER_sampler *samplers = NULL;
     MOJOSHADER_parseData *retval;
+    int attribute_count = 0;
 
     if ((retval = Malloc(ctx, sizeof (MOJOSHADER_parseData))) == NULL)
         return &out_of_mem_data;
@@ -4291,7 +4408,10 @@
         uniforms = build_uniforms(ctx);
 
     if (!isfail(ctx))
-        attributes = build_attributes(ctx);
+        attributes = build_attributes(ctx, &attribute_count);
+
+    if (!isfail(ctx))
+        samplers = build_samplers(ctx);
 
     // check again, in case build_output ran out of memory.
     if (isfail(ctx))
@@ -4299,6 +4419,7 @@
         Free(ctx, output);
         Free(ctx, uniforms);
         Free(ctx, attributes);
+        Free(ctx, samplers);
         retval->error = ctx->failstr;  // we recycle.  :)
         ctx->failstr = NULL;  // don't let this get free()'d too soon.
     } // if
@@ -4312,8 +4433,10 @@
         retval->minor_ver = (int) ctx->minor_ver;
         retval->uniform_count = ctx->uniform_count;
         retval->uniforms = uniforms;
-        retval->attribute_count = ctx->attribute_count;
+        retval->attribute_count = attribute_count;
         retval->attributes = attributes;
+        retval->sampler_count = ctx->sampler_count;
+        retval->samplers = samplers;
     } // else
 
     retval->malloc = (ctx->malloc == internal_malloc) ? NULL : ctx->malloc;
@@ -4378,7 +4501,7 @@
                 case REG_TYPE_CONSTINT:
                 case REG_TYPE_CONSTBOOL:
                     // separate uniforms into a different list for now.
-                    prev->next = item->next;
+                    prev->next = next;
                     item->next = NULL;
                     uitem->next = item;
                     uitem = item;
@@ -4401,6 +4524,15 @@
         ctx->profile->uniform_emitter(ctx, item->regtype, item->regnum);
     } // for
 
+    // ...and samplers...
+    for (item = ctx->samplers.next; item != NULL; item = item->next)
+    {
+        ctx->sampler_count++;
+        ctx->profile->sampler_emitter(ctx, item->regnum,
+                                      (TextureType) item->index);
+    } // for
+
+
     // ...and attributes...
     for (item = ctx->attributes.next; item != NULL; item = item->next)
     {
@@ -4471,6 +4603,9 @@
     if (data->attributes != NULL)
         f((void *) data->attributes, d);
 
+    if (data->samplers != NULL)
+        f((void *) data->samplers, d);
+
     if ((data->error != NULL) && (data->error != out_of_mem_str))
         f((void *) data->error, d);
 
--- a/mojoshader.h	Sat Apr 19 02:29:41 2008 -0400
+++ b/mojoshader.h	Sat Apr 19 03:58:57 2008 -0400
@@ -57,9 +57,6 @@
     MOJOSHADER_UNIFORM_FLOAT,
     MOJOSHADER_UNIFORM_INT,
     MOJOSHADER_UNIFORM_BOOL,
-    MOJOSHADER_UNIFORM_SAMPLER_2D,
-    MOJOSHADER_UNIFORM_SAMPLER_CUBE,
-    MOJOSHADER_UNIFORM_SAMPLER_3D,
 } MOJOSHADER_uniformType;
 
 /*
@@ -77,6 +74,30 @@
 } MOJOSHADER_uniform;
 
 /*
+ * Data types for samplers. See MOJOSHADER_sampler for more information.
+ */
+typedef enum
+{
+    MOJOSHADER_SAMPLER_2D,
+    MOJOSHADER_SAMPLER_CUBE,
+    MOJOSHADER_SAMPLER_VOLUME,
+} MOJOSHADER_samplerType;
+
+/*
+ * These are the samplers to be set for a shader. ...
+ *  IDirect3DDevice::SetTexture() would need this data, for example.
+ * These integers are the sampler "stage". So if index==6 and
+ *  type==MOJOSHADER_SAMPLER_2D, that means we'd expect a regular 2D texture
+ *  to be specified for what would be register "s6" in D3D assembly language,
+ *  before drawing with the shader.
+ */
+typedef struct
+{
+    MOJOSHADER_samplerType type;
+    int index;
+} MOJOSHADER_sampler;
+
+/*
  * Data types for attributes. See MOJOSHADER_attribute for more information.
  */
 typedef enum
@@ -178,6 +199,18 @@
     MOJOSHADER_uniform *uniforms;
 
     /*
+     * The number of elements pointed to by (samplers).
+     */
+    int sampler_count;
+
+    /*
+     * (sampler_count) elements of data that specify Samplers to be set for
+     *  this shader. See discussion on MOJOSHADER_sampler for details.
+     * This can be NULL on error or if (sampler_count) is zero.
+     */
+    MOJOSHADER_sampler *samplers;
+
+    /*
      * The number of elements pointed to by (attributes).
      */
     int attribute_count;
--- a/testparse.c	Sat Apr 19 02:29:41 2008 -0400
+++ b/testparse.c	Sat Apr 19 03:58:57 2008 -0400
@@ -95,6 +95,21 @@
             } // for
         } // else
 
+        printf("SAMPLERS:");
+        if (pd->sampler_count == 0)
+            printf(" (none.)\n");
+        else
+        {
+            int i;
+            printf("\n");
+            for (i = 0; i < pd->sampler_count; i++)
+            {
+                static const char *typenames[] = { "2d", "cube", "volume" };
+                const MOJOSHADER_sampler *s = &pd->samplers[i];
+                printf("    * %d: %s\n", s->index, typenames[(int) s->type]);
+            } // for
+        } // else
+
         if (pd->output != NULL)
         {
             int i;