Skip to content

Commit

Permalink
Relative addressing fixes.
Browse files Browse the repository at this point in the history
Emit correct code in GLSL profile, report arrays in MOJOSHADER_parseData().

--HG--
branch : trunk
  • Loading branch information
icculus committed May 5, 2008
1 parent 037ffd3 commit 0f94868
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 18 deletions.
131 changes: 114 additions & 17 deletions mojoshader.c
Expand Up @@ -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);

Expand All @@ -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;
Expand Down Expand Up @@ -293,6 +297,7 @@ typedef struct
} SourceArgInfo;


// !!! FIXME: get rid of this. use a bitfield instead.
typedef enum
{
// Specific to GLSL profile...
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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

Expand Down Expand Up @@ -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, \
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -4603,15 +4667,20 @@ 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;
int i;

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");
Expand All @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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++;
Expand Down
9 changes: 9 additions & 0 deletions mojoshader.h
Expand Up @@ -84,13 +84,22 @@ 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.
*/
typedef struct
{
MOJOSHADER_uniformType type;
int index;
int array_count;
const char *name;
} MOJOSHADER_uniform;

Expand Down
12 changes: 11 additions & 1 deletion testparse.c
Expand Up @@ -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");
Expand Down

0 comments on commit 0f94868

Please sign in to comment.