From 0f94868e8d68598cf67f9adbb423cd9478da7634 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Mon, 5 May 2008 02:50:19 -0400 Subject: [PATCH] Relative addressing fixes. Emit correct code in GLSL profile, report arrays in MOJOSHADER_parseData(). --HG-- branch : trunk --- mojoshader.c | 131 ++++++++++++++++++++++++++++++++++++++++++++------- mojoshader.h | 9 ++++ testparse.c | 12 ++++- 3 files changed, 134 insertions(+), 18 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index b11d23b9..acaf028c 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -157,6 +157,9 @@ typedef void (*emit_finalize)(Context *ctx); // one emit function for global definitions in each profile. typedef void (*emit_global)(Context *ctx, RegisterType regtype, int regnum); +// one emit function for relative uniform arrays in each profile. +typedef void (*emit_relative)(Context *ctx, int size); + // one emit function for uniforms in each profile. typedef void (*emit_uniform)(Context *ctx, RegisterType regtype, int regnum); @@ -179,6 +182,7 @@ typedef struct emit_start start_emitter; emit_end end_emitter; emit_global global_emitter; + emit_relative relative_emitter; emit_uniform uniform_emitter; emit_sampler sampler_emitter; emit_attribute attribute_emitter; @@ -293,6 +297,7 @@ typedef struct } SourceArgInfo; +// !!! FIXME: get rid of this. use a bitfield instead. typedef enum { // Specific to GLSL profile... @@ -348,6 +353,8 @@ struct Context uint32 previous_opcode; ContextFlags flags; int predicated; + int max_constreg; + int uniform_array; int loops; int reps; int cmps; @@ -680,6 +687,9 @@ static inline void set_used_register(Context *ctx, const RegisterType regtype, const int regnum) { reglist_insert(ctx, &ctx->used_registers, regtype, regnum); + + if ((regtype == REG_TYPE_CONST) && (ctx->max_constreg < regnum)) + ctx->max_constreg = regnum; } // set_used_register static inline int get_used_register(Context *ctx, const RegisterType regtype, @@ -1122,6 +1132,12 @@ static void emit_D3D_global(Context *ctx, RegisterType regtype, int regnum) } // emit_D3D_global +static void emit_D3D_relative(Context *ctx, int size) +{ + // no-op. +} // emit_D3D_relative + + static void emit_D3D_uniform(Context *ctx, RegisterType regtype, int regnum) { // no-op. @@ -1499,6 +1515,7 @@ static void emit_PASSTHROUGH_start(Context *ctx) static void emit_PASSTHROUGH_end(Context *ctx) {} static void emit_PASSTHROUGH_finalize(Context *ctx) {} static void emit_PASSTHROUGH_global(Context *ctx, RegisterType t, int n) {} +static void emit_PASSTHROUGH_relative(Context *ctx, int size) {} 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_attribute(Context *ctx, RegisterType t, int n, @@ -1629,6 +1646,16 @@ static const char *get_GLSL_varname(Context *ctx, RegisterType rt, int regnum) return retval; } // get_GLSL_varname + +static const char *get_GLSL_const_array_varname(Context *ctx) +{ + const char *shader_type_str = get_shader_type_string(ctx); + char *retval = get_scratch_buffer(ctx); + snprintf(retval, SCRATCH_BUFFER_SIZE, "%s_const_array", shader_type_str); + return retval; +} // get_GLSL_const_array_varname + + static const char *get_GLSL_destarg_varname(Context *ctx) { const DestArgInfo *arg = &ctx->dest_arg; @@ -1822,30 +1849,36 @@ static char *make_GLSL_srcarg_string(Context *ctx, const int idx, } // switch - char regnum_str[16]; - const char *regtype_str = get_GLSL_register_string(ctx, arg->regtype, - arg->regnum, regnum_str, - sizeof (regnum_str)); + char regnum_str[16] = { '\0' }; + const char *regtype_str = NULL; - if (regtype_str == NULL) + // !!! FIXME: use get_GLSL_varname() instead? + const char *shader_type_str = get_shader_type_string(ctx); + if (!arg->relative) { - fail(ctx, "Unknown source register type."); - return ""; + regtype_str = get_GLSL_register_string(ctx, arg->regtype, + arg->regnum, regnum_str, + sizeof (regnum_str)); } // if const char *rel_lbracket = ""; + char rel_offset[32] = { '\0' }; const char *rel_rbracket = ""; char rel_swizzle[4] = { '\0' }; const char *rel_regtype_str = ""; if (arg->relative) { + // !!! FIXME: use get_GLSL_const_array_varname() instead? (can't, because of shader_type_str nonsense). + regtype_str = "const_array"; + rel_lbracket = "["; + if (arg->regnum != 0) + snprintf(rel_offset, sizeof (rel_offset), "%d + ", arg->regnum); + rel_regtype_str = get_GLSL_varname(ctx, arg->relative_regtype, + arg->relative_regnum); rel_swizzle[0] = '.'; rel_swizzle[1] = swizzle_channels[arg->relative_component]; rel_swizzle[2] = '\0'; - rel_lbracket = "["; rel_rbracket = "]"; - rel_regtype_str = get_GLSL_varname(ctx, arg->relative_regtype, - arg->relative_regnum); if (regtype_str == NULL) { @@ -1868,11 +1901,16 @@ static char *make_GLSL_srcarg_string(Context *ctx, const int idx, swiz_str[i] = '\0'; assert(i < sizeof (swiz_str)); - const char *shader_type_str = get_shader_type_string(ctx); + if (regtype_str == NULL) + { + fail(ctx, "Unknown source register type."); + return ""; + } // if + char *retval = get_scratch_buffer(ctx); - snprintf(retval, SCRATCH_BUFFER_SIZE, "%s%s_%s%s%s%s%s%s%s%s", + snprintf(retval, SCRATCH_BUFFER_SIZE, "%s%s_%s%s%s%s%s%s%s%s%s", premod_str, shader_type_str, regtype_str, regnum_str, - rel_lbracket, rel_regtype_str, rel_swizzle, + rel_lbracket, rel_offset, rel_regtype_str, rel_swizzle, rel_rbracket, swiz_str, postmod_str); // !!! FIXME: make sure the scratch buffer was large enough. return retval; @@ -2031,6 +2069,14 @@ static void emit_GLSL_global(Context *ctx, RegisterType regtype, int regnum) pop_output(ctx); } // emit_GLSL_global +static void emit_GLSL_relative(Context *ctx, int size) +{ + const char *varname = get_GLSL_const_array_varname(ctx); + push_output(ctx, &ctx->globals); + output_line(ctx, "uniform vec4 %s[%d];", varname, size); + pop_output(ctx); +} // emit_GLSL_relative + static void emit_GLSL_uniform(Context *ctx, RegisterType regtype, int regnum) { const char *varname = get_GLSL_varname(ctx, regtype, regnum); @@ -2044,7 +2090,17 @@ static void emit_GLSL_uniform(Context *ctx, RegisterType regtype, int regnum) } // switch push_output(ctx, &ctx->globals); - output_line(ctx, "uniform %s %s;", type, varname); + + if ((regtype == REG_TYPE_CONST) && (ctx->uniform_array)) + { + const char *constarray = get_GLSL_const_array_varname(ctx); + output_line(ctx, "#define %s %s[%d]", varname, constarray, regnum); + } // if + else + { + output_line(ctx, "uniform %s %s;", type, varname); + } // else + pop_output(ctx); } // emit_GLSL_uniform @@ -3058,6 +3114,7 @@ static void emit_GLSL_RESERVED(Context *ctx) emit_##prof##_start, \ emit_##prof##_end, \ emit_##prof##_global, \ + emit_##prof##_relative, \ emit_##prof##_uniform, \ emit_##prof##_sampler, \ emit_##prof##_attribute, \ @@ -3281,6 +3338,12 @@ static int parse_source_token(Context *ctx, SourceArgInfo *info) if (!replicate_swizzle(relswiz)) return fail(ctx, "relative address needs replicate swizzle"); + ctx->uniform_array = 1; + // !!! FIXME: maybe do some codeflow analysis to see if we can + // !!! FIXME: drop this value lower? + if (ctx->max_constreg < (info->regnum + 127)) + ctx->max_constreg = info->regnum + 127; + set_used_register(ctx, info->relative_regtype, info->relative_regnum); retval++; } // if @@ -4587,6 +4650,7 @@ static char *build_output(Context *ctx) static char *alloc_varname(Context *ctx, const RegisterList *reg) { + // !!! FIXME: may not be GLSL... const char *varname = get_GLSL_varname(ctx, reg->regtype, reg->regnum); const size_t len = strlen(varname) + 1; char *retval = (char *) Malloc(ctx, len); @@ -4603,6 +4667,7 @@ static MOJOSHADER_uniform *build_uniforms(Context *ctx) if (retval != NULL) { + MOJOSHADER_uniform *wptr = retval; RegisterList *item = ctx->uniforms.next; MOJOSHADER_uniformType type = MOJOSHADER_UNIFORM_FLOAT; int index = 0; @@ -4610,8 +4675,12 @@ static MOJOSHADER_uniform *build_uniforms(Context *ctx) memset(retval, '\0', len); + int array_items = 0; + for (i = 0; i < ctx->uniform_count; i++) { + int skip = 0; + if (item == NULL) { fail(ctx, "BUG: mismatched uniform list and count"); @@ -4622,6 +4691,11 @@ static MOJOSHADER_uniform *build_uniforms(Context *ctx) switch (item->regtype) { case REG_TYPE_CONST: + if (ctx->uniform_array) + { + skip = 1; + array_items++; + } // if type = MOJOSHADER_UNIFORM_FLOAT; break; @@ -4638,11 +4712,31 @@ static MOJOSHADER_uniform *build_uniforms(Context *ctx) break; } // switch - retval[i].type = type; - retval[i].index = index; - retval[i].name = alloc_varname(ctx, item); + + if (!skip) + { + wptr->type = type; + wptr->index = index; + wptr->name = alloc_varname(ctx, item); + wptr++; + } // if + item = item->next; } // for + + if (ctx->uniform_array) + { + char *name = (char *) Malloc(ctx, 16); // !!! FIXME + if (name != NULL) + { + strcpy(name, get_GLSL_const_array_varname(ctx)); // !!! FIXME + wptr->type = type; + wptr->index = index; + wptr->array_count = ctx->max_constreg + 1; + wptr->name = name; + ctx->uniform_count -= (array_items - 1); + } // if + } // if } // if return retval; @@ -4953,6 +5047,9 @@ static void process_definitions(Context *ctx) } // while // okay, now deal with uniforms... + if (ctx->uniform_array) + ctx->profile->relative_emitter(ctx, ctx->max_constreg + 1); + for (item = ctx->uniforms.next; item != NULL; item = item->next) { ctx->uniform_count++; diff --git a/mojoshader.h b/mojoshader.h index 4172834f..648be95e 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -84,6 +84,14 @@ typedef enum * 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. + * (array_count) means this is an array of uniforms...this happens in some + * profiles when we see a relative address ("c0[a0.x]", not the usual "c0"). + * In those cases, the shader was built to set some range of constant + * registers as an array. You should set this array with (array_count) + * elements from the constant register file, starting at (index) instead of + * 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! * (name) is a profile-specific variable name; it may be NULL if it isn't * applicable to the requested profile. */ @@ -91,6 +99,7 @@ typedef struct { MOJOSHADER_uniformType type; int index; + int array_count; const char *name; } MOJOSHADER_uniform; diff --git a/testparse.c b/testparse.c index de8ae277..6d0a504b 100644 --- a/testparse.c +++ b/testparse.c @@ -140,7 +140,17 @@ static int do_parse(const unsigned char *buf, const int len, const char *prof) { static const char *typenames[] = { "float", "int", "bool" }; const MOJOSHADER_uniform *u = &pd->uniforms[i]; - printf(" * %d: %s", u->index, typenames[(int) u->type]); + const char *arrayof = ""; + char arrayrange[64] = { '\0' }; + if (u->array_count > 0) + { + arrayof = "array["; + snprintf(arrayrange, sizeof (arrayrange), "%d] ", + u->array_count); + } // if + + printf(" * %d: %s%s%s", u->index, arrayof, arrayrange, + typenames[(int) u->type]); if (u->name != NULL) printf(" (\"%s\")", u->name); printf("\n");