Allow sampler type remapping.
Allows workaround for Shader Model 1 not specifying what a sampler should be
in the bytecode itself.
--- a/mojoshader.c Sat May 19 01:56:29 2012 -0400
+++ b/mojoshader.c Tue May 29 02:43:24 2012 -0400
@@ -89,6 +89,8 @@
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 @@
} // 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
if (retval != NULL)
{
RegisterList *item = ctx->samplers.next;
- MOJOSHADER_samplerType type = MOJOSHADER_SAMPLER_2D;
int i;
memset(retval, '\0', len);
@@ -8793,26 +8822,7 @@
} // 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 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 @@
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;
--- a/mojoshader.h Sat May 19 01:56:29 2012 -0400
+++ b/mojoshader.h Tue May 29 02:43:24 2012 -0400
@@ -190,6 +190,21 @@
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 @@
* 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 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 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 @@
*
* (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 @@
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);
/*
--- a/mojoshader_assembler.c Sat May 19 01:56:29 2012 -0400
+++ b/mojoshader_assembler.c Tue May 29 02:43:24 2012 -0400
@@ -1671,7 +1671,7 @@
// 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);
--- a/mojoshader_effects.c Sat May 19 01:56:29 2012 -0400
+++ b/mojoshader_effects.c Tue May 29 02:43:24 2012 -0400
@@ -208,6 +208,8 @@
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 @@
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.
--- a/mojoshader_opengl.c Sat May 19 01:56:29 2012 -0400
+++ b/mojoshader_opengl.c Tue May 29 02:43:24 2012 -0400
@@ -1392,12 +1392,15 @@
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);
--- a/utils/finderrors.c Sat May 19 01:56:29 2012 -0400
+++ b/utils/finderrors.c Tue May 29 02:43:24 2012 -0400
@@ -112,7 +112,7 @@
} // 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
--- a/utils/testoutput.c Sat May 19 01:56:29 2012 -0400
+++ b/utils/testoutput.c Tue May 29 02:43:24 2012 -0400
@@ -16,7 +16,7 @@
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;
--- a/utils/testparse.c Sat May 19 01:56:29 2012 -0400
+++ b/utils/testparse.c Tue May 29 02:43:24 2012 -0400
@@ -482,7 +482,8 @@
(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 @@
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);