Report hardcoded constants in MOJOSHADER_parseData. trunk
authorRyan C. Gordon <icculus@icculus.org>
Sat, 03 May 2008 15:28:30 -0400
branchtrunk
changeset 278 5c432d216078
parent 277 49a6571cac6d
child 279 f06f4ea3d751
Report hardcoded constants in MOJOSHADER_parseData.
mojoshader.c
mojoshader.h
testparse.c
--- a/mojoshader.c	Sat May 03 14:16:01 2008 -0400
+++ b/mojoshader.c	Sat May 03 15:28:30 2008 -0400
@@ -228,6 +228,11 @@
     struct RegisterList *next;
 } RegisterList;
 
+typedef struct ConstantsList
+{
+    MOJOSHADER_constant constant;
+    struct ConstantsList *next;
+} ConstantsList;
 
 // result modifiers.
 #define MOD_SATURATE 0x01
@@ -348,6 +353,8 @@
     int cmps;
     RegisterList used_registers;
     RegisterList defined_registers;
+    int constant_count;
+    ConstantsList *constants;
     int uniform_count;
     RegisterList uniforms;
     int attribute_count;
@@ -3594,9 +3601,22 @@
 } // parse_args_TEX
 
 
-
 // State machine functions...
 
+static ConstantsList *alloc_constant_listitem(Context *ctx)
+{
+    ConstantsList *item = (ConstantsList *) Malloc(ctx, sizeof (ConstantsList));
+    if (item == NULL)
+        return NULL;
+
+    memset(&item->constant, '\0', sizeof (MOJOSHADER_constant));
+    item->next = ctx->constants;
+    ctx->constants = item;
+    ctx->constant_count++;
+
+    return item;
+} // alloc_constant_listitem
+
 static void state_DEF(Context *ctx)
 {
     const RegisterType regtype = ctx->dest_arg.regtype;
@@ -3604,10 +3624,19 @@
 
     ctx->instruction_count--;  // these don't increase your instruction count.
 
+    // !!! FIXME: fail if same register is defined twice.
+
     if (regtype != REG_TYPE_CONST)
         fail(ctx, "DEF token using invalid register");
     else
+    {
+        ConstantsList *item = alloc_constant_listitem(ctx);
+        item->constant.index = regnum;
+        item->constant.type = MOJOSHADER_UNIFORM_FLOAT;
+        memcpy(item->constant.value.f, ctx->dwords,
+               sizeof (item->constant.value.f));
         set_defined_register(ctx, regtype, regnum);
+    } // else
 } // state_DEF
 
 static void state_DEFI(Context *ctx)
@@ -3615,12 +3644,22 @@
     const RegisterType regtype = ctx->dest_arg.regtype;
     const int regnum = ctx->dest_arg.regnum;
 
+    // !!! FIXME: fail if same register is defined twice.
+
     ctx->instruction_count--;  // these don't increase your instruction count.
 
     if (regtype != REG_TYPE_CONSTINT)
         fail(ctx, "DEFI token using invalid register");
     else
+    {
+        ConstantsList *item = alloc_constant_listitem(ctx);
+        item->constant.index = regnum;
+        item->constant.type = MOJOSHADER_UNIFORM_INT;
+        memcpy(item->constant.value.i, ctx->dwords,
+               sizeof (item->constant.value.i));
+
         set_defined_register(ctx, regtype, regnum);
+    } // else
 } // state_DEFI
 
 static void state_DEFB(Context *ctx)
@@ -3628,12 +3667,20 @@
     const RegisterType regtype = ctx->dest_arg.regtype;
     const int regnum = ctx->dest_arg.regnum;
 
+    // !!! FIXME: fail if same register is defined twice.
+
     ctx->instruction_count--;  // these don't increase your instruction count.
 
     if (regtype != REG_TYPE_CONSTBOOL)
         fail(ctx, "DEFB token using invalid register");
     else
+    {
+        ConstantsList *item = alloc_constant_listitem(ctx);
+        item->constant.index = regnum;
+        item->constant.type = MOJOSHADER_UNIFORM_BOOL;
+        item->constant.value.b = ctx->dwords[0] ? 1 : 0;
         set_defined_register(ctx, regtype, regnum);
+    } // else
 } // state_DEFB
 
 static void state_DCL(Context *ctx)
@@ -4458,6 +4505,17 @@
 } // free_output_list
 
 
+static void free_constants_list(MOJOSHADER_free f, void *d, ConstantsList *item)
+{
+    while (item != NULL)
+    {
+        ConstantsList *next = item->next;
+        f(item, d);
+        item = next;
+    } // while
+} // free_constants_list
+
+
 static void destroy_context(Context *ctx)
 {
     if (ctx != NULL)
@@ -4472,6 +4530,7 @@
         free_output_list(f, d, ctx->mainline_intro.head.next);
         free_output_list(f, d, ctx->mainline.head.next);
         free_output_list(f, d, ctx->ignore.head.next);
+        free_constants_list(f, d, ctx->constants);
         free_reglist(f, d, ctx->used_registers.next);
         free_reglist(f, d, ctx->defined_registers.next);
         free_reglist(f, d, ctx->uniforms.next);
@@ -4593,6 +4652,33 @@
 } // build_uniforms
 
 
+static MOJOSHADER_constant *build_constants(Context *ctx)
+{
+    const size_t len = sizeof (MOJOSHADER_constant) * ctx->constant_count;
+    MOJOSHADER_constant *retval = (MOJOSHADER_constant *) Malloc(ctx, len);
+
+    if (retval != NULL)
+    {
+        ConstantsList *item = ctx->constants;
+        int i;
+
+        for (i = 0; i < ctx->constant_count; i++)
+        {
+            if (item == NULL)
+            {
+                fail(ctx, "BUG: mismatched constant list and count");
+                break;
+            } // if
+
+            memcpy(&retval[i], &item->constant, sizeof (MOJOSHADER_constant));
+            item = item->next;
+        } // for
+    } // if
+
+    return retval;
+} // build_constants
+
+
 static MOJOSHADER_sampler *build_samplers(Context *ctx)
 {
     const size_t len = sizeof (MOJOSHADER_sampler) * ctx->sampler_count;
@@ -4718,6 +4804,7 @@
 static MOJOSHADER_parseData *build_parsedata(Context *ctx)
 {
     char *output = NULL;
+    MOJOSHADER_constant *constants = NULL;
     MOJOSHADER_uniform *uniforms = NULL;
     MOJOSHADER_attribute *attributes = NULL;
     MOJOSHADER_sampler *samplers = NULL;
@@ -4734,6 +4821,9 @@
         output = build_output(ctx);
 
     if (!isfail(ctx))
+        constants = build_constants(ctx);
+
+    if (!isfail(ctx))
         uniforms = build_uniforms(ctx);
 
     if (!isfail(ctx))
@@ -4748,6 +4838,7 @@
         int i;
 
         Free(ctx, output);
+        Free(ctx, constants);
 
         if (uniforms != NULL)
         {
@@ -4784,6 +4875,8 @@
         retval->minor_ver = (int) ctx->minor_ver;
         retval->uniform_count = ctx->uniform_count;
         retval->uniforms = uniforms;
+        retval->constant_count = ctx->constant_count;
+        retval->constants = constants;
         retval->attribute_count = attribute_count;
         retval->attributes = attributes;
         retval->sampler_count = ctx->sampler_count;
@@ -4945,6 +5038,9 @@
     if (data->output != NULL)  // check for NULL in case of dumb free() impl.
         f((void *) data->output, d);
 
+    if (data->constants != NULL)
+        f((void *) data->constants, d);
+
     if (data->uniforms != NULL)
     {
         for (i = 0; i < data->uniform_count; i++)
--- a/mojoshader.h	Sat May 03 14:16:01 2008 -0400
+++ b/mojoshader.h	Sat May 03 15:28:30 2008 -0400
@@ -95,6 +95,29 @@
 } MOJOSHADER_uniform;
 
 /*
+ * These are the constants defined in a shader. These are data values
+ *  hardcoded in a shader (with the DEF, DEFI, DEFB instructions), which
+ *  override your Uniforms. This data is largely for informational purposes,
+ *  since they are compiled in and can't be changed, like Uniforms can be.
+ * These integers are register indexes. So if index==6 and
+ *  type==MOJOSHADER_UNIFORM_FLOAT, that means we'd expect a 4-float vector
+ *  to be specified for what would be register "c6" in D3D assembly language,
+ *  before drawing with the shader.
+ * (value) is the value of the constant, unioned by type.
+ */
+typedef struct
+{
+    MOJOSHADER_uniformType type;
+    int index;
+    union
+    {
+        float f[4];  /* if type==MOJOSHADER_UNIFORM_FLOAT */
+        int i[4];    /* if type==MOJOSHADER_UNIFORM_INT */
+        int b;       /* if type==MOJOSHADER_UNIFORM_BOOL */
+    } value;
+} MOJOSHADER_constant;
+
+/*
  * Data types for samplers. See MOJOSHADER_sampler for more information.
  */
 typedef enum
@@ -233,6 +256,21 @@
     MOJOSHADER_uniform *uniforms;
 
     /*
+     * The number of elements pointed to by (constants).
+     */
+    int constant_count;
+
+    /*
+     * (constant_count) elements of data that specify constants used in
+     *  this shader. See discussion on MOJOSHADER_constant for details.
+     * This can be NULL on error or if (constant_count) is zero.
+     *  This is largely informational: constants are hardcoded into a shader.
+     *  The constants that you can set like parameters are in the "uniforms"
+     *  list.
+     */
+    MOJOSHADER_constant *constants;
+
+    /*
      * The number of elements pointed to by (samplers).
      */
     int sampler_count;
--- a/testparse.c	Sat May 03 14:16:01 2008 -0400
+++ b/testparse.c	Sat May 03 15:28:30 2008 -0400
@@ -95,6 +95,40 @@
             } // for
         } // else
 
+        printf("CONSTANTS:");
+        if (pd->constant_count == 0)
+            printf(" (none.)\n");
+        else
+        {
+            int i;
+            printf("\n");
+            for (i = 0; i < pd->constant_count; i++)
+            {
+                static const char *typenames[] = { "float", "int", "bool" };
+                const MOJOSHADER_constant *c = &pd->constants[i];
+                printf("    * %d: %s (", c->index, typenames[(int) c->type]);
+                if (c->type == MOJOSHADER_UNIFORM_FLOAT)
+                {
+                    printf("%f %f %f %f", c->value.f[0], c->value.f[1],
+                                          c->value.f[2], c->value.f[3]);
+                } // if
+                else if (c->type == MOJOSHADER_UNIFORM_INT)
+                {
+                    printf("%d %d %d %d", c->value.i[0], c->value.i[1],
+                                          c->value.i[2], c->value.i[3]);
+                } // else if
+                else if (c->type == MOJOSHADER_UNIFORM_BOOL)
+                {
+                    printf("%s", c->value.b ? "true" : "false");
+                } // else if
+                else
+                {
+                    printf("???");
+                } // else
+                printf(")\n");
+            } // for
+        } // else
+
         printf("UNIFORMS:");
         if (pd->uniform_count == 0)
             printf(" (none.)\n");