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

Matteo Bruni matteo.mystral at gmail.com
Wed Apr 21 11:08:42 CDT 2010


Hi,
I've modified the swizzle/writemask parsing to better split the two. I
couldn't write the writemask rule as a list of accepted strings, as
they are too many (native accepts mixed [xyzw] and [rgba] in the same
writemask, test included), so I had to recur to the COMPONENT token
here too.
-------------- next part --------------
From bdcf52d8552b5d0250f4f33f3dca42fd5ad62fc7 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Wed, 21 Apr 2010 16:15:46 +0200
Subject: d3dx9: Add swizzle and writemask support to the shader assembler.

---
 dlls/d3dx9_36/asmshader.l        |   30 +++++++++++
 dlls/d3dx9_36/asmshader.y        |  100 ++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/asmutils.c         |   56 ++++++++++++++++++++-
 dlls/d3dx9_36/d3dx9_36_private.h |   10 ++++
 dlls/d3dx9_36/tests/asm.c        |   11 ++++
 5 files changed, 202 insertions(+), 5 deletions(-)

diff --git a/dlls/d3dx9_36/asmshader.l b/dlls/d3dx9_36/asmshader.l
index 99af380..ad1efab 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.
+ */
+DOT                     \.
+COMPONENT               [xyzw]|[rgba]
+
 /* Registers */
 REG_TEMP                r[0-9]+
 /* for relative addressing in the form o[x], v[x] and c[x] */
@@ -89,6 +96,29 @@ ps_2_0                  {return VER_PS20;       }
 ps_2_x                  {return VER_PS2X;       }
 ps_3_0                  {return VER_PS30;       }
 
+{DOT}                   {return yytext[0];      }
+{COMPONENT}             {
+                            switch(yytext[0]) {
+                                case 'x':
+                                case 'r':
+                                    asmshader_lval.component = 0;
+                                    break;
+                                case 'y':
+                                case 'g':
+                                    asmshader_lval.component = 1;
+                                    break;
+                                case 'z':
+                                case 'b':
+                                    asmshader_lval.component = 2;
+                                    break;
+                                case 'w':
+                                case 'a':
+                                    asmshader_lval.component = 3;
+                                    break;
+                            }
+                            return COMPONENT;
+                        }
+
 {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..e0117c6 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -45,13 +45,19 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
 %union {
     unsigned int        regnum;
     struct shader_reg   reg;
+    DWORD               writemask;
     struct {
-        DWORD           swizzle;
         DWORD           writemask;
-    } swizzle_wmask;
-    DWORD               writemask;
+        DWORD           idx;
+        DWORD           last;
+    } wm_components;
     DWORD               swizzle;
     struct {
+        DWORD           swizzle;
+        DWORD           idx;
+    } sw_components;
+    DWORD               component;
+    struct {
         DWORD           mod;
         DWORD           shift;
     } modshift;
@@ -82,12 +88,17 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
 %token VER_PS2X
 %token VER_PS30
 
+/* Misc stuff */
+%token <component> COMPONENT
 
 %type <reg> dreg_name
 %type <reg> dreg
 %type <reg> sreg_name
 %type <reg> sreg
+%type <writemask> writemask
+%type <wm_components> wm_components
 %type <swizzle> swizzle
+%type <sw_components> sw_components
 %type <modshift> omods
 %type <rel_reg> rel_reg
 %type <sregs> sregs
@@ -202,17 +213,100 @@ 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:            '.' wm_components
+                        {
+                            if($2.writemask == SWIZZLE_ERR) {
+                                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 {
+                                $$ = $2.writemask;
+                                TRACE("Writemask: %x\n", $$);
+                            }
+                        }
+
+wm_components:        COMPONENT
+                        {
+                            $$.writemask = 1 << $1;
+                            $$.last = $1;
+                            $$.idx = 1;
+                        }
+                    | wm_components COMPONENT
+                        {
+                            if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
+                                /* Wrong writemask */
+                                $$.writemask = SWIZZLE_ERR;
+                            else {
+                                if($2 <= $1.last)
+                                    $$.writemask = SWIZZLE_ERR;
+                                else {
+                                    $$.writemask = $1.writemask | (1 << $2);
+                                    $$.idx = $1.idx + 1;
+                                }
+                            }
+                        }
+
 swizzle:              /* empty */
                         {
                             $$ = BWRITERVS_NOSWIZZLE;
                             TRACE("Default swizzle: %08x\n", $$);
                         }
+                    | '.' sw_components
+                        {
+                            if($2.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 {
+                                DWORD last, i;
+
+                                $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
+                                /* Fill the swizzle by extending the last component */
+                                last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
+                                for(i = $2.idx; i < 4; i++){
+                                    $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
+                                }
+                                TRACE("Got a swizzle: %08x\n", $$);
+                            }
+                        }
+
+sw_components:        COMPONENT
+                        {
+                            $$.swizzle = $1;
+                            $$.idx = 1;
+                        }
+                    | sw_components COMPONENT
+                        {
+                            if($1.idx == 4) {
+                                /* Too many sw_components */
+                                $$.swizzle = SWIZZLE_ERR;
+                                $$.idx = 4;
+                            }
+                            else {
+                                $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
+                                $$.idx = $1.idx + 1;
+                            }
+                        }
 
 omods:                 /* Empty */
                         {
diff --git a/dlls/d3dx9_36/asmutils.c b/dlls/d3dx9_36/asmutils.c
index facb2af..6fd186a 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";
 }
diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index 275b153..7146f99 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,9 @@ DWORD d3d9_writemask(DWORD bwriter_writemask);
 DWORD d3d9_register(DWORD bwriter_register);
 DWORD d3d9_opcode(DWORD bwriter_opcode);
 
+/* Used to signal an incorrect swizzle/writemask */
+#define SWIZZLE_ERR ~0U
+
 /*
   Enumerations and defines used in the bytecode writer
   intermediate representation
@@ -407,6 +412,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);
diff --git a/dlls/d3dx9_36/tests/asm.c b/dlls/d3dx9_36/tests/asm.c
index de29e45..6cf8e08 100644
--- a/dlls/d3dx9_36/tests/asm.c
+++ b/dlls/d3dx9_36/tests/asm.c
@@ -1058,6 +1058,17 @@ static void vs_3_0_test(void) {
             "mov r2, r1_abs\n",
             {0xfffe0300, 0x02000001, 0x800f0002, 0x8be40001, 0x0000ffff}
         },*/
+        {   /* shader 9 */
+            "vs_3_0\n"
+            "mov r2, r1.xygb\n",
+            {0xfffe0300, 0x02000001, 0x800f0002, 0x80940001, 0x0000ffff}
+        },
+        {   /* shader 10 */
+            "vs_3_0\n"
+            "mov r2.xyb, r1\n",
+            {0xfffe0300, 0x02000001, 0x80070002, 0x80e40001, 0x0000ffff}
+        },
+
     };
 
     exec_tests("vs_3_0", tests, sizeof(tests) / sizeof(tests[0]));
-- 
1.6.4.4


More information about the wine-patches mailing list