Parse symbols in the CTAB, export them in MOJOSHADER_parseData.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 29 May 2011 17:34:12 -0400
changeset 1028 74e7ee46ac93
parent 1027 3fe5609f3620
child 1029 5af5af0210df
Parse symbols in the CTAB, export them in MOJOSHADER_parseData.
mojoshader.c
mojoshader.h
mojoshader_compiler.c
utils/testparse.c
--- a/mojoshader.c	Sun May 29 11:58:40 2011 -0400
+++ b/mojoshader.c	Sun May 29 17:34:12 2011 -0400
@@ -137,6 +137,8 @@
     int predicated;
     int glsl_generated_lit_opcode;
     int glsl_generated_texldd_setup;
+    int symbol_count;
+    MOJOSHADER_symbol *symbols;
 
 #if SUPPORT_PROFILE_ARB1_NV
     int profile_supports_nv2;
@@ -6856,14 +6858,93 @@
 } // parse_version_token
 
 
+static int parse_ctab_string(const uint8 *start, const uint32 bytes,
+                             const uint32 name)
+{
+    // Make sure strings don't overflow the CTAB buffer...
+    if (name < bytes)
+    {
+        int i;
+        const int slenmax = bytes - name;
+        const char *namestr = (const char *) (start + name);
+        for (i = 0; i < slenmax; i++)
+        {
+            if (namestr[i] == '\0')
+                return 1;  // it's okay.
+        } // for
+    } // if
+
+    return 0;  // overflowed.
+} // parse_ctab_string
+
+
+static int parse_ctab_typeinfo(Context *ctx, const uint8 *start,
+                               const uint32 bytes, const uint32 pos,
+                               MOJOSHADER_symbolTypeInfo *info)
+{
+    if ((pos + 16) >= bytes)
+        return 0;  // corrupt CTAB.
+
+    const uint16 *typeptr = (const uint16 *) (start + pos);
+
+    info->parameter_class = (MOJOSHADER_symbolClass) SWAP16(typeptr[0]);
+    info->parameter_type = (MOJOSHADER_symbolType) SWAP16(typeptr[1]);
+    info->rows = (unsigned int) SWAP16(typeptr[2]);
+    info->columns = (unsigned int) SWAP16(typeptr[3]);
+    info->elements = (unsigned int) SWAP16(typeptr[4]);
+    info->member_count = (unsigned int) SWAP16(typeptr[5]);
+
+    if ((pos + 16 + (info->member_count * 8)) >= bytes)
+        return 0;  // corrupt CTAB.
+
+    const size_t len = sizeof (MOJOSHADER_symbolStructMember) *
+                        info->member_count;
+
+    info->members = (MOJOSHADER_symbolStructMember *) Malloc(ctx, len);
+    if (info->members == NULL)
+        return 1;  // we'll check ctx->out_of_memory later.
+    memset(info->members, '\0', len);
+
+    int i;
+    const uint32 *member = (const uint32 *)((const uint8 *) (&typeptr[6]));
+    for (i = 0; i < info->member_count; i++)
+    {
+        MOJOSHADER_symbolStructMember *mbr = &info->members[i];
+        const uint32 name = SWAP32(member[0]);
+        const uint32 memberinfopos = SWAP32(member[1]);
+        member += 2;
+
+        if (!parse_ctab_string(start, bytes, name))
+            return 0;  // info->members will be free()'d elsewhere.
+
+        mbr->name = StrDup(ctx, (const char *) (start + name));
+        if (mbr->name == NULL)
+            return 1;  // we'll check ctx->out_of_memory later.
+        if (!parse_ctab_typeinfo(ctx, start, bytes, memberinfopos, &mbr->info))
+            return 0;
+        if (ctx->out_of_memory)
+            return 1;  // drop out now.
+    } // for
+
+    return 1;
+} // parse_ctab_typeinfo
+
+
 // Microsoft's tools add a CTAB comment to all shaders. This is the
 //  "constant table," or specifically: D3DXSHADER_CONSTANTTABLE:
 //  http://msdn.microsoft.com/en-us/library/bb205440(VS.85).aspx
 // This may tell us high-level truths about an otherwise generic low-level
 //  registers, for instance, how large an array actually is, etc.
-// !!! FIXME: parse symbols.
 static void parse_constant_table(Context *ctx, const uint32 bytes)
 {
+    if (bytes < 32)
+    {
+        fail(ctx, "Truncated CTAB data");
+        return;
+    } // if
+
+    assert(ctx->have_ctab == 0);  // !!! FIXME: can you have more than one?
+
     const uint8 *start = (uint8 *) &ctx->tokens[2];
     const uint32 id = SWAP32(ctx->tokens[1]);
     const uint32 size = SWAP32(ctx->tokens[2]);
@@ -6877,7 +6958,7 @@
     if (id != CTAB_ID)
         return;  // not the constant table.
 
-    if (size != CTAB_SIZE)
+    if (size != CTAB_SIZE)  // !!! FIXME: should this fail()?
         return;  // only handle this version of the struct.
 
     if (version != ctx->version_token) goto corrupt_ctab;
@@ -6887,6 +6968,12 @@
 
     ctx->have_ctab = 1;
 
+    ctx->symbol_count = constants;
+    ctx->symbols = Malloc(ctx, sizeof (MOJOSHADER_symbol) * constants);
+    if (ctx->symbols == NULL)
+        return;
+    memset(ctx->symbols, '\0', sizeof (MOJOSHADER_symbol) * constants);
+
     for (i = 0; i < constants; i++)
     {
         const uint8 *ptr = start + constantinfo + (i * CINFO_SIZE);
@@ -6898,8 +6985,7 @@
         const uint32 defval = SWAP32(*((uint32 *) (ptr + 16)));
         MOJOSHADER_uniformType mojotype = MOJOSHADER_UNIFORM_UNKNOWN;
 
-        if (name >= bytes) goto corrupt_ctab;
-        if ((typeinf + 16) >= bytes) goto corrupt_ctab;
+        if (!parse_ctab_string(start, bytes, name)) goto corrupt_ctab;
         if (defval >= bytes) goto corrupt_ctab;
 
         switch (regset)
@@ -6927,6 +7013,21 @@
                 ctx->variables = item;
             } // if
         } // if
+
+        // Add the symbol.
+        const char *namecpy = StrDup(ctx, (const char *) (start + name));
+        if (namecpy == NULL)
+            return;
+
+        MOJOSHADER_symbol *sym = &ctx->symbols[i];
+        sym->name = namecpy;
+        sym->register_set = (MOJOSHADER_symbolRegisterSet) regset;
+        sym->register_index = (unsigned int) regidx;
+        sym->register_count = (unsigned int) regcnt;
+        if (!parse_ctab_typeinfo(ctx, start, bytes, typeinf, &sym->info))
+            goto corrupt_ctab;  // sym->name will get free()'d later.
+        else if (ctx->out_of_memory)
+            return;  // just bail now.
     } // for
 
     return;
@@ -6936,18 +7037,36 @@
 } // parse_constant_table
 
 
+static int is_comment_token(Context *ctx, const uint32 tok, uint32 *tokcount)
+{
+    const uint32 token = SWAP32(tok);
+    if ((token & 0xFFFF) == 0xFFFE)  // actually a comment token?
+    {
+        if ((token & 0x80000000) != 0)
+            fail(ctx, "comment token high bit must be zero.");  // so says msdn.
+        *tokcount = ((token >> 16) & 0xFFFF);
+        return 1;
+    } // if
+
+    return 0;
+} // is_comment_token
+
+
 static int parse_comment_token(Context *ctx)
 {
-    const uint32 token = SWAP32(*(ctx->tokens));
-    if ((token & 0xFFFF) != 0xFFFE)
-        return 0;  // not a comment token.
-    if ((token & 0x80000000) != 0)
-        fail(ctx, "comment token high bit must be zero.");  // so says msdn.
-
-    const uint32 commenttoks = ((token >> 16) & 0xFFFF);
-    if ((commenttoks >= 8) && (commenttoks < ctx->tokencount))
-        parse_constant_table(ctx, commenttoks * 4);
-    return commenttoks + 1;  // comment data plus the initial token.
+    uint32 commenttoks = 0;
+    if (is_comment_token(ctx, *ctx->tokens, &commenttoks))
+    {
+        if ((commenttoks >= 1) && (commenttoks < ctx->tokencount))
+        {
+            const uint32 id = SWAP32(ctx->tokens[1]);
+            if (id == CTAB_ID)
+                parse_constant_table(ctx, commenttoks * 4);
+        } // if
+        return commenttoks + 1;  // comment data plus the initial token.
+    } // if
+
+    return 0;  // not a comment token.
 } // parse_comment_token
 
 
@@ -7107,6 +7226,32 @@
 } // free_variable_list
 
 
+static void free_sym_typeinfo(MOJOSHADER_free f, void *d,
+                              MOJOSHADER_symbolTypeInfo *typeinfo)
+{
+    int i;
+    for (i = 0; i < typeinfo->member_count; i++)
+    {
+        f((void *) typeinfo->members[i].name, d);
+        free_sym_typeinfo(f, d, &typeinfo->members[i].info);
+    } // for
+    f((void *) typeinfo->members, d);
+} // free_sym_members
+
+
+static void free_symbols(MOJOSHADER_free f, void *d, MOJOSHADER_symbol *syms,
+                         const int symcount)
+{
+    int i;
+    for (i = 0; i < symcount; i++)
+    {
+        f((void *) syms[i].name, d);
+        free_sym_typeinfo(f, d, &syms[i].info);
+    } // for
+    f((void *) syms, d);
+} // free_symbols
+
+
 static void destroy_context(Context *ctx)
 {
     if (ctx != NULL)
@@ -7128,6 +7273,7 @@
         free_reglist(f, d, ctx->samplers.next);
         free_variable_list(f, d, ctx->variables);
         errorlist_destroy(ctx->errors);
+        free_symbols(f, d, ctx->symbols, ctx->symbol_count);
         f(ctx, d);
     } // if
 } // destroy_context
@@ -7507,6 +7653,11 @@
         retval->attributes = attributes;
         retval->swizzle_count = ctx->swizzles_count;
         retval->swizzles = swizzles;
+        retval->symbol_count = ctx->symbol_count;
+        retval->symbols = ctx->symbols;
+
+        ctx->symbols = NULL;  // we don't own this now, retval does.
+        ctx->symbol_count = 0;
     } // else
 
     retval->error_count = error_count;
@@ -7810,12 +7961,7 @@
         f((void *) data->samplers[i].name, d);
     f((void *) data->samplers, d);
 
-    for (i = 0; i < data->symbol_count; i++)
-    {
-        f((void *) data->symbols[i].name, d);
-        f((void *) data->symbols[i].default_value, d);
-    } // for
-    f((void *) data->symbols, d);
+    free_symbols(f, d, data->symbols, data->symbol_count);
 
     f(data, d);
 } // MOJOSHADER_freeParseData
--- a/mojoshader.h	Sun May 29 11:58:40 2011 -0400
+++ b/mojoshader.h	Sun May 29 17:34:12 2011 -0400
@@ -315,7 +315,6 @@
     unsigned int register_index;
     unsigned int register_count;
     MOJOSHADER_symbolTypeInfo info;
-    void *default_value;
 } MOJOSHADER_symbol;
 
 
--- a/mojoshader_compiler.c	Sun May 29 11:58:40 2011 -0400
+++ b/mojoshader_compiler.c	Sun May 29 17:34:12 2011 -0400
@@ -6280,7 +6280,7 @@
     for (i = 0; i < data->symbol_count; i++)
     {
         f((void *) data->symbols[i].name, d);
-        f((void *) data->symbols[i].default_value, d);
+        // !!! FIXME: this is missing stuff (including freeing substructs).
     } // for
     f((void *) data->symbols, d);
 
--- a/utils/testparse.c	Sun May 29 11:58:40 2011 -0400
+++ b/utils/testparse.c	Sun May 29 17:34:12 2011 -0400
@@ -64,6 +64,49 @@
 } // shader_type
 
 
+static void print_typeinfo(const MOJOSHADER_symbolTypeInfo *info,
+                           unsigned int indent)
+{
+    static const char *symclasses[] = {
+        "scalar", "vector", "row-major matrix",
+        "column-major matrix", "object", "struct"
+    };
+
+    static const char *symtypes[] = {
+        "void", "bool", "int", "float", "string", "texture",
+        "texture1d", "texture2d", "texture3d", "texturecube",
+        "sampler", "sampler1d", "sampler2d", "sampler3d",
+        "samplercube", "pixelshader", "vertexshader", "unsupported"
+    };
+
+    INDENT();
+    printf("      symbol class %s\n", symclasses[info->parameter_class]);
+    INDENT();
+    printf("      symbol type %s\n", symtypes[info->parameter_type]);
+    INDENT();
+    printf("      rows %u\n", info->rows);
+    INDENT();
+    printf("      columns %u\n", info->columns);
+    INDENT();
+    printf("      elements %u\n", info->elements);
+
+    if (info->member_count > 0)
+    {
+        int i;
+        INDENT(); printf("      MEMBERS:\n");
+        for (i = 0; i < info->member_count; i++)
+        {
+            const MOJOSHADER_symbolStructMember *member = &info->members[i];
+            INDENT(); printf("      MEMBERS:\n");
+            indent++;
+            INDENT(); printf("      * %d: \"%s\"\n", i, member->name);
+            print_typeinfo(&member->info, indent);
+            indent--;
+        } // for
+    } // if
+} // print_typeinfo
+
+
 static void print_shader(const char *fname, const MOJOSHADER_parseData *pd,
                          unsigned int indent)
 {
@@ -196,6 +239,29 @@
             } // for
         } // else
 
+        INDENT(); printf("SYMBOLS:");
+        if (pd->symbol_count == 0)
+            printf(" (none.)\n");
+        else
+        {
+            int i;
+            printf("\n");
+            for (i = 0; i < pd->symbol_count; i++)
+            {
+                static const char *regsets[] = {
+                    "bool", "int4", "float4", "sampler"
+                };
+
+                const MOJOSHADER_symbol *sym = &pd->symbols[i];
+                INDENT(); printf("    * %d: \"%s\"\n", i, sym->name);
+                INDENT(); printf("      register set %s\n", regsets[sym->register_set]);
+                INDENT(); printf("      register index %u\n", sym->register_index);
+                INDENT(); printf("      register count %u\n", sym->register_count);
+                print_typeinfo(&sym->info, indent);
+            } // for
+            printf("\n");
+        } // else
+
         if (pd->output != NULL)
         {
             int i;