[10/18] d3dx9: Shader assembler PS <= 1.3 support

Matteo Bruni matteo.mystral at gmail.com
Sun Aug 16 12:52:57 CDT 2009


-------------- next part --------------
From 6bc5612c6eb5308e327d14e4452d23a3aeadd403 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sun, 16 Aug 2009 01:37:33 +0200
Subject: d3dx9: Shader assembler PS <= 1.3 support

---
 dlls/d3dx9_36/asmparser.c      |  795 ++++++++++++++++++++++++++++++++++++++++
 dlls/d3dx9_36/asmshader.y      |    8 +-
 dlls/d3dx9_36/bytecodewriter.c |  333 +++++++++++++++++-
 3 files changed, 1128 insertions(+), 8 deletions(-)

diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
index 2560c0b..c7588f1 100644
--- a/dlls/d3dx9_36/asmparser.c
+++ b/dlls/d3dx9_36/asmparser.c
@@ -98,6 +98,602 @@ static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype, DWORD
     }
 }
 
+static void asmparser_texcoord(struct asm_parser *This,
+                               const struct shader_reg *dst,
+                               const struct src_regs *srcs) {
+    struct instruction *instr;
+
+    if(srcs) {
+        asmparser_message(This, "Line %u: Source registers in texcoord 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;
+    }
+
+    /* texcoord copies the texture coord varying data into a temporary-register like
+     * readable form. In newer shader models this equals a MOV from v0 to r0, record
+     * it as this. The 1.x output module catches the mov and writes a texcoord if the
+     * parameters match
+     */
+    instr->opcode = BWRITERSIO_MOV;
+    instr->dstmod = BWRITERSPDM_SATURATE; /* texcoord clamps to [0;1] */
+    instr->shift = 0;
+    instr->comptype = 0;
+    /* The dest reg can be recorded and mapped normally
+     * with the t0 -> temporary reg map
+     */
+    This->funcs->dstreg(This, instr, dst);
+
+    /* The src reg needs special care */
+    memset(&instr->src[0], 0, sizeof(instr->src[0]));
+    instr->src[0].type = BWRITERSPR_INPUT;
+    switch(dst->regnum) {
+        case 0: instr->src[0].regnum = T0_VARYING; break;
+        case 1: instr->src[0].regnum = T1_VARYING; break;
+        case 2: instr->src[0].regnum = T2_VARYING; break;
+        case 3: instr->src[0].regnum = T3_VARYING; break;
+        case 4: instr->src[0].regnum = T4_VARYING; break;
+        case 5: instr->src[0].regnum = T5_VARYING; break;
+        case 6: instr->src[0].regnum = T6_VARYING; break;
+        case 7: instr->src[0].regnum = T7_VARYING; break;
+
+        default:
+            asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, dst->regnum);
+            instr->src[0].regnum = 0;
+            set_parse_status(This, PARSE_ERR);
+    }
+    instr->src[0].swizzle = BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_W;
+    instr->src[0].rel_reg = NULL;
+    instr->src[0].srcmod = BWRITERSPSM_NONE;
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_texkill(struct asm_parser *This,
+                              const struct shader_reg *dst) {
+    struct instruction *instr = alloc_instr(0);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = BWRITERSIO_TEXKILL;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+
+    /* Do not run the dst register through the normal
+     * register conversion. If used with ps_1_0 to ps_1_3
+     * the texture coordinate from that register is used,
+     * not the temporary register value. In ps_1_4 and
+     * ps_2_0 t0 is always a varying and temporaries can
+     * be used with texkill.
+     */
+    if(dst->type == BWRITERSPR_TEXTURE) {
+        memset(&instr->dst, 0, sizeof(instr->dst));
+        instr->dst.type = BWRITERSPR_INPUT;
+        switch(dst->regnum) {
+            case 0: instr->dst.regnum = T0_VARYING; break;
+            case 1: instr->dst.regnum = T1_VARYING; break;
+            case 2: instr->dst.regnum = T2_VARYING; break;
+            case 3: instr->dst.regnum = T3_VARYING; break;
+            case 4: instr->dst.regnum = T4_VARYING; break;
+            case 5: instr->dst.regnum = T5_VARYING; break;
+            case 6: instr->dst.regnum = T6_VARYING; break;
+            case 7: instr->dst.regnum = T7_VARYING; break;
+            default:
+                asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, dst->regnum);
+                instr->dst.regnum = 0;
+                set_parse_status(This, PARSE_ERR);
+        }
+        instr->dst.writemask = dst->writemask;
+        instr->dst.rel_reg = NULL;
+    } else {
+        instr->dst = *dst;
+    }
+    instr->has_dst = TRUE;
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_tex(struct asm_parser *This,
+                          const struct shader_reg *dst) {
+    struct instruction *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 = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+
+    /* The destination register can be recorded normally. The dstreg method
+     * maps the tX register to rY according to the declared mapping in the
+     * header
+     */
+    This->funcs->dstreg(This, instr, dst);
+
+    /* The first source register is the varying containing the coordinate */
+    memset(&instr->src[0], 0, sizeof(instr->src[0]));
+    instr->src[0].type = BWRITERSPR_INPUT;
+    switch(dst->regnum) {
+        case 0: instr->src[0].regnum = T0_VARYING; break;
+        case 1: instr->src[0].regnum = T1_VARYING; break;
+        case 2: instr->src[0].regnum = T2_VARYING; break;
+        case 3: instr->src[0].regnum = T3_VARYING; break;
+        case 4: instr->src[0].regnum = T4_VARYING; break;
+        case 5: instr->src[0].regnum = T5_VARYING; break;
+        case 6: instr->src[0].regnum = T6_VARYING; break;
+        case 7: instr->src[0].regnum = T7_VARYING; break;
+
+        default:
+            asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, dst->regnum);
+            instr->src[0].regnum = 0;
+            set_parse_status(This, PARSE_ERR);
+    }
+    instr->src[0].swizzle = BWRITERVS_NOSWIZZLE;
+    instr->src[0].srcmod = BWRITERSPSM_NONE;
+    instr->src[0].rel_reg = NULL;
+
+    /* The 2nd source register is the sampler register with the
+     * destination's regnum
+     */
+    memset(&instr->src[1], 0, 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_texreg2ar(struct asm_parser *This,
+                                const struct shader_reg *dst,
+                                const struct shader_reg *src0) {
+    struct instruction *instr = alloc_instr(2);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = BWRITERSIO_TEX;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+    /* The dest register can be mapped normally to a temporary register */
+    This->funcs->dstreg(This, instr, dst);
+    /* The src register is the temporary register form of tX as well - map
+     * it normally
+     */
+    This->funcs->srcreg(This, instr, 0, src0);
+    /* However, supply a swizzle */
+    instr->src[0].swizzle = BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X;
+
+    /* The 2nd source register is the sampler register with the
+     * destination's regnum
+     */
+    memset(&instr->src[1], 0, 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_texreg2gb(struct asm_parser *This,
+                                const struct shader_reg *dst,
+                                const struct shader_reg *src0) {
+    struct instruction *instr = alloc_instr(2);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = BWRITERSIO_TEX;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+    /* The dest register can be mapped normally to a temporary register */
+    This->funcs->dstreg(This, instr, dst);
+    /* The src register is the temporary register form of tX as well - map
+     * it normally
+     */
+    This->funcs->srcreg(This, instr, 0, src0);
+    /* However, supply a swizzle */
+    instr->src[0].swizzle = BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z;
+
+    /* The 2nd source register is the sampler register with the
+     * destination's regnum
+     */
+    memset(&instr->src[1], 0, 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_texreg2rgb(struct asm_parser *This,
+                                 const struct shader_reg *dst,
+                                 const struct shader_reg *src0) {
+    struct instruction *instr = alloc_instr(2);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = BWRITERSIO_TEX;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+    /* The dest register can be mapped normally to a temporary register */
+    This->funcs->dstreg(This, instr, dst);
+    /* The src register is the temporary register form of tX as well - map
+     * it normally
+     */
+    This->funcs->srcreg(This, instr, 0, src0);
+    /* However, supply a swizzle */
+    instr->src[0].swizzle = BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Z;
+
+    /* The 2nd source register is the sampler register with the
+     * destination's regnum
+     */
+    memset(&instr->src[1], 0, 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);
+    }
+}
+
+/* special pixel shader 1.3 functions
+ * Those are a bit tricky - they can be expressed in newer shader models with normal
+ * arithmetic instructions and a dependent texture read. The padding instructions
+ * are normal 3-way dot products, but the texturing instructions are composed of two
+ * instructions. Recording them as two instructions is tricky since the bytecode and
+ * assembler instruction _writing_ code works without a context, so it can't write
+ * the two instructions as one
+ *
+ * The output modules have no idea about the ps_1_x register assignments(or rather,
+ * should not have - they can read the constants if they really want to), thus
+ * record the registers in the common fashion. Thus e.g. texm3x2pad has 3 registers,
+ * one destination register(the temp register incarnation of t(m+1), and two source
+ * registers, the varying form of t(m) and the temporary form of t(n).
+ */
+
+static void asmparser_texm3x2pad(struct asm_parser *This,
+                                 const struct shader_reg *dst,
+                                 const struct shader_reg *src0) {
+    struct instruction *instr = alloc_instr(2);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = BWRITERSIO_TEXM3x2PAD;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+
+    /* Use the temporary register incarnation of the dest register + 1.
+     * texm3x2pad with dest t(m) must be followed by an texm3x2XXX instruction
+     * with destination t(m+1). Write to the red component.
+     */
+    memset(&instr->dst, 0, sizeof(instr->dst));
+    instr->dst.type = BWRITERSPR_TEMP;
+    instr->dst.writemask = BWRITERSP_WRITEMASK_0;
+    switch(dst->regnum) {
+        case 0: instr->dst.regnum = T1_REG; break;
+        case 1: instr->dst.regnum = T2_REG; break;
+        case 2: instr->dst.regnum = T3_REG; break;
+        default:
+        FIXME("texm3x2pad with dest t%u\n", dst->regnum);
+        break;
+    }
+
+    /* The first register is the varying incarnation of the dest reg */
+    memset(&instr->src[0], 0, sizeof(instr->src[0]));
+    instr->src[0].type = BWRITERSPR_INPUT;
+    switch(dst->regnum) {
+        case 0: instr->src[0].regnum = T0_VARYING; break;
+        case 1: instr->src[0].regnum = T1_VARYING; break;
+        case 2: instr->src[0].regnum = T2_VARYING; break;
+
+        default:
+            asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, dst->regnum);
+            instr->src[0].regnum = 0;
+            set_parse_status(This, PARSE_ERR);
+    }
+    instr->src[0].swizzle = BWRITERVS_NOSWIZZLE;
+    instr->src[0].srcmod = BWRITERSPSM_NONE;
+    instr->src[0].rel_reg = NULL;
+
+    /* The 2nd source is the temporary form of the t(n) source register -
+     * map it normally
+     */
+    This->funcs->srcreg(This, instr, 1, src0);
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+
+static void asmparser_texm3x3pad(struct asm_parser *This,
+                                 const struct shader_reg *dst,
+                                 const struct shader_reg *src0) {
+    struct instruction *instr = alloc_instr(2);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = BWRITERSIO_TEXM3x3PAD;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+
+    /* Use the temporary register incarnation of the dest register + 1.
+     * texm3x2pad with dest t(m) must be followed by an texm3x2XXX instruction
+     * with destination t(m+1). Write to the red component.
+     */
+    memset(&instr->dst, 0, sizeof(instr->dst));
+    instr->dst.type = BWRITERSPR_TEMP;
+    instr->dst.writemask = BWRITERSP_WRITEMASK_0;
+    switch(dst->regnum - This->m3x3pad_count) {
+        case 0: instr->dst.regnum = T2_REG; break;
+        case 1: instr->dst.regnum = T3_REG; break;
+        default:
+        FIXME("texm3x3pad with dest t%u, %s instruction\n", dst->regnum,
+              This->m3x3pad_count == 0 ? "first" : "second");
+        break;
+    }
+
+    /* The first register is the varying incarnation of the dest reg */
+    memset(&instr->src[0], 0, sizeof(instr->src[0]));
+    instr->src[0].type = BWRITERSPR_INPUT;
+    switch(dst->regnum) {
+        case 0: instr->src[0].regnum = T0_VARYING; break;
+        case 1: instr->src[0].regnum = T1_VARYING; break;
+        case 2: instr->src[0].regnum = T2_VARYING; break;
+        case 3: instr->src[0].regnum = T3_VARYING; break;
+
+        default:
+            asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, dst->regnum);
+            instr->src[0].regnum = 0;
+            set_parse_status(This, PARSE_ERR);
+    }
+    instr->src[0].swizzle = BWRITERVS_NOSWIZZLE;
+    instr->src[0].srcmod = BWRITERSPSM_NONE;
+    instr->src[0].rel_reg = NULL;
+
+    /* The 2nd source is the temporary form of the t(n) source register -
+     * map it normally
+     */
+    This->funcs->srcreg(This, instr, 1, src0);
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+
+    /* Increment the m3x3pad counter so the next time the function is called
+     * it knows that it deals with the 2nd instruction
+     */
+    This->m3x3pad_count++;
+}
+
+static void asmparser_texm3x3helper(struct asm_parser *This,
+                                    const struct shader_reg *dst,
+                                    const struct shader_reg *src0,
+                                    const struct shader_reg *src1,
+                                    DWORD instruction) {
+    struct instruction *instr;
+    if(src1) instr = alloc_instr(2);
+    else instr = alloc_instr(1);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = instruction;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+
+    /* No special surprises here - The destination is the temporary register
+     * form of the t(m+2) destination register passed in here. This specifies
+     * the implicit source register of the first and second row multiplications,
+     * which is identical to the source(the texture fetch overwrites the matrix
+     * multiplication, except for texm3x3) */
+    This->funcs->dstreg(This, instr, dst);
+
+    /* The first register is the varying incarnation of the src reg */
+    memset(&instr->src[0], 0, sizeof(instr->src[0]));
+    instr->src[0].type = BWRITERSPR_INPUT;
+    switch(src0->regnum) {
+        case 0: instr->src[0].regnum = T0_VARYING; break;
+        case 1: instr->src[0].regnum = T1_VARYING; break;
+        case 2: instr->src[0].regnum = T2_VARYING; break;
+        case 3: instr->src[0].regnum = T3_VARYING; break;
+
+        default:
+            asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, src0->regnum);
+            instr->src[0].regnum = 0;
+            set_parse_status(This, PARSE_ERR);
+    }
+    instr->src[0].swizzle = BWRITERVS_NOSWIZZLE;
+    instr->src[0].srcmod = BWRITERSPSM_NONE;
+    instr->src[0].rel_reg = NULL;
+
+    if(src1) {
+        /* The 2nd source is the temporary form of the t(n) source register -
+         * map it normally - if it exists. texm3x3 and texm3x3tex do not
+         * have a 2nd source
+         */
+        This->funcs->srcreg(This, instr, 1, src1);
+    }
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+
+    /* Reset the m3x3pad counter.
+     */
+    This->m3x3pad_count = 0;
+}
+
+static void asmparser_texm3x3spec(struct asm_parser *This,
+                                  const struct shader_reg *dst,
+                                  const struct shader_reg *src0,
+                                  const struct shader_reg *src1) {
+    asmparser_texm3x3helper(This, dst, src0, src1, BWRITERSIO_TEXM3x3SPEC);
+}
+static void asmparser_texm3x3vspec(struct asm_parser *This,
+                                   const struct shader_reg *dst,
+                                   const struct shader_reg *src0) {
+    asmparser_texm3x3helper(This, dst, src0, NULL, BWRITERSIO_TEXM3x3VSPEC);
+}
+static void asmparser_texm3x3(struct asm_parser *This,
+                              const struct shader_reg *dst,
+                              const struct shader_reg *src0) {
+    asmparser_texm3x3helper(This, dst, src0, NULL, BWRITERSIO_TEXM3x3);
+}
+static void asmparser_texm3x3tex(struct asm_parser *This,
+                                 const struct shader_reg *dst,
+                                 const struct shader_reg *src0) {
+    asmparser_texm3x3helper(This, dst, src0, NULL, BWRITERSIO_TEXM3x3TEX);
+}
+
+static void asmparser_tex1phelper(struct asm_parser *This,
+                                  const struct shader_reg *dst,
+                                  const struct shader_reg *src0,
+                                  DWORD instruction) {
+    struct instruction *instr = alloc_instr(2);
+
+    if(!instr) {
+        ERR("Error allocating memory for the instruction\n");
+        set_parse_status(This, PARSE_ERR);
+        return;
+    }
+
+    instr->opcode = instruction;
+    instr->dstmod = 0;
+    instr->shift = 0;
+    instr->comptype = 0;
+
+    /* No special surprises here - The destination is the temporary register
+     * form of the tm destination register passed in here. No implicit
+     * source-in-destination is involved in texdp3 and texdp3tex, except
+     * of the varying for the multiplication
+     */
+    This->funcs->dstreg(This, instr, dst);
+
+    /* The first register is the varying incarnation of the dst reg */
+    memset(&instr->src[0], 0, sizeof(instr->src[0]));
+    instr->src[0].type = BWRITERSPR_INPUT;
+    switch(dst->regnum) {
+        case 0: instr->src[0].regnum = T0_VARYING; break;
+        case 1: instr->src[0].regnum = T1_VARYING; break;
+        case 2: instr->src[0].regnum = T2_VARYING; break;
+        case 3: instr->src[0].regnum = T3_VARYING; break;
+
+        default:
+            asmparser_message(This, "Line %u: Unexpected TEXTURE register number %u\n", This->line_no, src0->regnum);
+            instr->src[0].regnum = 0;
+            set_parse_status(This, PARSE_ERR);
+    }
+    instr->src[0].swizzle = BWRITERVS_NOSWIZZLE;
+    instr->src[0].srcmod = BWRITERSPSM_NONE;
+    instr->src[0].rel_reg = NULL;
+
+    /* The 2nd source is the temporary form of the t(n) source register -
+     * map it normally
+     */
+    This->funcs->srcreg(This, instr, 1, src0);
+
+    if(!add_instruction(This->shader, instr)) {
+        ERR("Out of memory\n");
+        set_parse_status(This, PARSE_ERR);
+    }
+}
+static void asmparser_texdp3tex(struct asm_parser *This,
+                                const struct shader_reg *dst,
+                                const struct shader_reg *src0) {
+    asmparser_tex1phelper(This, dst, src0, BWRITERSIO_TEXDP3TEX);
+}
+
+static void asmparser_texdp3(struct asm_parser *This,
+                             const struct shader_reg *dst,
+                             const struct shader_reg *src0) {
+    asmparser_tex1phelper(This, dst, src0, BWRITERSIO_TEXDP3);
+}
+
+static void asmparser_tex3x2depth(struct asm_parser *This,
+                                  const struct shader_reg *dst,
+                                  const struct shader_reg *src0) {
+    asmparser_tex1phelper(This, dst, src0, BWRITERSIO_TEXM3x2DEPTH);
+}
+
+static void asmparser_tex3x2tex(struct asm_parser *This,
+                                const struct shader_reg *dst,
+                                const struct shader_reg *src0) {
+    asmparser_tex1phelper(This, dst, src0, BWRITERSIO_TEXM3x2TEX);
+}
+
 static void asmparser_instr(struct asm_parser *This, DWORD opcode,
                             DWORD mod, DWORD shift,
                             BWRITER_COMPARISON_TYPE comp,
@@ -126,12 +722,77 @@ static void asmparser_instr(struct asm_parser *This, DWORD opcode,
     }
     TRACE_(parsed_shader)("\n");
 
+    /* Check for instructions with different syntaxes in different shader versions */
+    switch(opcode) {
+        case BWRITERSIO_TEXCOORD:
+            /* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */
+            asmparser_texcoord(This, 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, 1) ||
+               This->shader->version == BWRITERPS_VERSION(1, 2) ||
+               This->shader->version == BWRITERPS_VERSION(1, 3)) {
+                asmparser_tex(This, dst);
+                return;
+            }
+            /* else fallback to the standard behavior */
+            break;
+    }
+
     if(src_count != expectednsrcs) {
         asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
         set_parse_status(This, PARSE_ERR);
         return;
     }
 
+    /* Handle PS 1.x instructions, "regularizing" them */
+    switch(opcode) {
+        case BWRITERSIO_TEXKILL:
+            asmparser_texkill(This, dst);
+            return;
+        case BWRITERSIO_TEXREG2AR:
+            asmparser_texreg2ar(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXREG2GB:
+            asmparser_texreg2gb(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXREG2RGB:
+            asmparser_texreg2rgb(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x2PAD:
+            asmparser_texm3x2pad(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x3PAD:
+            asmparser_texm3x3pad(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x3SPEC:
+            asmparser_texm3x3spec(This, dst, &srcs->reg[0], &srcs->reg[1]);
+            return;
+        case BWRITERSIO_TEXM3x3VSPEC:
+            asmparser_texm3x3vspec(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x3:
+            asmparser_texm3x3(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x3TEX:
+            asmparser_texm3x3tex(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXDP3TEX:
+            asmparser_texdp3tex(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXDP3:
+            asmparser_texdp3(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x2DEPTH:
+            asmparser_tex3x2depth(This, dst, &srcs->reg[0]);
+            return;
+        case BWRITERSIO_TEXM3x2TEX:
+            asmparser_tex3x2tex(This, dst, &srcs->reg[0]);
+            return;
+    }
+
     instr = alloc_instr(src_count);
     if(!instr) {
         ERR("Error allocating memory for the instruction\n");
@@ -415,6 +1076,30 @@ static void asmparser_srcreg_vs_3(struct asm_parser *This,
     memcpy(&instr->src[num], src, sizeof(*src));
 }
 
+struct allowed_reg_type ps_1_0123_reg_allowed[] = {
+    { BWRITERSPR_CONST,     8 },
+    { BWRITERSPR_TEMP,      2 },
+    { BWRITERSPR_TEXTURE,   4 },
+    { BWRITERSPR_INPUT,     2 },
+    { ~0U, 0 } /* End tag */
+};
+
+static void asmparser_srcreg_ps_1_0123(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_0123_reg_allowed)) {
+        asmparser_message(This, "Line %u: Source register %s not supported in <== PS 1.3\n",
+                          This->line_no,
+                          debug_print_srcreg(src, ST_PIXEL));
+        set_parse_status(This, PARSE_ERR);
+    }
+    check_abs_srcmod(This, src->srcmod);
+    reg = map_oldps_register(src, FALSE);
+    memcpy(&instr->src[num], &reg, sizeof(reg));
+}
+
 struct allowed_reg_type ps_2_0_reg_allowed[] = {
     { BWRITERSPR_INPUT,      2 },
     { BWRITERSPR_TEMP,      32 },
@@ -552,6 +1237,22 @@ static void asmparser_dstreg_vs_3(struct asm_parser *This,
     instr->has_dst = TRUE;
 }
 
+static void asmparser_dstreg_ps_1_0123(struct asm_parser *This,
+                                       struct instruction *instr,
+                                       const struct shader_reg *dst) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(dst, ps_1_0123_reg_allowed)) {
+        asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
+                          This->line_no,
+                          debug_print_dstreg(dst, ST_PIXEL));
+        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) {
@@ -616,6 +1317,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);
@@ -681,6 +1392,26 @@ static struct asmparser_backend parser_vs_3 = {
     asmparser_instr,
 };
 
+static struct asmparser_backend parser_ps_1_0123 = {
+    asmparser_constF,
+    asmparser_constI,
+    asmparser_constB,
+
+    asmparser_dstreg_ps_1_0123,
+    asmparser_srcreg_ps_1_0123,
+
+    asmparser_predicate_unsupported,
+    asmparser_coissue_supported,
+
+    asmparser_dcl_output,
+    asmparser_dcl_input,
+    asmparser_dcl_sampler,
+
+    asmparser_end,
+
+    asmparser_instr,
+};
+
 static struct asmparser_backend parser_ps_2 = {
     asmparser_constF,
     asmparser_constI,
@@ -851,6 +1582,70 @@ void create_vs30_parser(struct asm_parser *ret) {
     ret->funcs = &parser_vs_3;
 }
 
+void create_ps10_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_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_PIXEL;
+    ret->shader->version = BWRITERPS_VERSION(1, 0);
+    ret->funcs = &parser_ps_1_0123;
+    gen_oldps_input(ret->shader, 4);
+}
+
+void create_ps11_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_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_PIXEL;
+    ret->shader->version = BWRITERPS_VERSION(1, 1);
+    ret->funcs = &parser_ps_1_0123;
+    gen_oldps_input(ret->shader, 4);
+}
+
+void create_ps12_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_1_2\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, 2);
+    ret->funcs = &parser_ps_1_0123;
+    gen_oldps_input(ret->shader, 4);
+}
+
+void create_ps13_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_1_3\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, 3);
+    ret->funcs = &parser_ps_1_0123;
+    gen_oldps_input(ret->shader, 4);
+}
+
 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 653d4e9..bbb8247 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -325,22 +325,22 @@ version_marker:       VER_VS10
                     | VER_PS10
                         {
                             TRACE("Pixel  shader 1.0\n");
-                            /* TODO: create the appropriate parser context */
+                            create_ps10_parser(ctx);
                         }
                     | VER_PS11
                         {
                             TRACE("Pixel  shader 1.1\n");
-                            /* TODO: create the appropriate parser context */
+                            create_ps11_parser(ctx);
                         }
                     | VER_PS12
                         {
                             TRACE("Pixel  shader 1.2\n");
-                            /* TODO: create the appropriate parser context */
+                            create_ps12_parser(ctx);
                         }
                     | VER_PS13
                         {
                             TRACE("Pixel  shader 1.3\n");
-                            /* TODO: create the appropriate parser context */
+                            create_ps13_parser(ctx);
                         }
                     | VER_PS14
                         {
diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
index 1090bce..a4eacab 100644
--- a/dlls/d3dx9_36/bytecodewriter.c
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -587,6 +587,18 @@ static void ps_legacy_header(struct bc_writer *This, const struct bwriter_shader
     return;
 }
 
+static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
+    /* 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;
+    }
+
+    ps_legacy_header(This, shader, buffer, 4, FALSE);
+}
+
 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
     put_dword(buffer, D3DSIO_END);
 }
@@ -819,6 +831,27 @@ static void write_srcregs(struct bc_writer *This, const struct instruction *inst
     }
 }
 
+static DWORD map_ps13_temp(struct bc_writer *This, const struct shader_reg *reg) {
+    DWORD token = 0;
+    if(reg->regnum == T0_REG) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == T1_REG) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == T2_REG) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 2 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == T3_REG) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 3 & D3DSP_REGNUM_MASK; /* No shift */
+    } else {
+        token |= (D3DSPR_TEMP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+    }
+    return token;
+}
+
 static DWORD map_ps1x_varying(struct bc_writer *This,
                               const struct shader_reg *reg) {
     DWORD token = 0;
@@ -863,6 +896,90 @@ static DWORD map_ps1x_varying(struct bc_writer *This,
     return token;
 }
 
+static void ps_1_0123_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_ps1x_varying(This, reg);
+            break;
+
+            /* Take care about the texture temporaries. There's a problem: They aren't
+             * declared anywhere, so we can only hardcode the values that are used
+             * to map ps_1_3 shaders to the common shader structure
+             */
+        case BWRITERSPR_TEMP:
+            token |= map_ps13_temp(This, reg);
+            break;
+
+        case BWRITERSPR_CONST: /* Can be mapped 1:1 */
+            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_3 shader\n");
+            This->state = E_INVALIDARG;
+            return;
+    }
+
+    token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
+
+    if(reg->srcmod == BWRITERSPSM_DZ || reg->srcmod == BWRITERSPSM_DW ||
+       reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
+       reg->srcmod == BWRITERSPSM_NOT) {
+        WARN("Invalid source modifier %u for <= ps_1_3\n", reg->srcmod);
+        This->state = E_INVALIDARG;
+        return;
+    }
+    token |= d3d9_srcmod(reg->srcmod);
+    put_dword(buffer, token);
+}
+
+static void ps_1_0123_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:
+            token |= map_ps13_temp(This, reg);
+            break;
+
+        /* Some instructions like texkill have only a destination register parameter,
+         * although the instruction reads from the register. The register bytecode has
+         * a dest reg form, that's why it runs through this method. That means it has
+         * to handle BWRITERSPR_INPUT destinations
+         */
+        case BWRITERSPR_INPUT:
+            token |= map_ps1x_varying(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);
+}
+
 /* The length of an instruction consists of the destination register (if any),
  * the number of source registers, the number of address registers used for
  * indirect addressing, and optionally the predicate register
@@ -942,6 +1059,194 @@ static struct bytecode_backend vs_1_x_backend = {
     vs_1_x_handlers
 };
 
+static void instr_ps_1_0123_texld(struct bc_writer *This,
+                                  const struct instruction *instr,
+                                  struct bytecode_buffer *buffer) {
+    DWORD idx, srcidx;
+    struct shader_reg reg;
+
+    if(instr->src[1].type != BWRITERSPR_SAMPLER ||
+       instr->src[1].regnum > 3) {
+        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;
+    }
+
+    idx = instr->src[1].regnum;
+    if((idx == 0 && instr->dst.regnum != T0_REG) ||
+       (idx == 1 && instr->dst.regnum != T1_REG) ||
+       (idx == 2 && instr->dst.regnum != T2_REG) ||
+       (idx == 3 && instr->dst.regnum != T3_REG)) {
+        WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_x\n",
+             idx, instr->dst.regnum);
+        This->state = E_INVALIDARG;
+        return;
+    }
+
+    if(instr->src[0].type == BWRITERSPR_INPUT) {
+        /* A simple non-dependent read tex instruction */
+        if(instr->src[0].regnum != This->t_regnum[idx]) {
+            WARN("Cannot sample from s%u with texture address data from interpolator %u\n",
+                 idx, instr->src[0].regnum);
+            This->state = E_INVALIDARG;
+            return;
+        }
+        This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
+
+        /* map the temp dstreg to the ps_1_3 texture temporary register */
+        This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+    } else if(instr->src[0].type == BWRITERSPR_TEMP) {
+        if(instr->src[0].regnum == T0_REG) {
+            srcidx = 0;
+        } else if(instr->src[0].regnum == T1_REG) {
+            srcidx = 1;
+        } else if(instr->src[0].regnum == T2_REG) {
+            srcidx = 2;
+        } else if(instr->src[0].regnum == T3_REG) {
+            srcidx = 3;
+        } else {
+            WARN("Invalid address data source register r%u\n", instr->src[0].regnum);
+        }
+
+        if(instr->src[0].swizzle == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_W) ||
+           instr->src[0].swizzle == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Z) ||
+           instr->src[0].swizzle == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Y) ||
+           instr->src[0].swizzle == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_X)) {
+            TRACE("writing texreg2rgb\n");
+            This->funcs->opcode(This, instr, D3DSIO_TEXREG2RGB & D3DSI_OPCODE_MASK, buffer);
+        } else if(instr->src[0].swizzle == (BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X)) {
+            TRACE("writing texreg2ar\n");
+            This->funcs->opcode(This, instr, D3DSIO_TEXREG2AR & D3DSI_OPCODE_MASK, buffer);
+        } else if(instr->src[0].swizzle == (BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z)) {
+            TRACE("writing texreg2gb\n");
+            This->funcs->opcode(This, instr, D3DSIO_TEXREG2GB & D3DSI_OPCODE_MASK, buffer);
+        } else {
+            WARN("Unsupported src addr swizzle in dependent texld: 0x%08x\n", instr->src[0].swizzle);
+            This->state = E_INVALIDARG;
+            return;
+        }
+
+        /* Dst and src reg can be mapped normally. Both registers are temporary registers in the
+         * source shader and have to be mapped to the temporary form of the texture registers. However,
+         * the src reg doesn't have a swizzle
+         */
+        This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+        reg = instr->src[0];
+        reg.swizzle = BWRITERVS_NOSWIZZLE;
+        This->funcs->srcreg(This, &reg, buffer);
+    } else {
+        WARN("Invalid address data source register\n");
+        This->state = E_INVALIDARG;
+        return;
+    }
+}
+
+static void instr_tex2phandler(struct bc_writer *This,
+                               const struct instruction *instr,
+                               struct bytecode_buffer *buffer) {
+    struct shader_reg reg;
+    DWORD token = d3d9_opcode(instr->opcode) & D3DSI_OPCODE_MASK;
+
+    This->funcs->opcode(This, instr, token, buffer);
+
+    /* The dest reg is not interesting, it is just an information for newer shader
+     * versions that do not have native texm3x2* instructions. It is the dest reg
+     * of the final instruction. The first source is the temp register incarnation of the
+     * originally provided dest reg. Use it and map it to the texture register.
+     * Set the writemask to WRITEMASK_ALL, since the instruction is recorded with a
+     * writemask indicating which component the current texm3x2 instruction writes to
+     */
+    reg = instr->src[0];
+    reg.writemask = BWRITERSP_WRITEMASK_ALL;
+    This->funcs->dstreg(This, &reg, buffer, instr->shift, instr->dstmod);
+
+    /* The 2nd source is the varying form of the source register. Map it to the
+     * texture register as well
+     */
+    reg = instr->src[1];
+    This->funcs->srcreg(This, &instr->src[1], buffer);
+}
+
+static void instr_ps_1_0123_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->dst.regnum == T0_REG && instr->src[0].regnum == This->t_regnum[0]) ||
+           (instr->dst.regnum == T1_REG && instr->src[0].regnum == This->t_regnum[1]) ||
+           (instr->dst.regnum == T2_REG && instr->src[0].regnum == This->t_regnum[2]) ||
+           (instr->dst.regnum == T3_REG && instr->src[0].regnum == This->t_regnum[3])) {
+            if(instr->dstmod & BWRITERSPDM_SATURATE) {
+                This->funcs->opcode(This, instr, D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK, buffer);
+                /* Remove the SATURATE flag which the writer sets */
+                This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod & (~BWRITERSPDM_SATURATE));
+                return;
+            } else {
+                WARN("A varying -> temp copy is only supported with the SATURATE modifier in <=ps_1_3\n");
+                This->state = E_INVALIDARG;
+                return;
+            }
+        } 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_3\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);
+}
+
+struct instr_handler_table ps_1_0123_handlers[] = {
+    {BWRITERSIO_ADD,            instr_handler},
+    {BWRITERSIO_NOP,            instr_handler},
+    {BWRITERSIO_MOV,            instr_ps_1_0123_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_0123_texld},
+    {BWRITERSIO_TEXBEM,         instr_handler},
+    {BWRITERSIO_TEXBEML,        instr_handler},
+    {BWRITERSIO_TEXM3x2PAD,     instr_tex2phandler},
+    {BWRITERSIO_TEXM3x3PAD,     instr_tex2phandler},
+    {BWRITERSIO_TEXM3x3SPEC,    instr_handler},
+    {BWRITERSIO_TEXM3x3VSPEC,   instr_handler},
+    {BWRITERSIO_TEXM3x3TEX,     instr_handler},
+    {BWRITERSIO_TEXM3x3,        instr_handler},
+    {BWRITERSIO_TEXM3x2DEPTH,   instr_tex2phandler},
+    {BWRITERSIO_TEXM3x2TEX,     instr_tex2phandler},
+    {BWRITERSIO_TEXDP3,         instr_tex2phandler},
+    {BWRITERSIO_TEXDP3TEX,      instr_tex2phandler},
+    {BWRITERSIO_END,            NULL},
+};
+
+static struct bytecode_backend ps_1_0123_backend = {
+    ps_1_x_header,
+    end,
+    ps_1_0123_srcreg,
+    ps_1_0123_dstreg,
+    sm_1_x_opcode,
+    ps_1_0123_handlers
+};
+
 static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
     DWORD i;
     DWORD instr_def = D3DSIO_DEFB;
@@ -1813,6 +2118,26 @@ static void init_vs30_dx9_writer(struct bc_writer *writer) {
     writer->funcs = &vs_3_backend;
 }
 
+static void init_ps10_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 pixel shader 1.0 writer\n");
+    writer->funcs = &ps_1_0123_backend;
+}
+
+static void init_ps11_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 pixel shader 1.1 writer\n");
+    writer->funcs = &ps_1_0123_backend;
+}
+
+static void init_ps12_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 pixel shader 1.2 writer\n");
+    writer->funcs = &ps_1_0123_backend;
+}
+
+static void init_ps13_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 pixel shader 1.3 writer\n");
+    writer->funcs = &ps_1_0123_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;
@@ -1878,28 +2203,28 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
                 WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps10_dx9_writer(ret);
             break;
         case BWRITERPS_VERSION(1, 1):
             if(dxversion != 9) {
                 WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps11_dx9_writer(ret);
             break;
         case BWRITERPS_VERSION(1, 2):
             if(dxversion != 9) {
                 WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps12_dx9_writer(ret);
             break;
         case BWRITERPS_VERSION(1, 3):
             if(dxversion != 9) {
                 WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps13_dx9_writer(ret);
             break;
         case BWRITERPS_VERSION(1, 4):
             if(dxversion != 9) {
-- 
1.6.3.3


More information about the wine-patches mailing list