[4/4] d3dx9: Shader assembler ps_1_4 support.

Matteo Bruni matteo.mystral at gmail.com
Tue Jul 20 08:12:05 CDT 2010


-------------- next part --------------
From a2809cd8d64f17d12e80f242b987034040df6a10 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Tue, 20 Jul 2010 15:01:16 +0200
Subject: d3dx9: Shader assembler ps_1_4 support.

---
 dlls/d3dx9_36/asmparser.c        |  183 ++++++++++++++++++++++++++++++++++++
 dlls/d3dx9_36/asmshader.y        |    8 +-
 dlls/d3dx9_36/bytecodewriter.c   |  191 +++++++++++++++++++++++++++++++++++++-
 dlls/d3dx9_36/d3dx9_36_private.h |    1 +
 dlls/d3dx9_36/tests/asm.c        |   29 ++++++-
 5 files changed, 408 insertions(+), 4 deletions(-)

diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
index e1a32ca..10188a0 100644
--- a/dlls/d3dx9_36/asmparser.c
+++ b/dlls/d3dx9_36/asmparser.c
@@ -161,6 +161,12 @@ static void asmparser_dcl_input_ps_2(struct asm_parser *This, DWORD usage, DWORD
     }
 }
 
+static void asmparser_dcl_input_unsupported(struct asm_parser *This, DWORD usage, DWORD num,
+					    DWORD mod, const struct shader_reg *reg) {
+    asmparser_message(This, "Line %u: Input declaration unsupported in this shader version\n", This->line_no);
+    set_parse_status(This, PARSE_ERR);
+}
+
 static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype,
                                   DWORD mod, DWORD regnum,
                                   unsigned int line_no) {
@@ -220,6 +226,84 @@ static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift,
     }
 }
 
+static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
+                             const struct shader_reg *dst,
+                             const struct src_regs *srcs) {
+    struct instruction *instr;
+
+    if(!srcs || srcs->count != 1) {
+        asmparser_message(This, "Line %u: Wrong number of source registers in texcrd instruction\n", This->line_no);
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr = alloc_instr(1);
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    /* The job of texcrd is done by mov in later shader versions */
+    instr->opcode = BWRITERSIO_MOV;
+    instr->dstmod = mod;
+    instr->shift = shift;
+    instr->comptype = 0;
+
+    This->funcs->dstreg(This, instr, dst);
+    This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
+                              const struct shader_reg *dst,
+                              const struct src_regs *srcs) {
+    struct instruction *instr;
+
+    if(!srcs || srcs->count != 1) {
+        asmparser_message(This, "Line %u: texld (PS 1.4) has a wrong number of source registers\n", This->line_no);
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr = alloc_instr(2);
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    /* This code is recording a texld instruction, not tex. However,
+     * texld borrows the opcode of tex
+     */
+    instr->opcode = BWRITERSIO_TEX;
+    instr->dstmod = mod;
+    instr->shift = shift;
+    instr->comptype = 0;
+
+    This->funcs->dstreg(This, instr, dst);
+    This->funcs->srcreg(This, instr, 0, &srcs->reg[0]);
+
+    /* The 2nd source register is the sampler register with the
+     * destination's regnum
+     */
+    ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
+    instr->src[1].type = BWRITERSPR_SAMPLER;
+    instr->src[1].regnum = dst->regnum;
+    instr->src[1].swizzle = BWRITERVS_NOSWIZZLE;
+    instr->src[1].srcmod = BWRITERSPSM_NONE;
+    instr->src[1].rel_reg = NULL;
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
 static void asmparser_instr(struct asm_parser *This, DWORD opcode,
                             DWORD mod, DWORD shift,
                             BWRITER_COMPARISON_TYPE comp,
@@ -258,6 +342,19 @@ ns */
                 return;
             }
             /* Use the default handling */
+	    break;
+        case BWRITERSIO_TEXCOORD:
+            /* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */
+            asmparser_texcrd(This, mod, shift, dst, srcs);
+            return;
+        case BWRITERSIO_TEX:
+            /* this encodes both the tex PS 1.x instruction and the
+               texld 1.4/2.0+ instruction */
+            if(This->shader->version == BWRITERPS_VERSION(1, 4)) {
+                asmparser_texld14(This, mod, shift, dst, srcs);
+                return;
+            }
+            /* else fallback to the standard behavior */
             break;
     }
 
@@ -563,6 +660,30 @@ static void asmparser_srcreg_vs_3(struct asm_parser *This,
     memcpy(&instr->src[num], src, sizeof(*src));
 }
 
+static const struct allowed_reg_type ps_1_4_reg_allowed[] = {
+    { BWRITERSPR_CONST,     8,  FALSE },
+    { BWRITERSPR_TEMP,      6,  FALSE },
+    { BWRITERSPR_TEXTURE,   6,  FALSE },
+    { BWRITERSPR_INPUT,     2,  FALSE },
+    { ~0U, 0 } /* End tag */
+};
+
+static void asmparser_srcreg_ps_1_4(struct asm_parser *This,
+                                    struct instruction *instr, int num,
+                                    const struct shader_reg *src) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(src, ps_1_4_reg_allowed)) {
+        asmparser_message(This, "Line %u: Source register %s not supported in PS 1.4\n",
+                          This->line_no,
+                          debug_print_srcreg(src));
+        set_parse_status(This, PARSE_ERR);
+    }
+    check_abs_srcmod(This, src->srcmod);
+    reg = map_oldps_register(src, TRUE);
+    memcpy(&instr->src[num], &reg, sizeof(reg));
+}
+
 static const struct allowed_reg_type ps_2_0_reg_allowed[] = {
     { BWRITERSPR_INPUT,         2,  FALSE },
     { BWRITERSPR_TEMP,         32,  FALSE },
@@ -706,6 +827,22 @@ static void asmparser_dstreg_vs_3(struct asm_parser *This,
     instr->has_dst = TRUE;
 }
 
+static void asmparser_dstreg_ps_1_4(struct asm_parser *This,
+                                    struct instruction *instr,
+                                    const struct shader_reg *dst) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(dst, ps_1_4_reg_allowed)) {
+        asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
+                          This->line_no,
+                          debug_print_dstreg(dst));
+        set_parse_status(This, PARSE_ERR);
+    }
+    reg = map_oldps_register(dst, FALSE);
+    memcpy(&instr->dst, &reg, sizeof(reg));
+    instr->has_dst = TRUE;
+}
+
 static void asmparser_dstreg_ps_2(struct asm_parser *This,
                                   struct instruction *instr,
                                   const struct shader_reg *dst) {
@@ -769,6 +906,16 @@ static void asmparser_predicate_unsupported(struct asm_parser *This,
     set_parse_status(This, PARSE_ERR);
 }
 
+static void asmparser_coissue_supported(struct asm_parser *This) {
+    /* this sets the coissue flag of the last instruction added to the shader */
+    if(!This->shader) return;
+    if(This->shader->num_instrs == 0){
+        asmparser_message(This, "Line %u: Coissue flag on the first shader instruction\n", This->line_no);
+        set_parse_status(This, PARSE_ERR);
+    }
+    This->shader->instr[This->shader->num_instrs-1]->coissue = TRUE;
+}
+
 static void asmparser_coissue_unsupported(struct asm_parser *This) {
     asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no);
     set_parse_status(This, PARSE_ERR);
@@ -834,6 +981,26 @@ static const struct asmparser_backend parser_vs_3 = {
     asmparser_instr,
 };
 
+static const struct asmparser_backend parser_ps_1_4 = {
+    asmparser_constF,
+    asmparser_constI,
+    asmparser_constB,
+
+    asmparser_dstreg_ps_1_4,
+    asmparser_srcreg_ps_1_4,
+
+    asmparser_predicate_unsupported,
+    asmparser_coissue_supported,
+
+    asmparser_dcl_output_unsupported,
+    asmparser_dcl_input_unsupported,
+    asmparser_dcl_sampler_unsupported,
+
+    asmparser_end,
+
+    asmparser_instr,
+};
+
 static const struct asmparser_backend parser_ps_2 = {
     asmparser_constF,
     asmparser_constI,
@@ -1004,6 +1171,22 @@ void create_vs30_parser(struct asm_parser *ret) {
     ret->funcs = &parser_vs_3;
 }
 
+void create_ps14_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_1_4\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_PIXEL;
+    ret->shader->version = BWRITERPS_VERSION(1, 4);
+    ret->funcs = &parser_ps_1_4;
+    gen_oldps_input(ret->shader, 6);
+}
+
 void create_ps20_parser(struct asm_parser *ret) {
     TRACE_(parsed_shader)("ps_2_0\n");
 
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
index 3ed2128..a961af4 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -336,8 +336,7 @@ version_marker:       VER_VS10
                     | VER_PS14
                         {
                             TRACE("Pixel  shader 1.4\n");
-                            set_parse_status(&asm_ctx, PARSE_ERR);
-                            YYABORT;
+                            create_ps14_parser(&asm_ctx);
                         }
                     | VER_PS20
                         {
@@ -370,6 +369,11 @@ complexinstr:         instruction
                                 TRACE("predicate\n");
                                 asm_ctx.funcs->predicate(&asm_ctx, &$1);
                             }
+                    | '+' instruction
+                            {
+                                TRACE("coissue\n");
+                                asm_ctx.funcs->coissue(&asm_ctx);
+                            }
 
 instruction:          INSTR_ADD omods dreg ',' sregs
                             {
diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
index 9fe2bfc..5034c7b 100644
--- a/dlls/d3dx9_36/bytecodewriter.c
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -578,6 +578,28 @@ static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
     return S_OK;
 }
 
+static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
+    HRESULT hr;
+
+    /* First check the constants and varyings, and complain if unsupported things are used */
+    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 = find_ps_builtin_semantics(This, shader, 6);
+    if(FAILED(hr)) {
+        This->state = hr;
+        return;
+    }
+
+    /* Declare the shader type and version */
+    put_dword(buffer, This->version);
+    write_constF(shader, buffer, TRUE);
+}
+
 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
     put_dword(buffer, D3DSIO_END);
 }
@@ -888,6 +910,168 @@ static const struct bytecode_backend vs_1_x_backend = {
     vs_1_x_handlers
 };
 
+static void ps_1_4_srcreg(struct bc_writer *This, const struct shader_reg *reg,
+                          struct bytecode_buffer *buffer) {
+    DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
+    if(reg->rel_reg) {
+        WARN("Relative addressing not supported in <= ps_3_0\n");
+        This->state = E_INVALIDARG;
+        return;
+    }
+
+    switch(reg->type) {
+        case BWRITERSPR_INPUT:
+            token |= map_ps_input(This, reg);
+            break;
+
+        /* Can be mapped 1:1 */
+        case BWRITERSPR_TEMP:
+        case BWRITERSPR_CONST:
+            token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+        default:
+            WARN("Invalid register type for ps_1_4 shader\n");
+            This->state = E_INVALIDARG;
+            return;
+    }
+
+    token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
+
+    if(reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
+       reg->srcmod == BWRITERSPSM_NOT) {
+        WARN("Invalid source modifier %u for ps_1_4\n", reg->srcmod);
+        This->state = E_INVALIDARG;
+        return;
+    }
+    token |= d3d9_srcmod(reg->srcmod);
+    put_dword(buffer, token);
+}
+
+static void ps_1_4_dstreg(struct bc_writer *This, const struct shader_reg *reg,
+                          struct bytecode_buffer *buffer,
+                          DWORD shift, DWORD mod) {
+    DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
+
+    if(reg->rel_reg) {
+        WARN("Relative addressing not supported for destination registers\n");
+        This->state = E_INVALIDARG;
+        return;
+    }
+
+    switch(reg->type) {
+        case BWRITERSPR_TEMP: /* 1:1 mapping */
+            token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+	/* For texkill */
+        case BWRITERSPR_INPUT:
+            token |= map_ps_input(This, reg);
+            break;
+
+        default:
+            WARN("Invalid dest register type for 1.x pshader\n");
+            This->state = E_INVALIDARG;
+            return;
+    }
+
+    token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
+    token |= d3d9_dstmod(mod);
+
+    token |= d3d9_writemask(reg->writemask);
+    put_dword(buffer, token);
+}
+
+static void instr_ps_1_4_mov(struct bc_writer *This,
+                             const struct instruction *instr,
+                             struct bytecode_buffer *buffer) {
+    DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
+
+    if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
+        if(instr->src[0].regnum == This->t_regnum[0] ||
+           instr->src[0].regnum == This->t_regnum[1] ||
+           instr->src[0].regnum == This->t_regnum[2] ||
+           instr->src[0].regnum == This->t_regnum[3] ||
+           instr->src[0].regnum == This->t_regnum[4] ||
+           instr->src[0].regnum == This->t_regnum[5]) {
+            /* Similar to a regular mov, but a different opcode */
+            token = D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK;
+        } else if(instr->src[0].regnum == This->v_regnum[0] ||
+                  instr->src[0].regnum == This->v_regnum[1]) {
+            /* Handled by the normal mov below. Just drop out of the if condition */
+        } else {
+            WARN("Unsupported varying -> temp mov in ps_1_4\n");
+            This->state = E_INVALIDARG;
+            return;
+        }
+    }
+
+    This->funcs->opcode(This, instr, token, buffer);
+    This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+    This->funcs->srcreg(This, &instr->src[0], buffer);
+}
+
+static void instr_ps_1_4_texld(struct bc_writer *This,
+                               const struct instruction *instr,
+                               struct bytecode_buffer *buffer) {
+    if(instr->src[1].type != BWRITERSPR_SAMPLER ||
+       instr->src[1].regnum > 5) {
+        WARN("Unsupported sampler type %u regnum %u\n",
+             instr->src[1].type, instr->src[1].regnum);
+        This->state = E_INVALIDARG;
+        return;
+    } else if(instr->dst.type != BWRITERSPR_TEMP) {
+        WARN("Can only sample into a temp register\n");
+        This->state = E_INVALIDARG;
+        return;
+    }
+
+    if(instr->src[1].regnum != instr->dst.regnum) {
+        WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_4\n",
+             instr->src[1].regnum, instr->dst.regnum);
+        This->state = E_INVALIDARG;
+        return;
+    }
+
+    This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
+    This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+    This->funcs->srcreg(This, &instr->src[0], buffer);
+}
+
+static const struct instr_handler_table ps_1_4_handlers[] = {
+    {BWRITERSIO_ADD,            instr_handler},
+    {BWRITERSIO_NOP,            instr_handler},
+    {BWRITERSIO_MOV,            instr_ps_1_4_mov},
+    {BWRITERSIO_SUB,            instr_handler},
+    {BWRITERSIO_MAD,            instr_handler},
+    {BWRITERSIO_MUL,            instr_handler},
+    {BWRITERSIO_DP3,            instr_handler},
+    {BWRITERSIO_DP4,            instr_handler},
+    {BWRITERSIO_LRP,            instr_handler},
+
+    /* pshader instructions */
+    {BWRITERSIO_CND,            instr_handler},
+    {BWRITERSIO_CMP,            instr_handler},
+    {BWRITERSIO_TEXKILL,        instr_handler},
+    {BWRITERSIO_TEX,            instr_ps_1_4_texld},
+    {BWRITERSIO_TEXDEPTH,       instr_handler},
+    {BWRITERSIO_BEM,            instr_handler},
+
+    {BWRITERSIO_PHASE,          instr_handler},
+    {BWRITERSIO_END,            NULL},
+};
+
+static const struct bytecode_backend ps_1_4_backend = {
+    ps_1_4_header,
+    end,
+    ps_1_4_srcreg,
+    ps_1_4_dstreg,
+    sm_1_x_opcode,
+    ps_1_4_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);
 }
@@ -1676,6 +1860,11 @@ static void init_vs30_dx9_writer(struct bc_writer *writer) {
     writer->funcs = &vs_3_backend;
 }
 
+static void init_ps14_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 pixel shader 1.4 writer\n");
+    writer->funcs = &ps_1_4_backend;
+}
+
 static void init_ps20_dx9_writer(struct bc_writer *writer) {
     TRACE("Creating DirectX9 pixel shader 2.0 writer\n");
     writer->funcs = &ps_2_0_backend;
@@ -1769,7 +1958,7 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
                 WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps14_dx9_writer(ret);
             break;
 
         case BWRITERPS_VERSION(2, 0):
diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h
index 6e7d970..4be1d58 100644
--- a/dlls/d3dx9_36/d3dx9_36_private.h
+++ b/dlls/d3dx9_36/d3dx9_36_private.h
@@ -323,6 +323,7 @@ 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);
+void create_ps14_parser(struct asm_parser *ret);
 void create_ps20_parser(struct asm_parser *ret);
 void create_ps2x_parser(struct asm_parser *ret);
 void create_ps30_parser(struct asm_parser *ret);
diff --git a/dlls/d3dx9_36/tests/asm.c b/dlls/d3dx9_36/tests/asm.c
index 0b8b777..fe3eee0 100644
--- a/dlls/d3dx9_36/tests/asm.c
+++ b/dlls/d3dx9_36/tests/asm.c
@@ -561,6 +561,33 @@ static void ps_1_4_test(void) {
             "texdepth r5\n",
             {0xffff0104, 0x00000057, 0x800f0005, 0x0000ffff}
         },
+        {   /* shader 15 */
+            "ps_1_4\n"
+            "add r0, r1, r2_bx2\n",
+            {0xffff0104, 0x00000002, 0x800f0000, 0x80e40001, 0x84e40002, 0x0000ffff}
+        },
+        {   /* shader 16 */
+            "ps_1_4\n"
+            "add_x4 r0, r1, r2\n",
+            {0xffff0104, 0x00000002, 0x820f0000, 0x80e40001, 0x80e40002, 0x0000ffff}
+        },
+        {   /* shader 17 */
+            "ps_1_4\n"
+            "add r0.rgb, r1, r2\n"
+            "+add r0.a, r1, r2\n",
+            {0xffff0104, 0x00000002, 0x80070000, 0x80e40001, 0x80e40002, 0x40000002,
+             0x80080000, 0x80e40001, 0x80e40002, 0x0000ffff}
+        },
+        {   /* shader 18 */
+            "ps_1_4\n"
+            "texdepth_x2 r5\n",
+            {0xffff0104, 0x00000057, 0x810f0005, 0x0000ffff}
+        },
+        {   /* shader 18 */
+            "ps_1_4\n"
+            "bem_d2 r1, c0, r0\n",
+            {0xffff0104, 0x00000059, 0x8f0f0001, 0xa0e40000, 0x80e40000, 0x0000ffff}
+        },
     };
 
     exec_tests("ps_1_4", tests, sizeof(tests) / sizeof(tests[0]));
@@ -1627,7 +1654,7 @@ START_TEST(asm)
     todo_wine ps_1_1_test();
     vs_1_1_test();
     todo_wine ps_1_3_test();
-    todo_wine ps_1_4_test();
+    ps_1_4_test();
     vs_2_0_test();
     vs_2_x_test();
     ps_2_0_test();
-- 
1.7.1


More information about the wine-patches mailing list