From daa96c9fa848b71a9f1cacdfa2bc73864562816d Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 29 May 2012 02:43:24 -0400 Subject: [PATCH] Allow sampler type remapping. Allows workaround for Shader Model 1 not specifying what a sampler should be in the bytecode itself. --- mojoshader.c | 71 +++++++++++++++++++++++++----------------- mojoshader.h | 38 ++++++++++++++++++++-- mojoshader_assembler.c | 2 +- mojoshader_effects.c | 5 ++- mojoshader_opengl.c | 5 ++- utils/finderrors.c | 2 +- utils/testoutput.c | 2 +- utils/testparse.c | 6 ++-- 8 files changed, 93 insertions(+), 38 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index 3e7bccf4..826dbdb9 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -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; @@ -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. @@ -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 @@ -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]; @@ -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, @@ -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 @@ -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; @@ -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; @@ -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); @@ -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; @@ -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) { @@ -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; diff --git a/mojoshader.h b/mojoshader.h index f702206a..6c09fec9 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -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. */ @@ -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. @@ -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); @@ -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); @@ -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. * @@ -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); /* diff --git a/mojoshader_assembler.c b/mojoshader_assembler.c index a755e3a6..24ae275e 100644 --- a/mojoshader_assembler.c +++ b/mojoshader_assembler.c @@ -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); diff --git a/mojoshader_effects.c b/mojoshader_effects.c index 8903e718..7aa5e317 100644 --- a/mojoshader_effects.c +++ b/mojoshader_effects.c @@ -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) @@ -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. diff --git a/mojoshader_opengl.c b/mojoshader_opengl.c index a26480b9..f525099c 100644 --- a/mojoshader_opengl.c +++ b/mojoshader_opengl.c @@ -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); diff --git a/utils/finderrors.c b/utils/finderrors.c index a49ecd2c..d90f34e4 100644 --- a/utils/finderrors.c +++ b/utils/finderrors.c @@ -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 diff --git a/utils/testoutput.c b/utils/testoutput.c index 26e55aa2..773b359f 100644 --- a/utils/testoutput.c +++ b/utils/testoutput.c @@ -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; diff --git a/utils/testparse.c b/utils/testparse.c index 404049e8..5fa59450 100644 --- a/utils/testparse.c +++ b/utils/testparse.c @@ -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); @@ -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);