[1/3] d3dx9: Add swizzle and writemask support to the shader assembler.

Matteo Bruni matteo.mystral at gmail.com
Thu Apr 8 07:20:48 CDT 2010


-------------- next part --------------
From 8fca6d279251ea247daaaa478a7c5244e7bc41ba Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sun, 4 Apr 2010 22:49:58 +0200
Subject: d3dx9: Add swizzle and writemask support to the shader assembler.

---
 dlls/d3dx9_36/asmshader.l        |   72 ++++++++++++++++++++++++++++
 dlls/d3dx9_36/asmshader.y        |   39 +++++++++++++++
 dlls/d3dx9_36/asmutils.c         |   95 +++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/d3dx9_36_private.h |   12 +++++
 4 files changed, 216 insertions(+), 2 deletions(-)

diff --git a/dlls/d3dx9_36/asmshader.l b/dlls/d3dx9_36/asmshader.l
index 99af380..c5402f2 100644
--- a/dlls/d3dx9_36/asmshader.l
+++ b/dlls/d3dx9_36/asmshader.l
@@ -34,6 +34,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
 %option prefix="asmshader_"
 %option noinput nounput
 
+/* Swizzles and writemasks consist of a dot and up to 4 x, y, z or w characters,
+ * or up to 4 a, r, g, b characters. There are different rules for swizzles and
+ * writemasks wrt repetition, those are handled in the grammar. color(argb) and
+ * coordinate(xyzw) components cannot be mixed.
+ */
+SWIZZLE                 \.(([w-z]+)|((a|r|g|b)+))
+
 /* Registers */
 REG_TEMP                r[0-9]+
 /* for relative addressing in the form o[x], v[x] and c[x] */
@@ -89,6 +96,71 @@ ps_2_0                  {return VER_PS20;       }
 ps_2_x                  {return VER_PS2X;       }
 ps_3_0                  {return VER_PS30;       }
 
+{SWIZZLE}               {
+                            unsigned char i;
+                            char last = 0;
+                            DWORD ret = 0;
+                            BOOL wmask_valid = TRUE;
+
+                            /* Ignore the '.', hence the +1 */
+                            asmshader_lval.swizzle_wmask.swizzle = text2swizzle(yytext + 1);
+                            if(asmshader_lval.swizzle_wmask.swizzle == SWIZZLE_ERR) {
+                                TRACE("Invalid swizzle/writemask %s\n", yytext);
+                                asmshader_lval.swizzle_wmask.writemask = 0;
+                                return SWIZZLE;
+                            }
+                            ret = 0;
+                            last = 0;
+                            for(i = 0; i < strlen(yytext + 1); i++) {
+                                switch(yytext[i + 1]) {
+                                    case 'x':
+                                    case 'r':
+                                        if(last == 'x' || last == 'y' || last == 'z' || last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_0;
+                                        last = 'x';
+                                        break;
+                                    case 'y':
+                                    case 'g':
+                                        if(last == 'y' || last == 'z' || last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_1;
+                                        last = 'y';
+                                        break;
+                                    case 'z':
+                                    case 'b':
+                                        if(last == 'z' || last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_2;
+                                        last = 'z';
+                                        break;
+                                    case 'w':
+                                    case 'a':
+                                        if(last == 'w') {
+                                            wmask_valid = FALSE;
+                                            break;
+                                        }
+                                        ret |= BWRITERSP_WRITEMASK_3;
+                                        last = 'w';
+                                        break;
+                                }
+                            }
+                            if(wmask_valid) {
+                                TRACE("Swizzle/Writemask string is a valid writemask\n");
+                                asmshader_lval.swizzle_wmask.writemask = ret;
+                            } else {
+                                TRACE("Swizzle/Writemask string is not a valid writemask\n");
+                                asmshader_lval.swizzle_wmask.writemask = 0;
+                            }
+                            return SWIZZLE;
+                        }
+
 {COMMA}                 {return yytext[0];          }
 -                       {return yytext[0];          }
 \(                      {return yytext[0];          }
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
index 93741b6..b379d74 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -82,12 +82,15 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
 %token VER_PS2X
 %token VER_PS30
 
+/* Misc stuff */
+%token <swizzle_wmask> SWIZZLE
 
 %type <reg> dreg_name
 %type <reg> dreg
 %type <reg> sreg_name
 %type <reg> sreg
 %type <swizzle> swizzle
+%type <writemask> writemask
 %type <modshift> omods
 %type <rel_reg> rel_reg
 %type <sregs> sregs
@@ -202,17 +205,53 @@ dreg:                 dreg_name rel_reg
                                 $$.srcmod = BWRITERSPSM_NONE;
                                 set_rel_reg(&$$, &$2);
                             }
+                    | dreg_name writemask
+                            {
+                                $$.regnum = $1.regnum;
+                                $$.type = $1.type;
+                                $$.writemask = $2;
+                                $$.srcmod = BWRITERSPSM_NONE;
+                                $$.rel_reg = NULL;
+                            }
 
 dreg_name:            REG_TEMP
                         {
                             $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
                         }
 
+writemask:            SWIZZLE
+                        {
+                            TRACE("Got a writemask\n");
+                            if($1.writemask == 0) {
+                                asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
+                                                  asm_ctx.line_no);
+                                set_parse_status(&asm_ctx, PARSE_ERR);
+                                /* Provide a correct writemask to prevent following complaints */
+                                $$ = BWRITERSP_WRITEMASK_ALL;
+                            } else {
+                                $$ = $1.writemask;
+                            }
+                        }
+
 swizzle:              /* empty */
                         {
                             $$ = BWRITERVS_NOSWIZZLE;
                             TRACE("Default swizzle: %08x\n", $$);
                         }
+                    | SWIZZLE
+                        {
+                            if($1.swizzle == SWIZZLE_ERR) {
+                                asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
+                                                  asm_ctx.line_no);
+                                set_parse_status(&asm_ctx, PARSE_ERR);
+                                /* Provide a correct swizzle to prevent following complaints */
+                                $$ = BWRITERVS_NOSWIZZLE;
+                            }
+                            else {
+                                TRACE("Got a swizzle: %08x\n", $1.swizzle);
+                                $$ = $1.swizzle;
+                            }
+                        }
 
 omods:                 /* Empty */
                         {
diff --git a/dlls/d3dx9_36/asmutils.c b/dlls/d3dx9_36/asmutils.c
index facb2af..7ed2408 100644
--- a/dlls/d3dx9_36/asmutils.c
+++ b/dlls/d3dx9_36/asmutils.c
@@ -99,14 +99,66 @@ static const char *get_regname(const struct shader_reg *reg, shader_type st) {
     }
 }
 
+const char *debug_print_writemask(DWORD mask) {
+    char ret[6];
+    unsigned char pos = 1;
+
+    if(mask == BWRITERSP_WRITEMASK_ALL) return "";
+    ret[0] = '.';
+    if(mask & BWRITERSP_WRITEMASK_0) ret[pos++] = 'x';
+    if(mask & BWRITERSP_WRITEMASK_1) ret[pos++] = 'y';
+    if(mask & BWRITERSP_WRITEMASK_2) ret[pos++] = 'z';
+    if(mask & BWRITERSP_WRITEMASK_3) ret[pos++] = 'w';
+    ret[pos] = 0;
+    return wine_dbg_sprintf("%s", ret);
+}
+
 const char *debug_print_dstreg(const struct shader_reg *reg, shader_type st) {
-    return get_regname(reg, st);
+    return wine_dbg_sprintf("%s%s", get_regname(reg, st),
+                            debug_print_writemask(reg->writemask));
+}
+
+const char *debug_print_swizzle(DWORD arg) {
+    char ret[6];
+    unsigned int i;
+    DWORD swizzle[4];
+
+    switch(arg) {
+        case BWRITERVS_NOSWIZZLE:
+            return "";
+        case BWRITERVS_SWIZZLE_X:
+            return ".x";
+        case BWRITERVS_SWIZZLE_Y:
+            return ".y";
+        case BWRITERVS_SWIZZLE_Z:
+            return ".z";
+        case BWRITERVS_SWIZZLE_W:
+            return ".w";
+    }
+
+    swizzle[0] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 0)) & 0x03;
+    swizzle[1] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 2)) & 0x03;
+    swizzle[2] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 4)) & 0x03;
+    swizzle[3] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 6)) & 0x03;
+
+    ret[0] = '.';
+    for(i = 0; i < 4; i++) {
+        switch(swizzle[i]) {
+            case 0: ret[1 + i] = 'x'; break;
+            case 1: ret[1 + i] = 'y'; break;
+            case 2: ret[1 + i] = 'z'; break;
+            case 3: ret[1 + i] = 'w'; break;
+        }
+    }
+    ret[5] = '\0';
+    return wine_dbg_sprintf("%s", ret);
 }
 
 const char *debug_print_srcreg(const struct shader_reg *reg, shader_type st) {
     switch(reg->srcmod) {
         case BWRITERSPSM_NONE:
-            return get_regname(reg, st);
+            return wine_dbg_sprintf("%s%s", get_regname(reg, st),
+                                    debug_print_swizzle(reg->swizzle));
     }
     return "Unknown modifier";
 }
@@ -118,3 +170,42 @@ const char *debug_print_opcode(DWORD opcode) {
         default:                      return "unknown";
     }
 }
+
+DWORD text2swizzle(const char *text) {
+    DWORD ret = 0;
+    char last = 0;
+    unsigned int i, len = strlen(text);
+
+    if(len > 4){
+        TRACE("Invalid swizzle %s\n", text);
+        return SWIZZLE_ERR;
+    }
+
+    for(i = 0; i < 4; i++) {
+        if(i < len) {
+            last = text[i];
+        }
+        switch(last) {
+            case 'x':
+            case 'r':
+                ret |= (BWRITERVS_X_X << (2 * i));
+                break;
+            case 'y':
+            case 'g':
+                ret |= (BWRITERVS_X_Y << (2 * i));
+                break;
+            case 'z':
+            case 'b':
+                ret |= (BWRITERVS_X_Z << (2 * i));
+                break;
+            case 'w':
+            case 'a':
+                ret |= (BWRITERVS_X_W << (2 * i));
+                break;
+            default:
+                TRACE("Unexpected swizzle character %c\n", last);
+                return SWIZZLE_ERR;
+        }
+    }
+    return ret;
+}
diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index 275b153..9d50b80 100644
--- a/dlls/d3dx9_36/d3dx9_36_private.h
+++ b/dlls/d3dx9_36/d3dx9_36_private.h
@@ -342,6 +342,8 @@ struct bc_writer {
 /* Debug utility routines */
 const char *debug_print_dstreg(const struct shader_reg *reg, shader_type st);
 const char *debug_print_srcreg(const struct shader_reg *reg, shader_type st);
+const char *debug_print_swizzle(DWORD swizzle);
+const char *debug_print_writemask(DWORD mask);
 const char *debug_print_opcode(DWORD opcode);
 
 /* Utilities for internal->d3d constant mapping */
@@ -350,6 +352,11 @@ DWORD d3d9_writemask(DWORD bwriter_writemask);
 DWORD d3d9_register(DWORD bwriter_register);
 DWORD d3d9_opcode(DWORD bwriter_opcode);
 
+/* Misc utility functions */
+#define SWIZZLE_ERR ~0U
+DWORD text2swizzle(const char *text);
+
+
 /*
   Enumerations and defines used in the bytecode writer
   intermediate representation
@@ -407,6 +414,11 @@ typedef enum _BWRITERSHADER_PARAM_SRCMOD_TYPE {
 
 #define BWRITERVS_NOSWIZZLE (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_W)
 
+#define BWRITERVS_SWIZZLE_X (BWRITERVS_X_X | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X)
+#define BWRITERVS_SWIZZLE_Y (BWRITERVS_X_Y | BWRITERVS_Y_Y | BWRITERVS_Z_Y | BWRITERVS_W_Y)
+#define BWRITERVS_SWIZZLE_Z (BWRITERVS_X_Z | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z)
+#define BWRITERVS_SWIZZLE_W (BWRITERVS_X_W | BWRITERVS_Y_W | BWRITERVS_Z_W | BWRITERVS_W_W)
+
 struct bwriter_shader *SlAssembleShader(const char *text, char **messages);
 DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result);
 void SlDeleteShader(struct bwriter_shader *shader);
-- 
1.6.4.4


More information about the wine-patches mailing list