d3dx9: Shader assembler vs_1_0 and vs_1_1 support.

Matteo Bruni matteo.mystral at gmail.com
Wed May 26 11:40:47 CDT 2010


This patch should be not so complex. Maybe it's still OK to be merged
now, before rc2 (no problems anyway)...
-------------- next part --------------
From 03fe69ab92997d526cb9e03528b7562eb4d46452 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sun, 16 Aug 2009 01:02:16 +0200
Subject: d3dx9: Shader assembler vs_1_0 and vs_1_1 support.

---
 dlls/d3dx9_36/asmparser.c        |  110 +++++++++++++++++++++++++++
 dlls/d3dx9_36/asmshader.y        |    6 +-
 dlls/d3dx9_36/bytecodewriter.c   |  156 +++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/d3dx9_36_private.h |    3 +
 dlls/d3dx9_36/tests/asm.c        |   15 ++--
 5 files changed, 278 insertions(+), 12 deletions(-)

diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
index 0242909..39240f3 100644
--- a/dlls/d3dx9_36/asmparser.c
+++ b/dlls/d3dx9_36/asmparser.c
@@ -407,6 +407,46 @@ static BOOL check_reg_type(const struct shader_reg *reg,
 }
 
 /* Native assembler doesn't do separate checks for src and dst registers */
+static const struct allowed_reg_type vs_1_reg_allowed[] = {
+    { BWRITERSPR_TEMP,         12,  FALSE },
+    { BWRITERSPR_INPUT,        16,  FALSE },
+    { BWRITERSPR_CONST,       ~0U,   TRUE },
+    { BWRITERSPR_ADDR,          1,  FALSE },
+    { BWRITERSPR_RASTOUT,       3,  FALSE }, /* oPos, oFog and oPts */
+    { BWRITERSPR_ATTROUT,       2,  FALSE },
+    { BWRITERSPR_TEXCRDOUT,     8,  FALSE },
+    { ~0U, 0 } /* End tag */
+};
+
+/* struct instruction *asmparser_srcreg
+ *
+ * Records a source register in the instruction and does shader version
+ * specific checks and modifications on it
+ *
+ * Parameters:
+ *  This: Shader parser instance
+ *  instr: instruction to store the register in
+ *  num: Number of source register
+ *  src: Pointer to source the register structure. The caller can free
+ *  it afterwards
+ */
+static void asmparser_srcreg_vs_1(struct asm_parser *This,
+                                  struct instruction *instr, int num,
+                                  const struct shader_reg *src) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(src, vs_1_reg_allowed)) {
+        asmparser_message(This, "Line %u: Source register %s not supported in VS 1\n",
+                          This->line_no,
+                          debug_print_srcreg(src, ST_VERTEX));
+        set_parse_status(This, PARSE_ERR);
+    }
+    check_legacy_srcmod(This, src->srcmod);
+    check_abs_srcmod(This, src->srcmod);
+    reg = map_oldvs_register(src);
+    memcpy(&instr->src[num], &reg, sizeof(reg));
+}
+
 static const struct allowed_reg_type vs_2_reg_allowed[] = {
     { BWRITERSPR_TEMP,      12,  FALSE },
     { BWRITERSPR_INPUT,     16,  FALSE },
@@ -562,6 +602,24 @@ static void asmparser_srcreg_ps_3(struct asm_parser *This,
     memcpy(&instr->src[num], src, sizeof(*src));
 }
 
+static void asmparser_dstreg_vs_1(struct asm_parser *This,
+                                  struct instruction *instr,
+                                  const struct shader_reg *dst) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(dst, vs_1_reg_allowed)) {
+        asmparser_message(This, "Line %u: Destination register %s not supported in VS 1\n",
+                          This->line_no,
+                          debug_print_dstreg(dst, ST_VERTEX));
+        set_parse_status(This, PARSE_ERR);
+    }
+    check_ps_dstmod(This, instr->dstmod);
+    check_shift_dstmod(This, instr->shift);
+    reg = map_oldvs_register(dst);
+    memcpy(&instr->dst, &reg, sizeof(reg));
+    instr->has_dst = TRUE;
+}
+
 static void asmparser_dstreg_vs_2(struct asm_parser *This,
                                   struct instruction *instr,
                                   const struct shader_reg *dst) {
@@ -663,6 +721,26 @@ static void asmparser_coissue_unsupported(struct asm_parser *This) {
     set_parse_status(This, PARSE_ERR);
 }
 
+static const struct asmparser_backend parser_vs_1 = {
+    asmparser_constF,
+    asmparser_constI,
+    asmparser_constB,
+
+    asmparser_dstreg_vs_1,
+    asmparser_srcreg_vs_1,
+
+    asmparser_predicate_unsupported,
+    asmparser_coissue_unsupported,
+
+    asmparser_dcl_output,
+    asmparser_dcl_input,
+    asmparser_dcl_sampler,
+
+    asmparser_end,
+
+    asmparser_instr,
+};
+
 static const struct asmparser_backend parser_vs_2 = {
     asmparser_constF,
     asmparser_constI,
@@ -794,6 +872,38 @@ static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) {
     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL);
 }
 
+void create_vs10_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("vs_1_0\n");
+
+    ret->shader = asm_alloc(sizeof(*ret->shader));
+    if(!ret->shader) {
+        ERR("Failed to allocate memory for the shader\n");
+        set_parse_status(ret, PARSE_ERR);
+        return;
+    }
+
+    ret->shader->type = ST_VERTEX;
+    ret->shader->version = BWRITERVS_VERSION(1, 0);
+    ret->funcs = &parser_vs_1;
+    gen_oldvs_output(ret->shader);
+}
+
+void create_vs11_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("vs_1_1\n");
+
+    ret->shader = asm_alloc(sizeof(*ret->shader));
+    if(!ret->shader) {
+        ERR("Failed to allocate memory for the shader\n");
+        set_parse_status(ret, PARSE_ERR);
+        return;
+    }
+
+    ret->shader->type = ST_VERTEX;
+    ret->shader->version = BWRITERVS_VERSION(1, 1);
+    ret->funcs = &parser_vs_1;
+    gen_oldvs_output(ret->shader);
+}
+
 void create_vs20_parser(struct asm_parser *ret) {
     TRACE_(parsed_shader)("vs_2_0\n");
 
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
index 9a03bbf..9fe6311 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -271,14 +271,12 @@ shader:               version_marker instructions
 version_marker:       VER_VS10
                         {
                             TRACE("Vertex shader 1.0\n");
-                            set_parse_status(&asm_ctx, PARSE_ERR);
-                            YYABORT;
+                            create_vs10_parser(&asm_ctx);
                         }
                     | VER_VS11
                         {
                             TRACE("Vertex shader 1.1\n");
-                            set_parse_status(&asm_ctx, PARSE_ERR);
-                            YYABORT;
+                            create_vs11_parser(&asm_ctx);
                         }
                     | VER_VS20
                         {
diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
index 055b8ef..3bd003b 100644
--- a/dlls/d3dx9_36/bytecodewriter.c
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -484,6 +484,30 @@ static HRESULT vs_find_builtin_varyings(struct bc_writer *This, const struct bwr
     return S_OK;
 }
 
+static void vs_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
+    HRESULT hr;
+
+    if(shader->num_ci || shader->num_cb) {
+        WARN("Int and bool constants are not supported in shader model 1 shaders\n");
+        WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
+        This->state = E_INVALIDARG;
+        return;
+    }
+
+    hr = vs_find_builtin_varyings(This, shader);
+    if(FAILED(hr)) {
+        This->state = hr;
+        return;
+    }
+
+    /* Declare the shader type and version */
+    put_dword(buffer, This->version);
+
+    write_declarations(buffer, FALSE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
+    write_constF(shader, buffer, FALSE);
+    return;
+}
+
 static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
                                          const struct bwriter_shader *shader,
                                          DWORD texcoords) {
@@ -669,6 +693,73 @@ static void vs_12_dstreg(struct bc_writer *This, const struct shader_reg *reg,
     put_dword(buffer, token);
 }
 
+static void vs_1_x_srcreg(struct bc_writer *This, const struct shader_reg *reg,
+                          struct bytecode_buffer *buffer) {
+    DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
+    DWORD has_swizzle;
+    DWORD component;
+
+    switch(reg->type) {
+        case BWRITERSPR_OUTPUT:
+            /* Map the swizzle to a writemask, the format expected
+               by map_vs_output
+             */
+            switch(reg->swizzle) {
+                case BWRITERVS_SWIZZLE_X:
+                    component = BWRITERSP_WRITEMASK_0;
+                    break;
+                case BWRITERVS_SWIZZLE_Y:
+                    component = BWRITERSP_WRITEMASK_1;
+                    break;
+                case BWRITERVS_SWIZZLE_Z:
+                    component = BWRITERSP_WRITEMASK_2;
+                    break;
+                case BWRITERVS_SWIZZLE_W:
+                    component = BWRITERSP_WRITEMASK_3;
+                    break;
+                default:
+                    component = 0;
+            }
+            token |= map_vs_output(This, reg->regnum, component, &has_swizzle);
+            break;
+
+        case BWRITERSPR_RASTOUT:
+        case BWRITERSPR_ATTROUT:
+            /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
+             * but are unexpected. If we hit this path it might be due to an error.
+             */
+            FIXME("Unexpected register type %u\n", reg->type);
+            /* drop through */
+        case BWRITERSPR_INPUT:
+        case BWRITERSPR_TEMP:
+        case BWRITERSPR_CONST:
+        case BWRITERSPR_ADDR:
+            token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+            if(reg->rel_reg) {
+                if(reg->rel_reg->type != BWRITERSPR_ADDR ||
+                   reg->rel_reg->regnum != 0 ||
+                   reg->rel_reg->swizzle != BWRITERVS_SWIZZLE_X) {
+                    WARN("Relative addressing in vs_1_x is only allowed with a0.x\n");
+                    This->state = E_INVALIDARG;
+                    return;
+                }
+                token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
+            }
+            break;
+
+        default:
+            WARN("Invalid register type for 1.x vshader\n");
+            This->state = E_INVALIDARG;
+            return;
+    }
+
+    token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
+
+    token |= d3d9_srcmod(reg->srcmod);
+    put_dword(buffer, token);
+}
+
 static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
                           struct bytecode_buffer *buffer){
     unsigned int i;
@@ -721,6 +812,16 @@ static DWORD instrlen(const struct instruction *instr, unsigned int srcs, unsign
     return ret;
 }
 
+static void sm_1_x_opcode(struct bc_writer *This,
+                          const struct instruction *instr,
+                          DWORD token, struct bytecode_buffer *buffer) {
+    /* In sm_1_x instruction length isn't encoded */
+    if(instr->coissue){
+        token |= D3DSI_COISSUE;
+    }
+    put_dword(buffer, token);
+}
+
 static void instr_handler(struct bc_writer *This,
                           const struct instruction *instr,
                           struct bytecode_buffer *buffer) {
@@ -732,6 +833,47 @@ static void instr_handler(struct bc_writer *This,
     write_srcregs(This, instr, buffer);
 }
 
+static const struct instr_handler_table vs_1_x_handlers[] = {
+    {BWRITERSIO_ADD,            instr_handler},
+    {BWRITERSIO_NOP,            instr_handler},
+    {BWRITERSIO_MOV,            instr_handler},
+    {BWRITERSIO_SUB,            instr_handler},
+    {BWRITERSIO_MAD,            instr_handler},
+    {BWRITERSIO_MUL,            instr_handler},
+    {BWRITERSIO_RCP,            instr_handler},
+    {BWRITERSIO_RSQ,            instr_handler},
+    {BWRITERSIO_DP3,            instr_handler},
+    {BWRITERSIO_DP4,            instr_handler},
+    {BWRITERSIO_MIN,            instr_handler},
+    {BWRITERSIO_MAX,            instr_handler},
+    {BWRITERSIO_SLT,            instr_handler},
+    {BWRITERSIO_SGE,            instr_handler},
+    {BWRITERSIO_EXP,            instr_handler},
+    {BWRITERSIO_LOG,            instr_handler},
+    {BWRITERSIO_EXPP,           instr_handler},
+    {BWRITERSIO_LOGP,           instr_handler},
+    {BWRITERSIO_DST,            instr_handler},
+    {BWRITERSIO_FRC,            instr_handler},
+    {BWRITERSIO_M4x4,           instr_handler},
+    {BWRITERSIO_M4x3,           instr_handler},
+    {BWRITERSIO_M3x4,           instr_handler},
+    {BWRITERSIO_M3x3,           instr_handler},
+    {BWRITERSIO_M3x2,           instr_handler},
+    {BWRITERSIO_LIT,            instr_handler},
+
+    {BWRITERSIO_END,            NULL}, /* Sentinel value, it signals
+                                          the end of the list */
+};
+
+static const struct bytecode_backend vs_1_x_backend = {
+    vs_1_x_header,
+    end,
+    vs_1_x_srcreg,
+    vs_12_dstreg,
+    sm_1_x_opcode,
+    vs_1_x_handlers
+};
+
 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
     write_const(shader->constB, shader->num_cb, D3DSIO_DEFB, D3DSPR_CONSTBOOL, buffer, len);
 }
@@ -1492,6 +1634,16 @@ static const struct bytecode_backend ps_3_backend = {
     ps_3_handlers
 };
 
+static void init_vs10_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 vertex shader 1.0 writer\n");
+    writer->funcs = &vs_1_x_backend;
+}
+
+static void init_vs11_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 vertex shader 1.1 writer\n");
+    writer->funcs = &vs_1_x_backend;
+}
+
 static void init_vs20_dx9_writer(struct bc_writer *writer) {
     TRACE("Creating DirectX9 vertex shader 2.0 writer\n");
     writer->funcs = &vs_2_0_backend;
@@ -1536,14 +1688,14 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
                 WARN("Unsupported dxversion for vertex shader 1.0 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_vs10_dx9_writer(ret);
             break;
         case BWRITERVS_VERSION(1, 1):
             if(dxversion != 9) {
                 WARN("Unsupported dxversion for vertex shader 1.1 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_vs11_dx9_writer(ret);
             break;
         case BWRITERVS_VERSION(2, 0):
             if(dxversion != 9) {
diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index 52012c9..96e0533 100644
--- a/dlls/d3dx9_36/d3dx9_36_private.h
+++ b/dlls/d3dx9_36/d3dx9_36_private.h
@@ -178,6 +178,7 @@ struct instruction {
     unsigned int            num_srcs; /* For freeing the rel_regs */
     BOOL                    has_predicate;
     struct shader_reg       predicate;
+    BOOL                    coissue;
 };
 
 struct declaration {
@@ -311,6 +312,8 @@ struct asm_parser {
 
 extern struct asm_parser asm_ctx;
 
+void create_vs10_parser(struct asm_parser *ret);
+void create_vs11_parser(struct asm_parser *ret);
 void create_vs20_parser(struct asm_parser *ret);
 void create_vs2x_parser(struct asm_parser *ret);
 void create_vs30_parser(struct asm_parser *ret);
diff --git a/dlls/d3dx9_36/tests/asm.c b/dlls/d3dx9_36/tests/asm.c
index 7daa91f..1be2c55 100644
--- a/dlls/d3dx9_36/tests/asm.c
+++ b/dlls/d3dx9_36/tests/asm.c
@@ -1306,6 +1306,9 @@ static void failure_test(void) {
         /* shader 37: no a0 register in ps_3_0 */
         "ps_3_0\n"
         "add r0, v[ a0.x ], r1\n",
+        /* shader 38: only a0.x accepted in vs_1_1 */
+        "vs_1_1\n"
+        "mov r0, c0[ a0 ]\n",
     };
     HRESULT hr;
     unsigned int i;
@@ -1392,8 +1395,6 @@ static void assembleshader_test(void) {
     struct D3DXIncludeImpl include;
     HRESULT shader_vsh_res, incl_vsh_res;
 
-    todo_wine {
-
     /* pDefines test */
     shader = NULL;
     messages = NULL;
@@ -1421,6 +1422,8 @@ static void assembleshader_test(void) {
     }
     if(shader) ID3DXBuffer_Release(shader);
 
+    todo_wine {
+
     shader_vsh_res = create_file("shader.vsh", testshader, sizeof(testshader));
     if(SUCCEEDED(shader_vsh_res)) {
         incl_vsh_res = create_file("incl.vsh", testincl, sizeof(testincl));
@@ -1484,6 +1487,8 @@ static void assembleshader_test(void) {
     }
     if(shader) ID3DXBuffer_Release(shader);
 
+    } /* end of todo_wine */
+
     /* D3DXAssembleShaderFromResource test */
     shader = NULL;
     messages = NULL;
@@ -1497,8 +1502,6 @@ static void assembleshader_test(void) {
     }
     if(shader) ID3DXBuffer_Release(shader);
 
-    } /* end of todo_wine */
-
     /* D3DXAssembleShaderFromResource with missing shader resource test */
     shader = NULL;
     messages = NULL;
@@ -1521,9 +1524,9 @@ static void assembleshader_test(void) {
 
 START_TEST(asm)
 {
-    todo_wine preproc_test();
+    preproc_test();
     todo_wine ps_1_1_test();
-    todo_wine vs_1_1_test();
+    vs_1_1_test();
     todo_wine ps_1_3_test();
     todo_wine ps_1_4_test();
     vs_2_0_test();
-- 
1.6.4.4


More information about the wine-patches mailing list