Parse symbols in the CTAB, export them in MOJOSHADER_parseData.
--- 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;