[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], ®, 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, ®, 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, ®, 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, ®, 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