From b627d13ea81cc281c5981b6a2bc78e5de3685a34 Mon Sep 17 00:00:00 2001 From: Matteo Bruni Date: Thu, 13 May 2010 17:21:58 +0200 Subject: [PATCH] d3dx9: Add output dcl instruction partial support to the shader assembler. --- dlls/d3dx9_36/asmparser.c | 15 ++++++ dlls/d3dx9_36/asmshader.l | 12 +++++ dlls/d3dx9_36/asmshader.y | 40 ++++++++++++++++ dlls/d3dx9_36/asmutils.c | 2 + dlls/d3dx9_36/bytecodewriter.c | 79 ++++++++++++++++++++++++++++++++ dlls/d3dx9_36/d3dx9_36_private.h | 9 ++++ dlls/d3dx9_36/tests/asm.c | 6 +-- 7 files changed, 160 insertions(+), 3 deletions(-) diff --git a/dlls/d3dx9_36/asmparser.c b/dlls/d3dx9_36/asmparser.c index e08c4219ec4..f1360cb6c63 100644 --- a/dlls/d3dx9_36/asmparser.c +++ b/dlls/d3dx9_36/asmparser.c @@ -38,6 +38,19 @@ static void asmparser_end(struct asm_parser *This) { TRACE("Finalizing shader\n"); } +static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num, + const struct shader_reg *reg) { + if(!This->shader) return; + if(This->shader->type == ST_PIXEL) { + asmparser_message(This, "Line %u: Output register declared in a pixel shader\n", This->line_no); + set_parse_status(This, PARSE_ERR); + } + if(!record_declaration(This->shader, usage, num, TRUE, reg->regnum, reg->writemask)) { + ERR("Out of memory\n"); + set_parse_status(This, PARSE_ERR); + } +} + static void asmparser_instr(struct asm_parser *This, DWORD opcode, DWORD mod, DWORD shift, BWRITER_COMPARISON_TYPE comp, @@ -135,6 +148,8 @@ static const struct asmparser_backend parser_vs_3 = { asmparser_predicate_supported, asmparser_coissue_unsupported, + asmparser_dcl_output, + asmparser_end, asmparser_instr, diff --git a/dlls/d3dx9_36/asmshader.l b/dlls/d3dx9_36/asmshader.l index 0fe0932d718..e76da628a45 100644 --- a/dlls/d3dx9_36/asmshader.l +++ b/dlls/d3dx9_36/asmshader.l @@ -66,6 +66,8 @@ REG_PREDICATE p0 /* Not really a register, but it is considered as such */ REG_LABEL l[0-9]+ +DCL_POSITION _position[0-9]* + PREPROCESSORDIRECTIVE #[^\n]*\n /* Comments */ @@ -117,6 +119,7 @@ m4x3 {return INSTR_M4x3; } m3x4 {return INSTR_M3x4; } m3x3 {return INSTR_M3x3; } m3x2 {return INSTR_M3x2; } +dcl {return INSTR_DCL; } rep {return INSTR_REP; } endrep {return INSTR_ENDREP; } if {return INSTR_IF; } @@ -271,6 +274,15 @@ ps_3_0 {return VER_PS30; } ! {return SMOD_NOT; } +{DCL_POSITION} { + if(yytext[strlen("_position")] == '\0') { + asmshader_lval.regnum = 0; + } else { + asmshader_lval.regnum = atoi(yytext + strlen("_position")); + } + return USAGE_POSITION; + } + {PREPROCESSORDIRECTIVE} { /* TODO: update current line information */ TRACE("line info update: %s", yytext); diff --git a/dlls/d3dx9_36/asmshader.y b/dlls/d3dx9_36/asmshader.y index 0c114e5ea49..2a31ebeee69 100644 --- a/dlls/d3dx9_36/asmshader.y +++ b/dlls/d3dx9_36/asmshader.y @@ -80,6 +80,10 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) { DWORD shift; } modshift; BWRITER_COMPARISON_TYPE comptype; + struct { + DWORD dclusage; + unsigned int regnum; + } declaration; struct rel_reg rel_reg; struct src_regs sregs; } @@ -117,6 +121,7 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) { %token INSTR_M3x4 %token INSTR_M3x3 %token INSTR_M3x2 +%token INSTR_DCL %token INSTR_REP %token INSTR_ENDREP %token INSTR_IF @@ -193,6 +198,9 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) { %token SMOD_ABS %token SMOD_NOT +/* Usage declaration tokens */ +%token USAGE_POSITION + /* Misc stuff */ %token COMPONENT %token IMMVAL @@ -210,6 +218,7 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) { %type omods %type omodifier %type comp +%type dclusage %type rel_reg %type predicate %type immsum @@ -476,6 +485,30 @@ instruction: INSTR_ADD omods dreg ',' sregs TRACE("M3x2\n"); asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2); } + | INSTR_DCL dclusage REG_OUTPUT + { + struct shader_reg reg; + TRACE("Output reg declaration\n"); + ZeroMemory(®, sizeof(reg)); + reg.type = BWRITERSPR_OUTPUT; + reg.regnum = $3; + reg.rel_reg = NULL; + reg.srcmod = 0; + reg.writemask = BWRITERSP_WRITEMASK_ALL; + asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®); + } + | INSTR_DCL dclusage REG_OUTPUT writemask + { + struct shader_reg reg; + TRACE("Output reg declaration\n"); + ZeroMemory(®, sizeof(reg)); + reg.type = BWRITERSPR_OUTPUT; + reg.regnum = $3; + reg.rel_reg = NULL; + reg.srcmod = 0; + reg.writemask = $4; + asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®); + } | INSTR_REP sregs { TRACE("REP\n"); @@ -1041,6 +1074,13 @@ comp: COMP_GT { $$ = BWRITER_COMPARISON_GT; } | COMP_EQ { $$ = BWRITER_COMPARISON_EQ; } | COMP_NE { $$ = BWRITER_COMPARISON_NE; } +dclusage: USAGE_POSITION + { + TRACE("dcl_position%u\n", $1); + $$.regnum = $1; + $$.dclusage = BWRITERDECLUSAGE_POSITION; + } + predicate: '(' REG_PREDICATE swizzle ')' { $$.type = BWRITERSPR_PREDICATE; diff --git a/dlls/d3dx9_36/asmutils.c b/dlls/d3dx9_36/asmutils.c index 9adb108f228..c5098ca1aab 100644 --- a/dlls/d3dx9_36/asmutils.c +++ b/dlls/d3dx9_36/asmutils.c @@ -162,6 +162,7 @@ DWORD d3d9_opcode(DWORD bwriter_opcode) { case BWRITERSIO_RET: return D3DSIO_RET; case BWRITERSIO_ENDLOOP: return D3DSIO_ENDLOOP; case BWRITERSIO_LABEL: return D3DSIO_LABEL; + case BWRITERSIO_DCL: return D3DSIO_DCL; case BWRITERSIO_POW: return D3DSIO_POW; case BWRITERSIO_CRS: return D3DSIO_CRS; case BWRITERSIO_SGN: return D3DSIO_SGN; @@ -426,6 +427,7 @@ const char *debug_print_opcode(DWORD opcode) { case BWRITERSIO_RET: return "ret"; case BWRITERSIO_ENDLOOP: return "endloop"; case BWRITERSIO_LABEL: return "label"; + case BWRITERSIO_DCL: return "dcl"; case BWRITERSIO_POW: return "pow"; case BWRITERSIO_CRS: return "crs"; case BWRITERSIO_SGN: return "sgn"; diff --git a/dlls/d3dx9_36/bytecodewriter.c b/dlls/d3dx9_36/bytecodewriter.c index 64a70358dab..ff6393f2286 100644 --- a/dlls/d3dx9_36/bytecodewriter.c +++ b/dlls/d3dx9_36/bytecodewriter.c @@ -104,6 +104,54 @@ BOOL add_instruction(struct bwriter_shader *shader, struct instruction *instr) { return TRUE; } +BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask) { + unsigned int *num; + struct declaration **decl; + unsigned int i; + + if(!shader) return FALSE; + + if(output) { + num = &shader->num_outputs; + decl = &shader->outputs; + } else { + num = &shader->num_inputs; + decl = &shader->inputs; + } + + if(*num == 0) { + *decl = asm_alloc(sizeof(**decl)); + if(!*decl) { + ERR("Error allocating declarations array\n"); + return FALSE; + } + } else { + struct declaration *newdecl; + for(i = 0; i < *num; i++) { + if((*decl)[i].regnum == regnum && ((*decl)[i].writemask & writemask)) { + WARN("Declaration of register %u already exists, writemask match 0x%x\n", + regnum, (*decl)[i].writemask & writemask); + } + } + + newdecl = asm_realloc(*decl, + sizeof(**decl) * ((*num) + 1)); + if(!newdecl) { + ERR("Error reallocating declarations array\n"); + return FALSE; + } + *decl = newdecl; + } + (*decl)[*num].usage = usage; + (*decl)[*num].usage_idx = usage_idx; + (*decl)[*num].regnum = regnum; + (*decl)[*num].writemask = writemask; + (*num)++; + + return TRUE; +} + + /* shader bytecode buffer manipulation functions. * allocate_buffer creates a new buffer structure, put_dword adds a new * DWORD to the buffer. In the rare case of a memory allocation failure @@ -147,6 +195,35 @@ static void put_dword(struct bytecode_buffer *buffer, DWORD value) { /****************************************************** * Implementation of the writer functions starts here * ******************************************************/ +static void write_declarations(struct bytecode_buffer *buffer, BOOL len, + const struct declaration *decls, unsigned int num, DWORD type) { + DWORD i; + DWORD instr_dcl = D3DSIO_DCL; + DWORD token; + + if(len) { + instr_dcl |= 2 << D3DSI_INSTLENGTH_SHIFT; + } + + for(i = 0; i < num; i++) { + /* Write the DCL instruction */ + put_dword(buffer, instr_dcl); + + /* Write the usage and index */ + token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */ + token |= (decls[i].usage << D3DSP_DCL_USAGE_SHIFT) & D3DSP_DCL_USAGE_MASK; + token |= (decls[i].usage_idx << D3DSP_DCL_USAGEINDEX_SHIFT) & D3DSP_DCL_USAGEINDEX_MASK; + put_dword(buffer, token); + + /* Write the dest register */ + token = (1 << 31); /* Bit 31 of non-instruction opcodes is 1 */ + token |= (type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK; + token |= (d3d9_writemask(decls[i].writemask)) & D3DSP_WRITEMASK_ALL; + token |= decls[i].regnum & D3DSP_REGNUM_MASK; + put_dword(buffer, token); + } +} + static void end(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) { put_dword(buffer, D3DSIO_END); } @@ -206,6 +283,8 @@ static void sm_2_opcode(struct bc_writer *This, 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); + + write_declarations(buffer, TRUE, shader->outputs, shader->num_outputs, D3DSPR_OUTPUT); return; } diff --git a/dlls/d3dx9_36/d3dx9_36_private.h b/dlls/d3dx9_36/d3dx9_36_private.h index 6222d66f56c..0e839dd7591 100644 --- a/dlls/d3dx9_36/d3dx9_36_private.h +++ b/dlls/d3dx9_36/d3dx9_36_private.h @@ -253,6 +253,9 @@ struct asmparser_backend { const struct shader_reg *predicate); void (*coissue)(struct asm_parser *This); + void (*dcl_output)(struct asm_parser *This, DWORD usage, DWORD num, + const struct shader_reg *reg); + void (*end)(struct asm_parser *This); void (*instr)(struct asm_parser *This, DWORD opcode, DWORD mod, DWORD shift, @@ -262,6 +265,7 @@ struct asmparser_backend { struct instruction *alloc_instr(unsigned int srcs); BOOL add_instruction(struct bwriter_shader *shader, struct instruction *instr); +BOOL record_declaration(struct bwriter_shader *shader, DWORD usage, DWORD usage_idx, BOOL output, DWORD regnum, DWORD writemask); #define MESSAGEBUFFER_INITIAL_SIZE 256 @@ -402,6 +406,7 @@ typedef enum _BWRITERSHADER_INSTRUCTION_OPCODE_TYPE { BWRITERSIO_RET, BWRITERSIO_ENDLOOP, BWRITERSIO_LABEL, + BWRITERSIO_DCL, BWRITERSIO_POW, BWRITERSIO_CRS, BWRITERSIO_SGN, @@ -513,6 +518,10 @@ typedef enum _BWRITERSHADER_PARAM_SRCMOD_TYPE { #define BWRITERVS_SWIZZLE_Z (BWRITERVS_X_Z | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z) #define BWRITERVS_SWIZZLE_W (BWRITERVS_X_W | BWRITERVS_Y_W | BWRITERVS_Z_W | BWRITERVS_W_W) +typedef enum _BWRITERDECLUSAGE { + BWRITERDECLUSAGE_POSITION, +} BWRITERDECLUSAGE; + struct bwriter_shader *SlAssembleShader(const char *text, char **messages); DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result); void SlDeleteShader(struct bwriter_shader *shader); diff --git a/dlls/d3dx9_36/tests/asm.c b/dlls/d3dx9_36/tests/asm.c index d5473bc4b16..968766a77f9 100644 --- a/dlls/d3dx9_36/tests/asm.c +++ b/dlls/d3dx9_36/tests/asm.c @@ -1023,11 +1023,11 @@ static void vs_3_0_test(void) { "dcl_2d s0\n", {0xfffe0300, 0x0200001f, 0x90000000, 0xa00f0800, 0x0000ffff} },*/ -/* {*/ /* shader 2 */ -/* "vs_3_0\n" + { /* shader 2 */ + "vs_3_0\n" "dcl_position o0\n", {0xfffe0300, 0x0200001f, 0x80000000, 0xe00f0000, 0x0000ffff} - },*/ + }, /* {*/ /* shader 3 */ /* "vs_3_0\n" "dcl_texcoord12 o11\n",