[8/18] d3dx9: Shader assembler PS 2.X support

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


-------------- next part --------------
From 137377fcf093c2c1c9ed8e0b1e66754aa2a86a89 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sun, 16 Aug 2009 00:26:04 +0200
Subject: d3dx9: Shader assembler PS 2.X support

---
 dlls/d3dx9_36/asmparser.c      |  227 ++++++++++++++++++++++++
 dlls/d3dx9_36/asmshader.y      |    4 +-
 dlls/d3dx9_36/bytecodewriter.c |  384 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 611 insertions(+), 4 deletions(-)

diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
index 0d2ecc3..c268a0a 100644
--- a/dlls/d3dx9_36/asmparser.c
+++ b/dlls/d3dx9_36/asmparser.c
@@ -209,6 +209,52 @@ static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
     }
 }
 
+static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
+    struct shader_reg ret;
+    switch(reg->type) {
+        case BWRITERSPR_TEXTURE:
+            if(tex_varying) {
+                ret = *reg;
+                ret.type = BWRITERSPR_INPUT;
+                switch(reg->regnum) {
+                    case 0:     ret.regnum = T0_VARYING; break;
+                    case 1:     ret.regnum = T1_VARYING; break;
+                    case 2:     ret.regnum = T2_VARYING; break;
+                    case 3:     ret.regnum = T3_VARYING; break;
+                    case 4:     ret.regnum = T4_VARYING; break;
+                    case 5:     ret.regnum = T5_VARYING; break;
+                    case 6:     ret.regnum = T6_VARYING; break;
+                    case 7:     ret.regnum = T7_VARYING; break;
+                    default:
+                        FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
+                        return *reg;
+                }
+                return ret;
+            } else {
+                ret = *reg;
+                ret.type = BWRITERSPR_TEMP;
+                switch(reg->regnum) {
+                    case 0:     ret.regnum = T0_REG; break;
+                    case 1:     ret.regnum = T1_REG; break;
+                    case 2:     ret.regnum = T2_REG; break;
+                    case 3:     ret.regnum = T3_REG; break;
+                    default:
+                        FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
+                        return *reg;
+                }
+                return ret;
+            }
+
+        /* case BWRITERSPR_INPUT - Identical map of 1.x/2.0 color varyings
+         * Later on we may want to map 0 to C0_VARYING and 1 to C1_VARYING,
+         * but not until this function is only called for 1.x and 2.0 pixel
+         * shaders
+         */
+
+        default: return *reg;
+    }
+}
+
 /* Checks if the source modifier is not supported in VS (all versions) or
    PS 2.0 and newer */
 static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
@@ -328,6 +374,68 @@ static void asmparser_srcreg_vs_3(struct asm_parser *This,
     memcpy(&instr->src[num], src, sizeof(*src));
 }
 
+struct allowed_reg_type ps_2_0_reg_allowed[] = {
+    { BWRITERSPR_INPUT,      2 },
+    { BWRITERSPR_TEMP,      32 },
+    { BWRITERSPR_CONST,     32 },
+    { BWRITERSPR_CONSTINT,  16 },
+    { BWRITERSPR_CONSTBOOL, 16 },
+    { BWRITERSPR_SAMPLER,   16 },
+    { BWRITERSPR_TEXTURE,    8 },
+    { BWRITERSPR_COLOROUT, ~0U },
+    { BWRITERSPR_DEPTHOUT,   1 },
+    { ~0U, 0 } /* End tag */
+};
+
+static void asmparser_srcreg_ps_2(struct asm_parser *This,
+                                  struct instruction *instr, int num,
+                                  const struct shader_reg *src) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(src, ps_2_0_reg_allowed)) {
+        asmparser_message(This, "Line %u: Source register %s not supported in PS 2.0\n",
+                          This->line_no,
+                          debug_print_srcreg(src, ST_PIXEL));
+        set_parse_status(This, PARSE_ERR);
+    }
+    check_legacy_srcmod(This, src->srcmod);
+    check_abs_srcmod(This, src->srcmod);
+    reg = map_oldps_register(src, TRUE);
+    memcpy(&instr->src[num], &reg, sizeof(reg));
+}
+
+struct allowed_reg_type ps_2_x_reg_allowed[] = {
+    { BWRITERSPR_INPUT,      2 },
+    { BWRITERSPR_TEMP,      32 },
+    { BWRITERSPR_CONST,     32 },
+    { BWRITERSPR_CONSTINT,  16 },
+    { BWRITERSPR_CONSTBOOL, 16 },
+    { BWRITERSPR_PREDICATE,  1 },
+    { BWRITERSPR_SAMPLER,   16 },
+    { BWRITERSPR_TEXTURE,    8 },
+    { BWRITERSPR_LABEL,     16 },
+    { BWRITERSPR_COLOROUT, ~0U },
+    { BWRITERSPR_DEPTHOUT,   1 },
+    { ~0U, 0 } /* End tag */
+};
+
+static void asmparser_srcreg_ps_2_x(struct asm_parser *This,
+                                    struct instruction *instr, int num,
+                                    const struct shader_reg *src) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(src, ps_2_x_reg_allowed)) {
+        asmparser_message(This, "Line %u: Source register %s not supported in PS 2.x\n",
+                          This->line_no,
+                          debug_print_srcreg(src, ST_PIXEL));
+        set_parse_status(This, PARSE_ERR);
+    }
+    check_legacy_srcmod(This, src->srcmod);
+    check_abs_srcmod(This, src->srcmod);
+    reg = map_oldps_register(src, TRUE);
+    memcpy(&instr->src[num], &reg, sizeof(reg));
+}
+
 struct allowed_reg_type ps_3_reg_allowed[] = {
     { BWRITERSPR_INPUT,     10 },
     { BWRITERSPR_TEMP,      32 },
@@ -387,6 +495,38 @@ static void asmparser_dstreg_vs_3(struct asm_parser *This,
     instr->has_dst = TRUE;
 }
 
+static void asmparser_dstreg_ps_2(struct asm_parser *This,
+                                  struct instruction *instr,
+                                  const struct shader_reg *dst) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(dst, ps_2_0_reg_allowed)) {
+        asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.0\n",
+                          This->line_no,
+                          debug_print_dstreg(dst, ST_PIXEL));
+        set_parse_status(This, PARSE_ERR);
+    }
+    reg = map_oldps_register(dst, TRUE);
+    memcpy(&instr->dst, &reg, sizeof(reg));
+    instr->has_dst = TRUE;
+}
+
+static void asmparser_dstreg_ps_2_x(struct asm_parser *This,
+                                    struct instruction *instr,
+                                    const struct shader_reg *dst) {
+    struct shader_reg reg;
+
+    if(!check_reg_type(dst, ps_2_x_reg_allowed)) {
+        asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.x\n",
+                          This->line_no,
+                          debug_print_dstreg(dst, ST_PIXEL));
+        set_parse_status(This, PARSE_ERR);
+    }
+    reg = map_oldps_register(dst, TRUE);
+    memcpy(&instr->dst, &reg, sizeof(reg));
+    instr->has_dst = TRUE;
+}
+
 static void asmparser_dstreg_ps_3(struct asm_parser *This,
                                   struct instruction *instr,
                                   const struct shader_reg *dst) {
@@ -464,6 +604,46 @@ static struct asmparser_backend parser_vs_3 = {
     asmparser_instr,
 };
 
+static struct asmparser_backend parser_ps_2 = {
+    asmparser_constF,
+    asmparser_constI,
+    asmparser_constB,
+
+    asmparser_dstreg_ps_2,
+    asmparser_srcreg_ps_2,
+
+    asmparser_predicate_unsupported,
+    asmparser_coissue_unsupported,
+
+    asmparser_dcl_output,
+    asmparser_dcl_input,
+    asmparser_dcl_sampler,
+
+    asmparser_end,
+
+    asmparser_instr,
+};
+
+static struct asmparser_backend parser_ps_2_x = {
+    asmparser_constF,
+    asmparser_constI,
+    asmparser_constB,
+
+    asmparser_dstreg_ps_2_x,
+    asmparser_srcreg_ps_2_x,
+
+    asmparser_predicate_supported,
+    asmparser_coissue_unsupported,
+
+    asmparser_dcl_output,
+    asmparser_dcl_input,
+    asmparser_dcl_sampler,
+
+    asmparser_end,
+
+    asmparser_instr,
+};
+
 static struct asmparser_backend parser_ps_3 = {
     asmparser_constF,
     asmparser_constI,
@@ -500,6 +680,21 @@ static void gen_oldvs_output(struct bwriter_shader *shader) {
     record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL);
 }
 
+static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) {
+    switch(texcoords) {
+        case 8: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, FALSE, T7_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 7: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, FALSE, T6_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 6: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, FALSE, T5_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 5: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, FALSE, T4_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 4: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, FALSE, T3_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 3: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, FALSE, T2_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 2: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, FALSE, T1_VARYING, BWRITERSP_WRITEMASK_ALL);
+        case 1: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, FALSE, T0_VARYING, BWRITERSP_WRITEMASK_ALL);
+    };
+    record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, FALSE, C0_VARYING, BWRITERSP_WRITEMASK_ALL);
+    record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL);
+}
+
 void create_vs20_parser(struct asm_parser *ret) {
     TRACE_(parsed_shader)("vs_2_0\n");
 
@@ -547,6 +742,38 @@ void create_vs30_parser(struct asm_parser *ret) {
     ret->funcs = &parser_vs_3;
 }
 
+void create_ps20_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_2_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(2, 0);
+    ret->funcs = &parser_ps_2;
+    gen_oldps_input(ret->shader, 8);
+}
+
+void create_ps2x_parser(struct asm_parser *ret) {
+    TRACE_(parsed_shader)("ps_2_x\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(2, 1);
+    ret->funcs = &parser_ps_2_x;
+    gen_oldps_input(ret->shader, 8);
+}
+
 void create_ps30_parser(struct asm_parser *ret) {
     TRACE_(parsed_shader)("ps_3_0\n");
 
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
index 598b38f..7e142ad 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -350,12 +350,12 @@ version_marker:       VER_VS10
                     | VER_PS20
                         {
                             TRACE("Pixel  shader 2.0\n");
-                            /* TODO: create the appropriate parser context */
+                            create_ps20_parser(ctx);
                         }
                     | VER_PS2X
                         {
                             TRACE("Pixel  shader 2.x\n");
-                            /* TODO: create the appropriate parser context */
+                            create_ps2x_parser(ctx);
                         }
                     | VER_PS30
                         {
diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
index e2077a5..a7d2322 100644
--- a/dlls/d3dx9_36/bytecodewriter.c
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -496,6 +496,72 @@ static HRESULT find_builtin_varyings(struct bc_writer *This, const struct bwrite
     return S_OK;
 }
 
+static void ps_legacy_header(struct bc_writer *This, const struct bwriter_shader *shader,
+                             struct bytecode_buffer *buffer, DWORD texcoords,
+                             BOOL has_instr_len) {
+    DWORD i;
+    DWORD usage, usage_idx, writemask, regnum;
+
+    This->v_regnum[0] = -1; This->v_regnum[1] = -1;
+    for(i = 0; i < 8; i++) This->t_regnum[i] = -1;
+
+    for(i = 0; i < shader->num_inputs; i++) {
+        usage = shader->inputs[i].usage;
+        usage_idx = shader->inputs[i].usage_idx;
+        writemask = shader->inputs[i].writemask;
+        regnum = shader->inputs[i].regnum;
+
+        switch(usage) {
+            case BWRITERDECLUSAGE_COLOR:
+                if(usage_idx > 1) {
+                    WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
+                    This->state = E_INVALIDARG;
+                    return;
+                }
+                if(writemask != BWRITERSP_WRITEMASK_ALL) {
+                    WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
+                    This->state = E_INVALIDARG;
+                    return;
+                }
+                TRACE("v%u is v%u\n", regnum, usage_idx);
+                This->v_regnum[usage_idx] = regnum;
+                break;
+
+            case BWRITERDECLUSAGE_TEXCOORD:
+                if(usage_idx > texcoords) {
+                    WARN("dcl_texcoord%u not supported in this shader version\n", usage_idx);
+                    This->state = E_INVALIDARG;
+                    return;
+                }
+
+                /* Accept .x, .xy and .xyz as full write masks. A HLSL generated shader might only use
+                 * two components, the others can be savely ignored
+                 */
+                if(writemask != (BWRITERSP_WRITEMASK_0) &&
+                   writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1) &&
+                   writemask != (BWRITERSP_WRITEMASK_0 | BWRITERSP_WRITEMASK_1 | BWRITERSP_WRITEMASK_2) &&
+                   writemask != (BWRITERSP_WRITEMASK_ALL)) {
+                    WARN("Partial writemasks not supported on texture coordinates in sm 1 and 2\n");
+                } else {
+                    writemask = BWRITERSP_WRITEMASK_ALL;
+                }
+                TRACE("v%u is t%u\n", regnum, usage_idx);
+                This->t_regnum[usage_idx] = regnum;
+                break;
+
+            default:
+                WARN("Varying type %u is not supported in shader model 1.x\n", usage);
+                This->state = E_INVALIDARG;
+                return;
+        }
+    }
+
+    /* Declare the shader type and version */
+    put_dword(buffer, This->version);
+    write_constF(shader, buffer, has_instr_len);
+    return;
+}
+
 static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
     put_dword(buffer, D3DSIO_END);
 }
@@ -651,6 +717,50 @@ static void write_srcregs(struct bc_writer *This, const struct instruction *inst
     }
 }
 
+static DWORD map_ps1x_varying(struct bc_writer *This,
+                              const struct shader_reg *reg) {
+    DWORD token = 0;
+    /* Map color interpolators */
+    if(reg->regnum == This->v_regnum[0]) {
+        token |= (D3DSPR_INPUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->v_regnum[1]) {
+        token |= (D3DSPR_INPUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
+        /* Texture coordinate interpolators */
+    } else if(reg->regnum == This->t_regnum[0]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[1]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[2]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 2 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[3]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 3 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[4]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 4 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[5]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 5 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[6]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 6 & D3DSP_REGNUM_MASK; /* No shift */
+    } else if(reg->regnum == This->t_regnum[7]) {
+        token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+        token |= 7 & D3DSP_REGNUM_MASK; /* No shift */
+    } else {
+        WARN("Invalid 1.x pshader varying\n");
+        This->state = E_INVALIDARG;
+        return token;
+    }
+
+    return 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
@@ -1035,6 +1145,266 @@ static void write_samplers(const struct bwriter_shader *shader, struct bytecode_
     }
 }
 
+static void ps_2_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
+    ps_legacy_header(This, shader, buffer, 8, TRUE);
+    write_samplers(shader, buffer);
+    write_constB(shader, buffer, TRUE);
+    write_constI(shader, buffer, TRUE);
+}
+
+static void ps_2_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 d3d9reg;
+    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;
+
+            /* Can be mapped 1:1 */
+        case BWRITERSPR_TEMP:
+        case BWRITERSPR_CONST:
+        case BWRITERSPR_COLOROUT:
+        case BWRITERSPR_CONSTBOOL:
+        case BWRITERSPR_CONSTINT:
+        case BWRITERSPR_SAMPLER:
+        case BWRITERSPR_LABEL:
+            d3d9reg = d3d9_register(reg->type);
+            token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+            token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+        case BWRITERSPR_DEPTHOUT:
+            token |= (D3DSPR_DEPTHOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= (D3DSPR_DEPTHOUT << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+            token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+        case BWRITERSPR_LOOP:
+            if(reg->regnum) {
+                WARN("Loop index register with regnum %u not supported in ps_2_0\n",
+                     reg->regnum);
+                This->state = E_INVALIDARG;
+            }
+            token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= (D3DSPR_LOOP << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+            token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+        case BWRITERSPR_PREDICATE:
+            if(This->version != BWRITERPS_VERSION(2, 1)){
+                WARN("Predicate register not supported in ps_2_0\n");
+                This->state = E_INVALIDARG;
+            }
+            if(reg->regnum) {
+                WARN("Predicate register with regnum %u not supported\n",
+                     reg->regnum);
+                This->state = E_INVALIDARG;
+            }
+            token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+            token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+        default:
+            WARN("Invalid register type for ps_2_0 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) {
+        WARN("Invalid source modifier %u for ps_2_0\n", reg->srcmod);
+        This->state = E_INVALIDARG;
+        return;
+    }
+    token |= d3d9_srcmod(reg->srcmod);
+    put_dword(buffer, token);
+}
+
+static void ps_2_0_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 */
+    DWORD d3d9reg;
+
+    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 */
+        case BWRITERSPR_COLOROUT:
+        case BWRITERSPR_DEPTHOUT:
+            d3d9reg = d3d9_register(reg->type);
+            token |= (d3d9reg << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= (d3d9reg << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+            token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+            break;
+
+        case BWRITERSPR_PREDICATE:
+            if(This->version != BWRITERPS_VERSION(2, 1)){
+                WARN("Predicate register not supported in ps_2_0\n");
+                This->state = E_INVALIDARG;
+            }
+            token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+            token |= (D3DSPR_PREDICATE << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+            token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+            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 2.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);
+}
+
+struct instr_handler_table ps_2_0_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_ABS,            instr_handler},
+    {BWRITERSIO_EXP,            instr_handler},
+    {BWRITERSIO_LOG,            instr_handler},
+    {BWRITERSIO_EXPP,           instr_handler},
+    {BWRITERSIO_LOGP,           instr_handler},
+    {BWRITERSIO_LRP,            instr_handler},
+    {BWRITERSIO_FRC,            instr_handler},
+    {BWRITERSIO_CRS,            instr_handler},
+    {BWRITERSIO_NRM,            instr_handler},
+    {BWRITERSIO_SINCOS,         instr_handler},
+    {BWRITERSIO_M4x4,           instr_handler},
+    {BWRITERSIO_M4x3,           instr_handler},
+    {BWRITERSIO_M3x4,           instr_handler},
+    {BWRITERSIO_M3x3,           instr_handler},
+    {BWRITERSIO_M3x2,           instr_handler},
+    {BWRITERSIO_POW,            instr_handler},
+    {BWRITERSIO_DP2ADD,         instr_handler},
+    {BWRITERSIO_CMP,            instr_handler},
+
+    {BWRITERSIO_TEX,            instr_handler},
+    {BWRITERSIO_TEX | ( BWRITERSI_TEXLD_PROJECT << BWRITER_OPCODESPECIFICCONTROL_SHIFT ),                       instr_handler},
+    {BWRITERSIO_TEX | ( BWRITERSI_TEXLD_BIAS << BWRITER_OPCODESPECIFICCONTROL_SHIFT ),                          instr_handler},
+    {BWRITERSIO_TEXKILL,        instr_handler},
+
+    {BWRITERSIO_END,            NULL},
+};
+
+static struct bytecode_backend ps_2_0_backend = {
+    ps_2_header,
+    end,
+    ps_2_srcreg,
+    ps_2_0_dstreg,
+    sm_2_opcode,
+    ps_2_0_handlers
+};
+
+struct instr_handler_table ps_2_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_ABS,            instr_handler},
+    {BWRITERSIO_EXP,            instr_handler},
+    {BWRITERSIO_LOG,            instr_handler},
+    {BWRITERSIO_EXPP,           instr_handler},
+    {BWRITERSIO_LOGP,           instr_handler},
+    {BWRITERSIO_LRP,            instr_handler},
+    {BWRITERSIO_FRC,            instr_handler},
+    {BWRITERSIO_CRS,            instr_handler},
+    {BWRITERSIO_NRM,            instr_handler},
+    {BWRITERSIO_SINCOS,         instr_handler},
+    {BWRITERSIO_M4x4,           instr_handler},
+    {BWRITERSIO_M4x3,           instr_handler},
+    {BWRITERSIO_M3x4,           instr_handler},
+    {BWRITERSIO_M3x3,           instr_handler},
+    {BWRITERSIO_M3x2,           instr_handler},
+    {BWRITERSIO_POW,            instr_handler},
+    {BWRITERSIO_DP2ADD,         instr_handler},
+    {BWRITERSIO_CMP,            instr_handler},
+
+    {BWRITERSIO_CALL,           instr_handler},
+    {BWRITERSIO_CALLNZ,         instr_handler},
+    {BWRITERSIO_REP,            instr_handler},
+    {BWRITERSIO_ENDREP,         instr_handler},
+    {BWRITERSIO_IF,             instr_handler},
+    {BWRITERSIO_LABEL,          instr_handler},
+    {BWRITERSIO_IFC,            instr_handler},
+    {BWRITERSIO_ELSE,           instr_handler},
+    {BWRITERSIO_ENDIF,          instr_handler},
+    {BWRITERSIO_BREAK,          instr_handler},
+    {BWRITERSIO_BREAKC,         instr_handler},
+    {BWRITERSIO_RET,            instr_handler},
+
+    {BWRITERSIO_TEX,            instr_handler},
+    {BWRITERSIO_TEX | ( BWRITERSI_TEXLD_PROJECT << BWRITER_OPCODESPECIFICCONTROL_SHIFT ),                       instr_handler},
+    {BWRITERSIO_TEX | ( BWRITERSI_TEXLD_BIAS << BWRITER_OPCODESPECIFICCONTROL_SHIFT ),                          instr_handler},
+    {BWRITERSIO_TEXKILL,        instr_handler},
+    {BWRITERSIO_DSX,            instr_handler},
+    {BWRITERSIO_DSY,            instr_handler},
+
+    {BWRITERSIO_SETP,           instr_handler},
+    {BWRITERSIO_BREAKP,         instr_handler},
+
+    {BWRITERSIO_TEXLDD,         instr_handler},
+
+    {BWRITERSIO_END,            NULL},
+};
+
+static struct bytecode_backend ps_2_x_backend = {
+    ps_2_header,
+    end,
+    ps_2_srcreg,
+    ps_2_0_dstreg,
+    sm_2_opcode,
+    ps_2_x_handlers
+};
+
 static void sm_3_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
     /* Declare the shader type and version */
     put_dword(buffer, This->version);
@@ -1280,6 +1650,16 @@ static void init_vs30_dx9_writer(struct bc_writer *writer) {
     writer->funcs = &vs_3_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;
+}
+
+static void init_ps2x_dx9_writer(struct bc_writer *writer) {
+    TRACE("Creating DirectX9 pixel shader 2.x writer\n");
+    writer->funcs = &ps_2_x_backend;
+}
+
 static void init_ps30_dx9_writer(struct bc_writer *writer) {
     TRACE("Creating DirectX9 pixel shader 3.0 writer\n");
     writer->funcs = &ps_3_backend;
@@ -1371,7 +1751,7 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
                 WARN("Unsupported dxversion for pixel shader 2.0 requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps20_dx9_writer(ret);
             break;
 
         case BWRITERPS_VERSION(2, 1):
@@ -1379,7 +1759,7 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
                 WARN("Unsupported dxversion for pixel shader 2.x requested: %u\n", dxversion);
                 goto fail;
             }
-            /* TODO: Set the appropriate writer backend */
+            init_ps2x_dx9_writer(ret);
             break;
 
         case BWRITERPS_VERSION(3, 0):
-- 
1.6.3.3


More information about the wine-patches mailing list