Allow sampler type remapping.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 29 May 2012 02:43:24 -0400
changeset 1104 9147482e1ec7
parent 1103 8b7c29c019d5
child 1105 57e255c3b243
Allow sampler type remapping. Allows workaround for Shader Model 1 not specifying what a sampler should be in the bytecode itself.
mojoshader.c
mojoshader.h
mojoshader_assembler.c
mojoshader_effects.c
mojoshader_opengl.c
utils/finderrors.c
utils/testoutput.c
utils/testparse.c
--- 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);