[11/18] d3dx9: Shader assembler PS 1.4 support
Matteo Bruni
matteo.mystral at gmail.com
Sun Aug 16 12:53:17 CDT 2009
-------------- next part --------------
From e99dc7fdd3449255d0e7fa0b2451867f3324c18b Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sun, 16 Aug 2009 02:16:08 +0200
Subject: d3dx9: Shader assembler PS 1.4 support
---
dlls/d3dx9_36/asmparser.c | 218 +++++++++++++++++++++++++++++++++++++++-
dlls/d3dx9_36/asmshader.y | 2 +-
dlls/d3dx9_36/bytecodewriter.c | 186 ++++++++++++++++++++++++++++++++++-
3 files changed, 403 insertions(+), 3 deletions(-)
diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
index c7588f1..f0de949 100644
--- a/dlls/d3dx9_36/asmparser.c
+++ b/dlls/d3dx9_36/asmparser.c
@@ -158,6 +158,63 @@ static void asmparser_texcoord(struct asm_parser *This,
}
}
+static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
+ const struct shader_reg *dst,
+ const struct src_regs *srcs) {
+ struct instruction *instr;
+
+ if(!srcs || srcs->count != 1) {
+ asmparser_message(This, "Line %u: Wrong number of source registers in texcrd instruction\n", This->line_no);
+ set_parse_status(This, PARSE_ERR);
+ return;
+ }
+
+ instr = alloc_instr(1);
+ if(!instr) {
+ ERR("Error allocating memory for the instruction\n");
+ set_parse_status(This, PARSE_ERR);
+ return;
+ }
+
+ /* The job of texcrd is done by mov in later shader versions */
+ instr->opcode = BWRITERSIO_MOV;
+ instr->dstmod = mod;
+ instr->shift = shift;
+ instr->comptype = 0;
+
+ /* No fanciness with the dest reg recording. It is a temporary register
+ * already
+ */
+ 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(srcs->reg[0].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, srcs->reg[0].regnum);
+ instr->src[0].regnum = 0;
+ set_parse_status(This, PARSE_ERR);
+ }
+ instr->src[0].swizzle = srcs->reg[0].swizzle;
+ instr->src[0].srcmod = srcs->reg[0].srcmod; /* For _DW and _DZ */
+ instr->src[0].rel_reg = NULL;
+
+ 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);
@@ -272,6 +329,83 @@ static void asmparser_tex(struct asm_parser *This,
}
}
+static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
+ const struct shader_reg *dst,
+ const struct src_regs *srcs) {
+ struct instruction *instr;
+
+ if(!srcs || srcs->count != 1) {
+ asmparser_message(This, "Line %u: texld (PS 1.4) has a wrong number of source registers\n", This->line_no);
+ set_parse_status(This, PARSE_ERR);
+ return;
+ }
+
+ instr = alloc_instr(2);
+ if(!instr) {
+ ERR("Error allocating memory for the instruction\n");
+ set_parse_status(This, PARSE_ERR);
+ return;
+ }
+
+ /* This code is recording a texld instruction, not tex. However,
+ * texld borrows the opcode of tex
+ */
+ instr->opcode = BWRITERSIO_TEX;
+ instr->dstmod = mod;
+ instr->shift = shift;
+ instr->comptype = 0;
+
+ /* The destination register can be recorded normally. The destination
+ * register for ps_1_4 texld is a normal temporary register.
+ */
+ This->funcs->dstreg(This, instr, dst);
+
+ /* The first source register is the varying containing the coordinate.
+ * It can be a temporary register, then it can be recorded without
+ * any modifications. It can be a texture register, then it has to be
+ * mapped to the input varying
+ */
+ if(srcs->reg[0].type == BWRITERSPR_TEXTURE) {
+ memset(&instr->src[0], 0, sizeof(instr->src[0]));
+ instr->src[0].type = BWRITERSPR_INPUT;
+ switch(srcs->reg[0].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, srcs->reg[0].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;
+ } else {
+ instr->src[0] = srcs->reg[0];
+ }
+
+ /* 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) {
@@ -726,7 +860,9 @@ static void asmparser_instr(struct asm_parser *This, DWORD opcode,
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);
+ if(This->shader->version == BWRITERPS_VERSION(1, 4))
+ asmparser_texcrd(This, mod, shift, dst, srcs);
+ else asmparser_texcoord(This, dst, srcs);
return;
case BWRITERSIO_TEX:
/* this encodes both the tex PS 1.x instruction and the
@@ -737,6 +873,10 @@ static void asmparser_instr(struct asm_parser *This, DWORD opcode,
asmparser_tex(This, dst);
return;
}
+ else if(This->shader->version == BWRITERPS_VERSION(1, 4)) {
+ asmparser_texld14(This, mod, shift, dst, srcs);
+ return;
+ }
/* else fallback to the standard behavior */
break;
}
@@ -1100,6 +1240,30 @@ static void asmparser_srcreg_ps_1_0123(struct asm_parser *This,
memcpy(&instr->src[num], ®, sizeof(reg));
}
+struct allowed_reg_type ps_1_4_reg_allowed[] = {
+ { BWRITERSPR_CONST, 8 },
+ { BWRITERSPR_TEMP, 6 },
+ { BWRITERSPR_TEXTURE, 6 },
+ { BWRITERSPR_INPUT, 2 },
+ { ~0U, 0 } /* End tag */
+};
+
+static void asmparser_srcreg_ps_1_4(struct asm_parser *This,
+ struct instruction *instr, int num,
+ const struct shader_reg *src) {
+ struct shader_reg reg;
+
+ if(!check_reg_type(src, ps_1_4_reg_allowed)) {
+ asmparser_message(This, "Line %u: Source register %s not supported in PS 1.4\n",
+ This->line_no,
+ debug_print_srcreg(src, 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 },
@@ -1253,6 +1417,22 @@ static void asmparser_dstreg_ps_1_0123(struct asm_parser *This,
instr->has_dst = TRUE;
}
+static void asmparser_dstreg_ps_1_4(struct asm_parser *This,
+ struct instruction *instr,
+ const struct shader_reg *dst) {
+ struct shader_reg reg;
+
+ if(!check_reg_type(dst, ps_1_4_reg_allowed)) {
+ asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
+ This->line_no,
+ debug_print_dstreg(dst, 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) {
@@ -1412,6 +1592,26 @@ static struct asmparser_backend parser_ps_1_0123 = {
asmparser_instr,
};
+static struct asmparser_backend parser_ps_1_4 = {
+ asmparser_constF,
+ asmparser_constI,
+ asmparser_constB,
+
+ asmparser_dstreg_ps_1_4,
+ asmparser_srcreg_ps_1_4,
+
+ asmparser_predicate_unsupported,
+ asmparser_coissue_supported,
+
+ asmparser_dcl_output,
+ asmparser_dcl_input,
+ asmparser_dcl_sampler,
+
+ asmparser_end,
+
+ asmparser_instr,
+};
+
static struct asmparser_backend parser_ps_2 = {
asmparser_constF,
asmparser_constI,
@@ -1646,6 +1846,22 @@ void create_ps13_parser(struct asm_parser *ret) {
gen_oldps_input(ret->shader, 4);
}
+void create_ps14_parser(struct asm_parser *ret) {
+ TRACE_(parsed_shader)("ps_1_4\n");
+
+ ret->shader = asm_alloc(sizeof(*ret->shader));
+ if(!ret->shader) {
+ ERR("Failed to allocate memory for the shader\n");
+ set_parse_status(ret, PARSE_ERR);
+ return;
+ }
+
+ ret->shader->type = ST_PIXEL;
+ ret->shader->version = BWRITERPS_VERSION(1, 4);
+ ret->funcs = &parser_ps_1_4;
+ gen_oldps_input(ret->shader, 6);
+}
+
void create_ps20_parser(struct asm_parser *ret) {
TRACE_(parsed_shader)("ps_2_0\n");
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
index bbb8247..ad8f8f8 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -345,7 +345,7 @@ version_marker: VER_VS10
| VER_PS14
{
TRACE("Pixel shader 1.4\n");
- /* TODO: create the appropriate parser context */
+ create_ps14_parser(ctx);
}
| VER_PS20
{
diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
index a4eacab..46e169e 100644
--- a/dlls/d3dx9_36/bytecodewriter.c
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -599,6 +599,18 @@ static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *s
ps_legacy_header(This, shader, buffer, 4, FALSE);
}
+static void ps_1_4_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, 6, FALSE);
+}
+
static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
put_dword(buffer, D3DSIO_END);
}
@@ -1247,6 +1259,173 @@ static struct bytecode_backend ps_1_0123_backend = {
ps_1_0123_handlers
};
+static void ps_1_4_srcreg(struct bc_writer *This, const struct shader_reg *reg,
+ struct bytecode_buffer *buffer) {
+ DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
+ if(reg->rel_reg) {
+ WARN("Relative addressing not supported in <= ps_3_0\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ switch(reg->type) {
+ case BWRITERSPR_INPUT:
+ token |= map_ps1x_varying(This, reg);
+ break;
+
+ /* Can be mapped 1:1 */
+ case BWRITERSPR_TEMP:
+ case BWRITERSPR_CONST:
+ token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+ break;
+
+ default:
+ WARN("Invalid register type for ps_1_4 shader\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
+
+ /* TODO: _dz and _dw are only allowed in texld instruction */
+ if(reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
+ reg->srcmod == BWRITERSPSM_NOT) {
+ WARN("Invalid source modifier %u for ps_1_4\n", reg->srcmod);
+ This->state = E_INVALIDARG;
+ return;
+ }
+ token |= d3d9_srcmod(reg->srcmod);
+ put_dword(buffer, token);
+}
+
+static void ps_1_4_dstreg(struct bc_writer *This, const struct shader_reg *reg,
+ struct bytecode_buffer *buffer,
+ DWORD shift, DWORD mod) {
+ DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
+
+ if(reg->rel_reg) {
+ WARN("Relative addressing not supported for destination registers\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ switch(reg->type) {
+ case BWRITERSPR_TEMP: /* 1:1 mapping */
+ token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+ break;
+
+ /* 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);
+}
+
+static void instr_ps_1_4_mov(struct bc_writer *This,
+ const struct instruction *instr,
+ struct bytecode_buffer *buffer) {
+ DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
+
+ if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
+ if(instr->src[0].regnum == This->t_regnum[0] ||
+ instr->src[0].regnum == This->t_regnum[1] ||
+ instr->src[0].regnum == This->t_regnum[2] ||
+ instr->src[0].regnum == This->t_regnum[3] ||
+ instr->src[0].regnum == This->t_regnum[4] ||
+ instr->src[0].regnum == This->t_regnum[5]) {
+ /* Similar to a regular mov, but a different opcode */
+ token = D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK;
+ } else if(instr->src[0].regnum == This->v_regnum[0] ||
+ instr->src[0].regnum == This->v_regnum[1]) {
+ /* Handled by the normal mov below. Just drop out of the if condition */
+ } else {
+ WARN("Unsupported varying -> temp mov in ps_1_4\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ }
+
+ This->funcs->opcode(This, instr, token, buffer);
+ This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+ This->funcs->srcreg(This, &instr->src[0], buffer);
+}
+
+static void instr_ps_1_4_texld(struct bc_writer *This,
+ const struct instruction *instr,
+ struct bytecode_buffer *buffer) {
+ if(instr->src[1].type != BWRITERSPR_SAMPLER ||
+ instr->src[1].regnum > 5) {
+ WARN("Unsupported sampler type %u regnum %u\n",
+ instr->src[1].type, instr->src[1].regnum);
+ This->state = E_INVALIDARG;
+ return;
+ } else if(instr->dst.type != BWRITERSPR_TEMP) {
+ WARN("Can only sample into a temp register\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ if(instr->src[1].regnum != instr->dst.regnum) {
+ WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_4\n",
+ instr->src[1].regnum, instr->dst.regnum);
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
+ This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
+ This->funcs->srcreg(This, &instr->src[0], buffer);
+}
+
+struct instr_handler_table ps_1_4_handlers[] = {
+ {BWRITERSIO_ADD, instr_handler},
+ {BWRITERSIO_NOP, instr_handler},
+ {BWRITERSIO_MOV, instr_ps_1_4_mov},
+ {BWRITERSIO_SUB, instr_handler},
+ {BWRITERSIO_MAD, instr_handler},
+ {BWRITERSIO_MUL, instr_handler},
+ {BWRITERSIO_DP3, instr_handler},
+ {BWRITERSIO_DP4, instr_handler},
+ {BWRITERSIO_LRP, instr_handler},
+
+ /* pshader instructions */
+ {BWRITERSIO_CND, instr_handler},
+ {BWRITERSIO_CMP, instr_handler},
+ {BWRITERSIO_TEXKILL, instr_handler},
+ {BWRITERSIO_TEX, instr_ps_1_4_texld},
+ {BWRITERSIO_TEXDEPTH, instr_handler},
+ {BWRITERSIO_BEM, instr_handler},
+
+ {BWRITERSIO_PHASE, instr_handler},
+ {BWRITERSIO_END, NULL},
+};
+
+static struct bytecode_backend ps_1_4_backend = {
+ ps_1_4_header,
+ end,
+ ps_1_4_srcreg,
+ ps_1_4_dstreg,
+ sm_1_x_opcode,
+ ps_1_4_handlers
+};
+
static void write_constB(const struct bwriter_shader *shader, struct bytecode_buffer *buffer, BOOL len) {
DWORD i;
DWORD instr_def = D3DSIO_DEFB;
@@ -2138,6 +2317,11 @@ static void init_ps13_dx9_writer(struct bc_writer *writer) {
writer->funcs = &ps_1_0123_backend;
}
+static void init_ps14_dx9_writer(struct bc_writer *writer) {
+ TRACE("Creating DirectX9 pixel shader 1.4 writer\n");
+ writer->funcs = &ps_1_4_backend;
+}
+
static void init_ps20_dx9_writer(struct bc_writer *writer) {
TRACE("Creating DirectX9 pixel shader 2.0 writer\n");
writer->funcs = &ps_2_0_backend;
@@ -2231,7 +2415,7 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
WARN("Unsupported dxversion for pixel shader 1.4 requested: %u\n", dxversion);
goto fail;
}
- /* TODO: Set the appropriate writer backend */
+ init_ps14_dx9_writer(ret);
break;
case BWRITERPS_VERSION(2, 0):
--
1.6.3.3
More information about the wine-patches
mailing list