Skip to content

Commit

Permalink
Allow sampler type remapping.
Browse files Browse the repository at this point in the history
Allows workaround for Shader Model 1 not specifying what a sampler should be
 in the bytecode itself.
  • Loading branch information
icculus committed May 29, 2012
1 parent c41d6b4 commit daa96c9
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 38 deletions.
71 changes: 42 additions & 29 deletions mojoshader.c
Expand Up @@ -89,6 +89,8 @@ typedef struct Context
uint32 tokencount;
const MOJOSHADER_swizzle *swizzles;
unsigned int swizzles_count;
const MOJOSHADER_samplerMap *samplermap;
unsigned int samplermap_count;
Buffer *output;
Buffer *preflight;
Buffer *globals;
Expand Down Expand Up @@ -487,6 +489,16 @@ static void floatstr(Context *ctx, char *buf, size_t bufsize, float f,
} // else
} // floatstr

static inline TextureType cvtMojoToD3DSamplerType(const MOJOSHADER_samplerType type)
{
return (TextureType) (((int) type) + 2);
} // cvtMojoToD3DSamplerType

static inline MOJOSHADER_samplerType cvtD3DToMojoSamplerType(const TextureType type)
{
return (MOJOSHADER_samplerType) (((int) type) - 2);
} // cvtD3DToMojoSamplerType


// Deal with register lists... !!! FIXME: I sort of hate this.

Expand Down Expand Up @@ -627,13 +639,28 @@ static void add_attribute_register(Context *ctx, const RegisterType rtype,
ctx->uses_fog = 1; // note that we have to check this later.
} // add_attribute_register

static inline void add_sampler(Context *ctx, const RegisterType rtype,
const int regnum, const TextureType ttype,
const int texbem)
static inline void add_sampler(Context *ctx, const int regnum,
TextureType ttype, const int texbem)
{
const RegisterType rtype = REG_TYPE_SAMPLER;

// !!! FIXME: make sure it doesn't exist?
// !!! FIXME: (ps_1_1 assume we can add it multiple times...)
RegisterList *item = reglist_insert(ctx, &ctx->samplers, rtype, regnum);

if (ctx->samplermap != NULL)
{
unsigned int i;
for (i = 0; i < ctx->samplermap_count; i++)
{
if (ctx->samplermap[i].index == regnum)
{
ttype = cvtMojoToD3DSamplerType(ctx->samplermap[i].type);
break;
} // if
} // for
} // if

item->index = (int) ttype;
item->misc |= texbem;
} // add_sampler
Expand Down Expand Up @@ -7011,7 +7038,7 @@ static void state_DCL(Context *ctx)
else if (shader_is_pixel(ctx))
{
if (regtype == REG_TYPE_SAMPLER)
add_sampler(ctx, regtype, regnum, (TextureType) ctx->dwords[0], 0);
add_sampler(ctx, regnum, (TextureType) ctx->dwords[0], 0);
else
{
const MOJOSHADER_usage usage = (MOJOSHADER_usage) ctx->dwords[0];
Expand Down Expand Up @@ -7438,7 +7465,7 @@ static void state_texops(Context *ctx, const char *opcode,
if (dims)
{
TextureType ttyp = (dims == 2) ? TEXTURE_TYPE_2D : TEXTURE_TYPE_VOLUME;
add_sampler(ctx, REG_TYPE_SAMPLER, dst->regnum, ttyp, texbem);
add_sampler(ctx, dst->regnum, ttyp, texbem);
} // if

add_attribute_register(ctx, REG_TYPE_TEXTURE, dst->regnum,
Expand Down Expand Up @@ -7625,13 +7652,12 @@ static void state_TEXLD(Context *ctx)

else
{
// !!! FIXME: cubemaps? can you do that in ps_1_1?
// !!! FIXME: add (other?) checks for ps_1_1 version here...
const DestArgInfo *info = &ctx->dest_arg;
const int sampler = info->regnum;
if (info->regtype != REG_TYPE_TEXTURE)
fail(ctx, "TEX param must be a texture register");
add_sampler(ctx, REG_TYPE_SAMPLER, sampler, TEXTURE_TYPE_2D, 0);
add_sampler(ctx, sampler, TEXTURE_TYPE_2D, 0);
add_attribute_register(ctx, REG_TYPE_TEXTURE, sampler,
MOJOSHADER_USAGE_TEXCOORD, sampler, 0xF, 0);
} // else
Expand Down Expand Up @@ -8490,6 +8516,8 @@ static Context *build_context(const char *profile,
const unsigned int bufsize,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
{
if (m == NULL) m = MOJOSHADER_internal_malloc;
Expand All @@ -8508,6 +8536,8 @@ static Context *build_context(const char *profile,
ctx->tokencount = bufsize / sizeof (uint32);
ctx->swizzles = swiz;
ctx->swizzles_count = swizcount;
ctx->samplermap = smap;
ctx->samplermap_count = smapcount;
ctx->endline = ENDLINE_STR;
ctx->endline_len = strlen(ctx->endline);
ctx->last_address_reg_component = -1;
Expand Down Expand Up @@ -8779,7 +8809,6 @@ static MOJOSHADER_sampler *build_samplers(Context *ctx)
if (retval != NULL)
{
RegisterList *item = ctx->samplers.next;
MOJOSHADER_samplerType type = MOJOSHADER_SAMPLER_2D;
int i;

memset(retval, '\0', len);
Expand All @@ -8793,26 +8822,7 @@ static MOJOSHADER_sampler *build_samplers(Context *ctx)
} // if

assert(item->regtype == REG_TYPE_SAMPLER);
switch ((const TextureType) item->index)
{
case TEXTURE_TYPE_2D:
type = MOJOSHADER_SAMPLER_2D;
break;

case TEXTURE_TYPE_CUBE:
type = MOJOSHADER_SAMPLER_CUBE;
break;

case TEXTURE_TYPE_VOLUME:
type = MOJOSHADER_SAMPLER_VOLUME;
break;

default:
fail(ctx, "Unknown sampler type");
break;
} // switch

retval[i].type = type;
retval[i].type = cvtD3DToMojoSamplerType((TextureType) item->index);
retval[i].index = item->regnum;
retval[i].name = alloc_varname(ctx, item);
retval[i].texbem = (item->misc != 0) ? 1 : 0;
Expand Down Expand Up @@ -9285,6 +9295,8 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
const unsigned int bufsize,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f, void *d)
{
Expand All @@ -9296,7 +9308,8 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
if ( ((m == NULL) && (f != NULL)) || ((m != NULL) && (f == NULL)) )
return &MOJOSHADER_out_of_mem_data; // supply both or neither.

ctx = build_context(profile, tokenbuf, bufsize, swiz, swizcount, m, f, d);
ctx = build_context(profile, tokenbuf, bufsize, swiz, swizcount,
smap, smapcount, m, f, d);
if (ctx == NULL)
return &MOJOSHADER_out_of_mem_data;

Expand Down
38 changes: 36 additions & 2 deletions mojoshader.h
Expand Up @@ -190,6 +190,21 @@ typedef struct MOJOSHADER_sampler
int texbem;
} MOJOSHADER_sampler;


/*
* This struct is used if you have to force a sampler to a specific type.
* Generally, you can ignore this, but if you have, say, a ps_1_1
* shader, you might need to specify what the samplers are meant to be
* to get correct results, as Shader Model 1 samples textures according
* to what is bound to a sampler at the moment instead of what the shader
* is hardcoded to expect.
*/
typedef struct MOJOSHADER_samplerMap
{
int index;
MOJOSHADER_samplerType type;
} MOJOSHADER_samplerMap;

/*
* Data types for attributes. See MOJOSHADER_attribute for more information.
*/
Expand Down Expand Up @@ -695,6 +710,18 @@ int MOJOSHADER_maxShaderModel(const char *profile);
* input register in the code would produce reg.ywzx, that swizzle would
* change it to reg.wzxy ... (swiz) can be NULL.
*
* You can force the shader to expect samplers of certain types. Generally
* you don't need this, as Shader Model 2 and later always specify what they
* expect samplers to be (2D, cubemap, etc). Shader Model 1, however, just
* uses whatever is bound to a given sampler at draw time, but this doesn't
* work in OpenGL, etc. In these cases, MojoShader will default to
* 2D texture sampling, which works 75% of the time, but if you really
* needed something else, you'll need to specify it here. This can also be
* used, at your own risk, to override DCL opcodes in shaders: if the
* shader explicit says 2D, but you want Cubemap, for example, you can use
* this to override. If you aren't sure about any of this stuff, you can
* almost certainly ignore it: (smap) can be NULL.
*
* This function is thread safe, so long as (m) and (f) are too, and that
* (tokenbuf) remains intact for the duration of the call. This allows you
* to parse several shaders on separate CPU cores at the same time.
Expand All @@ -704,6 +731,8 @@ const MOJOSHADER_parseData *MOJOSHADER_parse(const char *profile,
const unsigned int bufsize,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f,
void *d);
Expand Down Expand Up @@ -854,6 +883,8 @@ const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
const unsigned int _len,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f,
void *d);
Expand Down Expand Up @@ -2634,7 +2665,8 @@ int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type);
*
* (tokenbuf) is a buffer of Direct3D shader bytecode.
* (bufsize) is the size, in bytes, of the bytecode buffer.
* (swiz) and (swizcount) are passed to MOJOSHADER_parse() unmolested.
* (swiz), (swizcount), (smap), and (smapcount) are passed to
* MOJOSHADER_parse() unmolested.
*
* Returns NULL on error, or a shader handle on success.
*
Expand All @@ -2650,7 +2682,9 @@ int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type);
MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
const unsigned int bufsize,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount);
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount);


/*
Expand Down
2 changes: 1 addition & 1 deletion mojoshader_assembler.c
Expand Up @@ -1671,7 +1671,7 @@ static const MOJOSHADER_parseData *build_final_assembly(Context *ctx)
// like setting up the uniforms list, etc.
MOJOSHADER_parseData *retval = (MOJOSHADER_parseData *)
MOJOSHADER_parse(MOJOSHADER_PROFILE_BYTECODE,
bytecode, output_len, NULL, 0,
bytecode, output_len, NULL, 0, NULL, 0,
ctx->malloc, ctx->free, ctx->malloc_data);
Free(ctx, bytecode);

Expand Down
5 changes: 4 additions & 1 deletion mojoshader_effects.c
Expand Up @@ -208,6 +208,8 @@ const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
const unsigned int _len,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount,
MOJOSHADER_malloc m,
MOJOSHADER_free f,
void *d)
Expand Down Expand Up @@ -515,7 +517,8 @@ const MOJOSHADER_effect *MOJOSHADER_parseEffect(const char *profile,
shader->technique = technique;
shader->pass = pass;
shader->shader = MOJOSHADER_parse(profile, ptr, shadersize,
swiz, swizcount, m, f, d);
swiz, swizcount, smap, smapcount,
m, f, d);

// !!! FIXME: check for errors.

Expand Down
5 changes: 4 additions & 1 deletion mojoshader_opengl.c
Expand Up @@ -1392,12 +1392,15 @@ int MOJOSHADER_glMaxUniforms(MOJOSHADER_shaderType shader_type)
MOJOSHADER_glShader *MOJOSHADER_glCompileShader(const unsigned char *tokenbuf,
const unsigned int bufsize,
const MOJOSHADER_swizzle *swiz,
const unsigned int swizcount)
const unsigned int swizcount,
const MOJOSHADER_samplerMap *smap,
const unsigned int smapcount)
{
MOJOSHADER_glShader *retval = NULL;
GLuint shader = 0;
const MOJOSHADER_parseData *pd = MOJOSHADER_parse(ctx->profile, tokenbuf,
bufsize, swiz, swizcount,
smap, smapcount,
ctx->malloc_fn,
ctx->free_fn,
ctx->malloc_data);
Expand Down
2 changes: 1 addition & 1 deletion utils/finderrors.c
Expand Up @@ -112,7 +112,7 @@ static int do_file(const char *profile, const char *dname, const char *fn, int *
} // if

#if FINDERRORS_COMPILE_SHADERS
MOJOSHADER_glShader *shader = MOJOSHADER_glCompileShader(buf, rc, NULL, 0);
MOJOSHADER_glShader *shader = MOJOSHADER_glCompileShader(buf, rc, NULL, 0, NULL, 0);
if (shader == NULL)
report("FAIL: %s %s\n", fname, MOJOSHADER_glGetError());
else
Expand Down
2 changes: 1 addition & 1 deletion utils/testoutput.c
Expand Up @@ -16,7 +16,7 @@ static int do_parse(const unsigned char *buf, const int len, const char *prof)
const MOJOSHADER_parseData *pd;
int retval = 0;

pd = MOJOSHADER_parse(prof, buf, len, NULL, 0, NULL, NULL, NULL);
pd = MOJOSHADER_parse(prof, buf, len, NULL, 0, NULL, 0, NULL, NULL, NULL);
if (pd->error_count > 0)
{
int i;
Expand Down
6 changes: 4 additions & 2 deletions utils/testparse.c
Expand Up @@ -482,7 +482,8 @@ static int do_parse(const char *fname, const unsigned char *buf,
(buf[2] == 0xFF) && (buf[3] == 0xFE) )
{
const MOJOSHADER_effect *effect;
effect = MOJOSHADER_parseEffect(prof, buf, len, 0, 0, Malloc, Free, 0);
effect = MOJOSHADER_parseEffect(prof, buf, len, NULL, 0,
NULL, 0, Malloc, Free, 0);
retval = (effect->error_count == 0);
printf("EFFECT: %s\n", fname);
print_effect(fname, effect, 1);
Expand All @@ -492,7 +493,8 @@ static int do_parse(const char *fname, const unsigned char *buf,
else // do it as a regular compiled shader.
{
const MOJOSHADER_parseData *pd;
pd = MOJOSHADER_parse(prof, buf, len, NULL, 0, Malloc, Free, NULL);
pd = MOJOSHADER_parse(prof, buf, len, NULL, 0,
NULL, 0, Malloc, Free, NULL);
retval = (pd->error_count == 0);
printf("SHADER: %s\n", fname);
print_shader(fname, pd, 1);
Expand Down

0 comments on commit daa96c9

Please sign in to comment.