[7/18] d3dx9: Shader assembler VS 2.X support
Matteo Bruni
matteo.mystral at gmail.com
Sun Aug 16 12:52:15 CDT 2009
-------------- next part --------------
From 2107d78d34882a0fa173b81ee0357ed2c64a6e16 Mon Sep 17 00:00:00 2001
From: Matteo Bruni <matteo.mystral at gmail.com>
Date: Sat, 15 Aug 2009 22:18:17 +0200
Subject: d3dx9: Shader assembler VS 2.X support
---
dlls/d3dx9_36/asmparser.c | 188 ++++++++++++++
dlls/d3dx9_36/asmshader.y | 4 +-
dlls/d3dx9_36/bytecodewriter.c | 527 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 715 insertions(+), 4 deletions(-)
diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c
index 6f34ffb..0d2ecc3 100644
--- a/dlls/d3dx9_36/asmparser.c
+++ b/dlls/d3dx9_36/asmparser.c
@@ -154,6 +154,61 @@ static void asmparser_instr(struct asm_parser *This, DWORD opcode,
}
}
+static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
+ struct shader_reg ret;
+ switch(reg->type) {
+ case BWRITERSPR_RASTOUT:
+ ret = *reg;
+ ret.type = BWRITERSPR_OUTPUT;
+ if(reg->regnum == BWRITERSRO_POSITION) {
+ ret.regnum = OPOS_REG;
+ return ret;
+ } else if(reg->regnum == BWRITERSRO_FOG) {
+ ret.regnum = OFOG_REG;
+ ret.writemask = OFOG_WRITEMASK;
+ return ret;
+ } else if(reg->regnum == BWRITERSRO_POINT_SIZE) {
+ ret.regnum = OPTS_REG;
+ ret.writemask = OPTS_WRITEMASK;
+ return ret;
+ }
+ FIXME("Unhandled RASTOUT register %u\n", reg->regnum);
+ return *reg;
+
+ case BWRITERSPR_TEXCRDOUT:
+ ret = *reg;
+ ret.type = BWRITERSPR_OUTPUT;
+ switch(reg->regnum) {
+ case 0: ret.regnum = OT0_REG; break;
+ case 1: ret.regnum = OT1_REG; break;
+ case 2: ret.regnum = OT2_REG; break;
+ case 3: ret.regnum = OT3_REG; break;
+ case 4: ret.regnum = OT4_REG; break;
+ case 5: ret.regnum = OT5_REG; break;
+ case 6: ret.regnum = OT6_REG; break;
+ case 7: ret.regnum = OT7_REG; break;
+ default:
+ FIXME("Unhandled TEXCRDOUT regnum %u\n", reg->regnum);
+ return *reg;
+ }
+ return ret;
+
+ case BWRITERSPR_ATTROUT:
+ ret = *reg;
+ ret.type = BWRITERSPR_OUTPUT;
+ switch(reg->regnum) {
+ case 0: ret.regnum = OD0_REG; break;
+ case 1: ret.regnum = OD1_REG; break;
+ default:
+ FIXME("Unhandled ATTROUT regnum %u\n", reg->regnum);
+ return *reg;
+ }
+ return ret;
+
+ 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) {
@@ -169,6 +224,15 @@ static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
}
}
+static void check_abs_srcmod(struct asm_parser *This, DWORD srcmod) {
+ if(srcmod == BWRITERSPSM_ABS || srcmod == BWRITERSPSM_ABSNEG) {
+ asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
+ This->line_no,
+ debug_print_srcmod(srcmod));
+ set_parse_status(This, PARSE_ERR);
+ }
+}
+
static void check_loop_swizzle(struct asm_parser *This,
const struct shader_reg *src) {
if((src->type == BWRITERSPR_LOOP && src->swizzle != BWRITERVS_NOSWIZZLE) ||
@@ -201,6 +265,40 @@ static BOOL check_reg_type(const struct shader_reg *reg,
return FALSE;
}
+struct allowed_reg_type vs_2_reg_allowed[] = {
+ { BWRITERSPR_TEMP, 12 },
+ { BWRITERSPR_INPUT, 16 },
+ { BWRITERSPR_CONST, ~0U },
+ { BWRITERSPR_ADDR, 1 },
+ { BWRITERSPR_CONSTBOOL, 16 },
+ { BWRITERSPR_CONSTINT, 16 },
+ { BWRITERSPR_LOOP, 1 },
+ { BWRITERSPR_LABEL, 16 },
+ { BWRITERSPR_PREDICATE, 1 },
+ { BWRITERSPR_RASTOUT, 3 }, /* oPos, oFog and oPts */
+ { BWRITERSPR_ATTROUT, 2 },
+ { BWRITERSPR_TEXCRDOUT, 8 },
+ { ~0U, 0 } /* End tag */
+};
+
+static void asmparser_srcreg_vs_2(struct asm_parser *This,
+ struct instruction *instr, int num,
+ const struct shader_reg *src) {
+ struct shader_reg reg;
+
+ if(!check_reg_type(src, vs_2_reg_allowed)) {
+ asmparser_message(This, "Line %u: Source register %s not supported in VS 2\n",
+ This->line_no,
+ debug_print_srcreg(src, ST_VERTEX));
+ set_parse_status(This, PARSE_ERR);
+ }
+ check_loop_swizzle(This, src);
+ check_legacy_srcmod(This, src->srcmod);
+ check_abs_srcmod(This, src->srcmod);
+ reg = map_oldvs_register(src);
+ memcpy(&instr->src[num], ®, sizeof(reg));
+}
+
struct allowed_reg_type vs_3_reg_allowed[] = {
{ BWRITERSPR_TEMP, 32 },
{ BWRITERSPR_INPUT, 16 },
@@ -260,6 +358,22 @@ static void asmparser_srcreg_ps_3(struct asm_parser *This,
memcpy(&instr->src[num], src, sizeof(*src));
}
+static void asmparser_dstreg_vs_2(struct asm_parser *This,
+ struct instruction *instr,
+ const struct shader_reg *dst) {
+ struct shader_reg reg;
+
+ if(!check_reg_type(dst, vs_2_reg_allowed)) {
+ asmparser_message(This, "Line %u: Destination register %s not supported in VS 2.0\n",
+ This->line_no,
+ debug_print_dstreg(dst, ST_VERTEX));
+ set_parse_status(This, PARSE_ERR);
+ }
+ reg = map_oldvs_register(dst);
+ memcpy(&instr->dst, ®, sizeof(reg));
+ instr->has_dst = TRUE;
+}
+
static void asmparser_dstreg_vs_3(struct asm_parser *This,
struct instruction *instr,
const struct shader_reg *dst) {
@@ -299,11 +413,37 @@ static void asmparser_predicate_supported(struct asm_parser *This,
memcpy(&This->shader->instr[This->shader->num_instrs-1]->predicate, predicate, sizeof(*predicate));
}
+static void asmparser_predicate_unsupported(struct asm_parser *This,
+ const struct shader_reg *predicate) {
+ asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no);
+ set_parse_status(This, PARSE_ERR);
+}
+
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);
}
+static struct asmparser_backend parser_vs_2 = {
+ asmparser_constF,
+ asmparser_constI,
+ asmparser_constB,
+
+ asmparser_dstreg_vs_2,
+ asmparser_srcreg_vs_2,
+
+ asmparser_predicate_supported,
+ asmparser_coissue_unsupported,
+
+ asmparser_dcl_output,
+ asmparser_dcl_input,
+ asmparser_dcl_sampler,
+
+ asmparser_end,
+
+ asmparser_instr,
+};
+
static struct asmparser_backend parser_vs_3 = {
asmparser_constF,
asmparser_constI,
@@ -344,6 +484,54 @@ static struct asmparser_backend parser_ps_3 = {
asmparser_instr,
};
+static void gen_oldvs_output(struct bwriter_shader *shader) {
+ record_declaration(shader, BWRITERDECLUSAGE_POSITION, 0, TRUE, OPOS_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, TRUE, OT0_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, TRUE, OT1_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, TRUE, OT2_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, TRUE, OT3_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, TRUE, OT4_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, TRUE, OT5_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, TRUE, OT6_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, TRUE, OT7_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_FOG, 0, TRUE, OFOG_REG, OFOG_WRITEMASK);
+ record_declaration(shader, BWRITERDECLUSAGE_PSIZE, 0, TRUE, OPTS_REG, OPTS_WRITEMASK);
+ record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, TRUE, OD0_REG, BWRITERSP_WRITEMASK_ALL);
+ record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL);
+}
+
+void create_vs20_parser(struct asm_parser *ret) {
+ TRACE_(parsed_shader)("vs_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_VERTEX;
+ ret->shader->version = BWRITERVS_VERSION(2, 0);
+ ret->funcs = &parser_vs_2;
+ gen_oldvs_output(ret->shader);
+}
+
+void create_vs2x_parser(struct asm_parser *ret) {
+ TRACE_(parsed_shader)("vs_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_VERTEX;
+ ret->shader->version = BWRITERVS_VERSION(2, 1);
+ ret->funcs = &parser_vs_2;
+ gen_oldvs_output(ret->shader);
+}
+
void create_vs30_parser(struct asm_parser *ret) {
TRACE_(parsed_shader)("vs_3_0\n");
diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y
index fe2e204..598b38f 100644
--- a/dlls/d3dx9_36/asmshader.y
+++ b/dlls/d3dx9_36/asmshader.y
@@ -310,12 +310,12 @@ version_marker: VER_VS10
| VER_VS20
{
TRACE("Vertex shader 2.0\n");
- /* TODO: create the appropriate parser context */
+ create_vs20_parser(ctx);
}
| VER_VS2X
{
TRACE("Vertex shader 2.x\n");
- /* TODO: create the appropriate parser context */
+ create_vs2x_parser(ctx);
}
| VER_VS30
{
diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c
index 665d1db..e2077a5 100644
--- a/dlls/d3dx9_36/bytecodewriter.c
+++ b/dlls/d3dx9_36/bytecodewriter.c
@@ -401,10 +401,245 @@ static void write_constF(const struct bwriter_shader *shader, struct bytecode_bu
}
}
+static HRESULT find_builtin_varyings(struct bc_writer *This, const struct bwriter_shader *shader) {
+ DWORD i;
+ DWORD usage, usage_idx, writemask, regnum;
+
+ for(i = 0; i < shader->num_outputs; i++) {
+ usage = shader->outputs[i].usage;
+ usage_idx = shader->outputs[i].usage_idx;
+ writemask = shader->outputs[i].writemask;
+ regnum = shader->outputs[i].regnum;
+
+ switch(usage) {
+ case BWRITERDECLUSAGE_POSITION:
+ case BWRITERDECLUSAGE_POSITIONT:
+ if(usage_idx > 0) {
+ WARN("dcl_position%u not supported in sm 1 shaders\n", usage_idx);
+ return E_INVALIDARG;
+ }
+ if(writemask != BWRITERSP_WRITEMASK_ALL) {
+ WARN("Only WRITEMASK_ALL is supported on position in sm 1\n");
+ return E_INVALIDARG;
+ }
+ TRACE("o%u is oPos\n", regnum);
+ This->oPos_regnum = regnum;
+ break;
+
+ case BWRITERDECLUSAGE_COLOR:
+ if(usage_idx > 1) {
+ WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
+ return E_INVALIDARG;
+ }
+ if(writemask != BWRITERSP_WRITEMASK_ALL) {
+ WARN("Only WRITEMASK_ALL is supported on color in sm 1\n");
+ return E_INVALIDARG;
+ }
+ TRACE("o%u is oD%u\n", regnum, usage_idx);
+ This->oD_regnum[usage_idx] = regnum;
+ break;
+
+ case BWRITERDECLUSAGE_TEXCOORD:
+ if(usage_idx > 8) {
+ WARN("dcl_color%u not supported in sm 1 shaders\n", usage_idx);
+ return E_INVALIDARG;
+ }
+ 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");
+ return E_INVALIDARG;
+ } else {
+ writemask = BWRITERSP_WRITEMASK_ALL;
+ }
+ TRACE("o%u is oT%u\n", regnum, usage_idx);
+ This->oT_regnum[usage_idx] = regnum;
+ break;
+
+ case BWRITERDECLUSAGE_PSIZE:
+ if(usage_idx > 0) {
+ WARN("dcl_psize%u not supported in sm 1 shaders\n", usage_idx);
+ return E_INVALIDARG;
+ }
+ if(writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1 &&
+ writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3) {
+ WARN("Unsupported oPts size writemask\n");
+ return E_INVALIDARG;
+ }
+ TRACE("o%u writemask 0x%08x is oPts\n", regnum, writemask);
+ This->oPts_regnum = regnum;
+ This->oPts_mask = writemask;
+ break;
+
+ case BWRITERDECLUSAGE_FOG:
+ if(usage_idx > 0) {
+ WARN("dcl_fog%u not supported in sm 1 shaders\n", usage_idx);
+ return E_INVALIDARG;
+ }
+ if(writemask != BWRITERSP_WRITEMASK_0 && writemask != BWRITERSP_WRITEMASK_1 &&
+ writemask != BWRITERSP_WRITEMASK_2 && writemask != BWRITERSP_WRITEMASK_3) {
+ WARN("Unsupported fog writemask\n");
+ return E_INVALIDARG;
+ }
+ TRACE("o%u writemask 0x%08x is oFog\n", regnum, writemask);
+ This->oFog_regnum = regnum;
+ This->oFog_mask = writemask;
+ break;
+
+ default:
+ WARN("Varying type %u is not supported in shader model 1.x\n", usage);
+ return E_INVALIDARG;
+ }
+ }
+
+ return S_OK;
+}
+
static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
put_dword(buffer, D3DSIO_END);
}
+static DWORD vs_output(struct bc_writer *This, DWORD regnum, DWORD mask, DWORD *has_components) {
+ DWORD token = 0;
+
+ *has_components = TRUE;
+ if(regnum == This->oPos_regnum) {
+ token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= D3DSRO_POSITION & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oFog_regnum && mask == This->oFog_mask) {
+ token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= D3DSRO_FOG & D3DSP_REGNUM_MASK; /* No shift */
+ token |= D3DSP_WRITEMASK_ALL;
+ *has_components = FALSE;
+ } else if(regnum == This->oPts_regnum && mask == This->oPts_mask) {
+ token |= (D3DSPR_RASTOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= D3DSRO_POINT_SIZE & D3DSP_REGNUM_MASK; /* No shift */
+ token |= D3DSP_WRITEMASK_ALL;
+ *has_components = FALSE;
+ } else if(regnum == This->oD_regnum[0]) {
+ token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oD_regnum[0]) {
+ token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oD_regnum[1]) {
+ token |= (D3DSPR_ATTROUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[0]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[1]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[2]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 2 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[3]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 3 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[4]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 4 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[5]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 5 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[6]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 6 & D3DSP_REGNUM_MASK; /* No shift */
+ } else if(regnum == This->oT_regnum[7]) {
+ token |= (D3DSPR_TEXCRDOUT << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 7 & D3DSP_REGNUM_MASK; /* No shift */
+ } else {
+ /* The varying must be undeclared - if an unsupported varying was decared,
+ * the header function would have caught it and this code would not run
+ */
+ WARN("Undeclared varying %u\n", regnum);
+ This->state = E_INVALIDARG;
+ return -1;
+ }
+ return token;
+}
+
+static void vs_12_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 has_wmask;
+
+ if(reg->rel_reg) {
+ WARN("Relative addressing not supported for destination registers\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ switch(reg->type) {
+ case BWRITERSPR_OUTPUT:
+ token |= vs_output(This, reg->regnum, reg->writemask, &has_wmask);
+ break;
+
+ case BWRITERSPR_RASTOUT:
+ case BWRITERSPR_ATTROUT:
+ /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
+ * but are unexpected. If we hit this path it might be due to an error.
+ */
+ FIXME("Unexpected register type %u\n", reg->type);
+ /* drop through */
+ case BWRITERSPR_INPUT:
+ case BWRITERSPR_TEMP:
+ case BWRITERSPR_CONST:
+ token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
+ has_wmask = TRUE;
+ break;
+
+ case BWRITERSPR_ADDR:
+ if(reg->regnum != 0) {
+ WARN("Only a0 exists in shader model 1.x and 2.x\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ token |= (D3DSPR_ADDR << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+ has_wmask = TRUE;
+ break;
+
+ case BWRITERSPR_PREDICATE:
+ if(This->version != BWRITERVS_VERSION(2, 1)){
+ WARN("Predicate register is allowed only in vs_2_x\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ if(reg->regnum != 0) {
+ WARN("Only predicate register p0 exists\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ 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 */
+ has_wmask = TRUE;
+ break;
+
+ default:
+ WARN("Invalid register type for 1.x vshader\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+
+ /* strictly speaking there are no modifiers in vs_2_0 and vs_1_x, but they can be written
+ * into the bytecode and since the compiler doesn't do such checks write them
+ * (the checks are done by the undocumented shader validator)
+ */
+ token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
+ token |= d3d9_dstmod(mod);
+
+ if(has_wmask) {
+ token |= d3d9_writemask(reg->writemask);
+ }
+ put_dword(buffer, token);
+}
+
static void write_srcregs(struct bc_writer *This, const struct instruction *instr,
struct bytecode_buffer *buffer){
unsigned int i;
@@ -489,6 +724,158 @@ static void write_constI(const struct bwriter_shader *shader, struct bytecode_bu
}
}
+static void vs_2_header(struct bc_writer *This,
+ const struct bwriter_shader *shader,
+ struct bytecode_buffer *buffer) {
+ HRESULT hr;
+
+ hr = find_builtin_varyings(This, shader);
+ if(FAILED(hr)) {
+ This->state = hr;
+ return;
+ }
+
+ /* Declare the shader type and version */
+ put_dword(buffer, This->version);
+
+ write_declarations(buffer, TRUE, shader->inputs, shader->num_inputs, D3DSPR_INPUT);
+ write_constF(shader, buffer, TRUE);
+ write_constB(shader, buffer, TRUE);
+ write_constI(shader, buffer, TRUE);
+ return;
+}
+
+static void vs_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 has_swizzle;
+ DWORD component ;
+ DWORD d3d9reg;
+
+ switch(reg->type) {
+ case BWRITERSPR_OUTPUT:
+ /* The output register component is stored as a writemask, since that is the form most
+ * commonly used. If we're reading from it, we've got a swizzle. If this swizzle selects
+ * a single component, map it to a writemask selecting this component, otherwise
+ * 0 does the job. If a component is needed to identify the register, an unconvertible
+ * swizzle is an error anyway
+ */
+ if(reg->swizzle == BWRITERVS_SWIZZLE_X) {
+ component = BWRITERSP_WRITEMASK_0;
+ } else if(reg->swizzle == BWRITERVS_SWIZZLE_Y) {
+ component = BWRITERSP_WRITEMASK_1;
+ } else if(reg->swizzle == BWRITERVS_SWIZZLE_Z) {
+ component = BWRITERSP_WRITEMASK_2;
+ } else if(reg->swizzle == BWRITERVS_SWIZZLE_W) {
+ component = BWRITERSP_WRITEMASK_3;
+ } else {
+ component = 0;
+ }
+ token |= vs_output(This, reg->regnum, component, &has_swizzle);
+ break;
+
+ case BWRITERSPR_RASTOUT:
+ case BWRITERSPR_ATTROUT:
+ /* These registers are mapped to input and output regs. They can be encoded in the bytecode,
+ * but are unexpected. If we hit this path it might be due to an error.
+ */
+ FIXME("Unexpected register type %u\n", reg->type);
+ /* drop through */
+ case BWRITERSPR_INPUT:
+ case BWRITERSPR_TEMP:
+ case BWRITERSPR_CONST:
+ case BWRITERSPR_ADDR:
+ case BWRITERSPR_CONSTINT:
+ case BWRITERSPR_CONSTBOOL:
+ 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_LOOP:
+ if(reg->regnum != 0) {
+ WARN("Only regnum 0 is supported for the loop index register in vs_2_0\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ 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_LABEL:
+ if(reg->regnum > 15) {
+ WARN("Only labels 0-15 are supported in vs_2_0\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ token |= (D3DSPR_LABEL << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
+ token |= (D3DSPR_LABEL << D3DSP_REGTYPE_SHIFT2) & D3DSP_REGTYPE_MASK2;
+ token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
+ break;
+
+ case BWRITERSPR_PREDICATE:
+ if(This->version != BWRITERVS_VERSION(2, 1)){
+ WARN("Predicate register is allowed only in vs_2_x\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ if(reg->regnum > 0) {
+ WARN("Only predicate register 0 is supported\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ 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 2.0 vshader\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 vs_2_0\n", reg->srcmod);
+ This->state = E_INVALIDARG;
+ return;
+ }
+ if(reg->srcmod == BWRITERSPSM_NOT &&
+ reg->type != BWRITERSPR_CONSTBOOL && reg->type != BWRITERSPR_PREDICATE){
+ WARN("The '!' modifier can only be used on bool or predicate registers\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ token |= d3d9_srcmod(reg->srcmod);
+
+ if(reg->rel_reg) {
+ if((reg->rel_reg->type == BWRITERSPR_ADDR || reg->rel_reg->type == BWRITERSPR_LOOP) &&
+ reg->rel_reg->regnum == 0) {
+ token |= D3DVS_ADDRMODE_RELATIVE & D3DVS_ADDRESSMODE_MASK;
+ } else {
+ WARN("Unsupported relative addressing register\n");
+ This->state = E_INVALIDARG;
+ return;
+ }
+ }
+
+ put_dword(buffer, token);
+
+ /* vs_2_0 and newer write the register containing the index explicitly in the
+ * binary code
+ */
+ if(token & D3DVS_ADDRMODE_RELATIVE) {
+ vs_2_srcreg(This, reg->rel_reg, buffer);
+ }
+}
+
static void sm_2_opcode(struct bc_writer *This,
const struct instruction *instr,
DWORD token, struct bytecode_buffer *buffer) {
@@ -502,6 +889,132 @@ static void sm_2_opcode(struct bc_writer *This,
put_dword(buffer,token);
}
+struct instr_handler_table vs_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_SLT, instr_handler},
+ {BWRITERSIO_SGE, instr_handler},
+ {BWRITERSIO_ABS, instr_handler},
+ {BWRITERSIO_EXP, instr_handler},
+ {BWRITERSIO_LOG, instr_handler},
+ {BWRITERSIO_EXPP, instr_handler},
+ {BWRITERSIO_LOGP, instr_handler},
+ {BWRITERSIO_DST, instr_handler},
+ {BWRITERSIO_LRP, instr_handler},
+ {BWRITERSIO_FRC, instr_handler},
+ {BWRITERSIO_CRS, instr_handler},
+ {BWRITERSIO_SGN, 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_LIT, instr_handler},
+ {BWRITERSIO_POW, instr_handler},
+ {BWRITERSIO_MOVA, 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_ELSE, instr_handler},
+ {BWRITERSIO_ENDIF, instr_handler},
+ {BWRITERSIO_LOOP, instr_handler},
+ {BWRITERSIO_RET, instr_handler},
+ {BWRITERSIO_ENDLOOP, instr_handler},
+
+ {BWRITERSIO_END, NULL},
+};
+
+static struct bytecode_backend vs_2_0_backend = {
+ vs_2_header,
+ end,
+ vs_2_srcreg,
+ vs_12_dstreg,
+ sm_2_opcode,
+ vs_2_0_handlers
+};
+
+struct instr_handler_table vs_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_SLT, instr_handler},
+ {BWRITERSIO_SGE, instr_handler},
+ {BWRITERSIO_ABS, instr_handler},
+ {BWRITERSIO_EXP, instr_handler},
+ {BWRITERSIO_LOG, instr_handler},
+ {BWRITERSIO_EXPP, instr_handler},
+ {BWRITERSIO_LOGP, instr_handler},
+ {BWRITERSIO_DST, instr_handler},
+ {BWRITERSIO_LRP, instr_handler},
+ {BWRITERSIO_FRC, instr_handler},
+ {BWRITERSIO_CRS, instr_handler},
+ {BWRITERSIO_SGN, 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_LIT, instr_handler},
+ {BWRITERSIO_POW, instr_handler},
+ {BWRITERSIO_MOVA, 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_LOOP, instr_handler},
+ {BWRITERSIO_RET, instr_handler},
+ {BWRITERSIO_ENDLOOP, instr_handler},
+
+ {BWRITERSIO_SETP, instr_handler},
+ {BWRITERSIO_BREAKP, instr_handler},
+
+ {BWRITERSIO_END, NULL},
+};
+
+static struct bytecode_backend vs_2_x_backend = {
+ vs_2_header,
+ end,
+ vs_2_srcreg,
+ vs_12_dstreg,
+ sm_2_opcode,
+ vs_2_x_handlers
+};
+
static void write_samplers(const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
DWORD i;
DWORD instr_dcl = D3DSIO_DCL | (2 << D3DSI_INSTLENGTH_SHIFT);
@@ -752,6 +1265,16 @@ static struct bytecode_backend ps_3_backend = {
ps_3_handlers
};
+static void init_vs20_dx9_writer(struct bc_writer *writer) {
+ TRACE("Creating DirectX9 vertex shader 2.0 writer\n");
+ writer->funcs = &vs_2_0_backend;
+}
+
+static void init_vs2x_dx9_writer(struct bc_writer *writer) {
+ TRACE("Creating DirectX9 vertex shader 2.x writer\n");
+ writer->funcs = &vs_2_x_backend;
+}
+
static void init_vs30_dx9_writer(struct bc_writer *writer) {
TRACE("Creating DirectX9 vertex shader 3.0 writer\n");
writer->funcs = &vs_3_backend;
@@ -790,14 +1313,14 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
WARN("Unsupported dxversion for vertex shader 2.0 requested: %u\n", dxversion);
goto fail;
}
- /* TODO: Set the appropriate writer backend */
+ init_vs20_dx9_writer(ret);
break;
case BWRITERVS_VERSION(2, 1):
if(dxversion != 9) {
WARN("Unsupported dxversion for vertex shader 2.x requested: %u\n", dxversion);
goto fail;
}
- /* TODO: Set the appropriate writer backend */
+ init_vs2x_dx9_writer(ret);
break;
case BWRITERVS_VERSION(3, 0):
if(dxversion != 9) {
--
1.6.3.3
More information about the wine-patches
mailing list