From 6ede56495a33aef4ddaf1bff117546741da498eb Mon Sep 17 00:00:00 2001 From: Ivan Gyurdiev Date: Mon, 10 Jul 2006 03:11:35 -0600 Subject: [PATCH] wined3d: More flow control instructions - Implement if, else, endif, rep, endrep, break - Implement ifc, breakc, using undocumented comparison bits in the instruction token - Fix bug in main loop processing of codes with no dst token - Fix bug in GLSL output modifier processing of codes with no dst token - Fix bug in loop implementation (src1 contains the integer data, src0 is aL) - Add versioning for all the instructions above, and remove GLSL_REQUIRED thing, which is useless and should be removed from all opcodes in general. --- dlls/wined3d/baseshader.c | 39 +++++++++----- dlls/wined3d/glsl_shader.c | 93 +++++++++++++++++++++++++++++----- dlls/wined3d/pixelshader.c | 20 ++++---- dlls/wined3d/vertexshader.c | 20 ++++---- dlls/wined3d/wined3d_private.h | 22 +++++++- 5 files changed, 148 insertions(+), 46 deletions(-) diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index 5baca259a24..1275dd55ad8 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -273,7 +273,8 @@ HRESULT shader_get_registers_used( pToken += curOpcode->num_params; /* If there's a loop in the shader */ - } else if (D3DSIO_LOOP == curOpcode->opcode) { + } else if (D3DSIO_LOOP == curOpcode->opcode || + D3DSIO_REP == curOpcode->opcode) { reg_maps->loop = 1; pToken += curOpcode->num_params; @@ -632,7 +633,6 @@ void shader_generate_main( const DWORD *pToken = pFunction; const SHADER_OPCODE *curOpcode = NULL; SHADER_HANDLER hw_fct = NULL; - DWORD opcode_token; DWORD i; SHADER_OPCODE_ARG hw_arg; @@ -662,8 +662,8 @@ void shader_generate_main( } /* Read opcode */ - opcode_token = *pToken++; - curOpcode = shader_get_opcode(iface, opcode_token); + hw_arg.opcode_token = *pToken++; + curOpcode = shader_get_opcode(iface, hw_arg.opcode_token); /* Select handler */ if (curOpcode == NULL) @@ -675,7 +675,7 @@ void shader_generate_main( /* Unknown opcode and its parameters */ if (NULL == curOpcode) { - FIXME("Unrecognized opcode: token=%08lX\n", opcode_token); + FIXME("Unrecognized opcode: token=%08lX\n", hw_arg.opcode_token); pToken += shader_skip_unrecognized(iface, pToken); /* Nothing to do */ @@ -685,7 +685,7 @@ void shader_generate_main( D3DSIO_DEFI == curOpcode->opcode || D3DSIO_DEFB == curOpcode->opcode) { - pToken += shader_skip_opcode(This, curOpcode, opcode_token); + pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token); /* If a generator function is set for current shader target, use it */ } else if (hw_fct != NULL) { @@ -702,17 +702,16 @@ void shader_generate_main( } /* Predication token */ - if (opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) + if (hw_arg.opcode_token & D3DSHADER_INSTRUCTION_PREDICATED) hw_arg.predicate = *pToken++; /* Other source tokens */ - for (i = curOpcode->dst_token; i < curOpcode->num_params; i++) { + for (i = 0; i < (curOpcode->num_params - curOpcode->dst_token); i++) { DWORD param, addr_token = 0; - pToken += shader_get_param(iface, pToken, ¶m, &addr_token); - hw_arg.src[i-1] = param; - hw_arg.src_addr[i-1] = addr_token; + hw_arg.src[i] = param; + hw_arg.src_addr[i] = addr_token; } /* Call appropriate function for output target */ @@ -726,7 +725,7 @@ void shader_generate_main( } else { FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name); - pToken += shader_skip_opcode(This, curOpcode, opcode_token); + pToken += shader_skip_opcode(This, curOpcode, hw_arg.opcode_token); } } /* TODO: What about result.depth? */ @@ -863,6 +862,22 @@ void shader_trace_init( TRACE("%s", curOpcode->name); + if (curOpcode->opcode == D3DSIO_IFC || + curOpcode->opcode == D3DSIO_BREAKC) { + + DWORD op = (opcode_token & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT; + switch (op) { + case COMPARISON_GT: TRACE("_gt"); break; + case COMPARISON_EQ: TRACE("_eq"); break; + case COMPARISON_GE: TRACE("_ge"); break; + case COMPARISON_LT: TRACE("_lt"); break; + case COMPARISON_NE: TRACE("_ne"); break; + case COMPARISON_LE: TRACE("_le"); break; + default: + TRACE("_(%lu)", op); + } + } + /* Destination token */ if (curOpcode->dst_token) { diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 0d0ed3a51b5..bd91f105475 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -755,9 +755,10 @@ static void shader_glsl_add_param( /** Process GLSL instruction modifiers */ void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG* arg) { - - if (0 != (arg->dst & D3DSP_DSTMOD_MASK)) { - DWORD mask = arg->dst & D3DSP_DSTMOD_MASK; + + DWORD mask = arg->dst & D3DSP_DSTMOD_MASK; + + if (arg->opcode->dst_token && mask != 0) { char dst_reg[50]; char dst_mask[6]; char dst_str[100]; @@ -777,6 +778,23 @@ void shader_glsl_add_instruction_modifiers(SHADER_OPCODE_ARG* arg) { } } +static inline const char* shader_get_comp_op( + const DWORD opcode) { + + DWORD op = (opcode & INST_CONTROLS_MASK) >> INST_CONTROLS_SHIFT; + switch (op) { + case COMPARISON_GT: return ">"; + case COMPARISON_EQ: return "=="; + case COMPARISON_GE: return ">="; + case COMPARISON_LT: return "<"; + case COMPARISON_NE: return "!="; + case COMPARISON_LE: return "<="; + default: + FIXME("Unrecognized comparison value: %lu\n", op); + return "(\?\?)"; + } +} + /***************************************************************************** * * Begin processing individual instruction opcodes @@ -1152,24 +1170,73 @@ void shader_glsl_sincos(SHADER_OPCODE_ARG* arg) { */ void shader_glsl_loop(SHADER_OPCODE_ARG* arg) { - char src0_str[100]; - char src0_reg[50]; - char src0_mask[6]; + char src1_str[100]; + char src1_reg[50]; + char src1_mask[6]; - shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str); + shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str); shader_addline(arg->buffer, "for (tmpInt = 0, aL = %s.y; tmpInt < %s.x; tmpInt++, aL += %s.z) {\n", - src0_reg, src0_reg, src0_reg); + src1_reg, src1_reg, src1_reg); } -/** Process the D3DSIO_ENDLOOP instruction in GLSL: - * End the for() loop - */ -void shader_glsl_endloop(SHADER_OPCODE_ARG* arg) { - +void shader_glsl_end(SHADER_OPCODE_ARG* arg) { shader_addline(arg->buffer, "}\n"); } +void shader_glsl_rep(SHADER_OPCODE_ARG* arg) { + + char src0_str[100]; + char src0_reg[50]; + char src0_mask[6]; + + shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str); + shader_addline(arg->buffer, "for (tmpInt = 0; tmpInt < %s.x; tmpInt++) {\n", src0_reg); +} + +void shader_glsl_if(SHADER_OPCODE_ARG* arg) { + + char src0_str[100]; + char src0_reg[50]; + char src0_mask[6]; + + shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str); + shader_addline(arg->buffer, "if (%s) {\n", src0_str); +} + +void shader_glsl_ifc(SHADER_OPCODE_ARG* arg) { + + char src0_str[100], src1_str[100]; + char src0_reg[50], src1_reg[50]; + char src0_mask[6], src1_mask[6]; + + shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str); + shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str); + + shader_addline(arg->buffer, "if (%s %s %s) {\n", + src0_str, shader_get_comp_op(arg->opcode_token), src1_str); +} + +void shader_glsl_else(SHADER_OPCODE_ARG* arg) { + shader_addline(arg->buffer, "} else {\n"); +} + +void shader_glsl_break(SHADER_OPCODE_ARG* arg) { + shader_addline(arg->buffer, "break;\n"); +} + +void shader_glsl_breakc(SHADER_OPCODE_ARG* arg) { + + char src0_str[100], src1_str[100]; + char src0_reg[50], src1_reg[50]; + char src0_mask[6], src1_mask[6]; + + shader_glsl_add_param(arg, arg->src[0], arg->src_addr[0], TRUE, src0_reg, src0_mask, src0_str); + shader_glsl_add_param(arg, arg->src[1], arg->src_addr[1], TRUE, src1_reg, src1_mask, src1_str); + + shader_addline(arg->buffer, "if (%s %s %s) break;\n", + src0_str, shader_get_comp_op(arg->opcode_token), src1_str); +} /********************************************* * Pixel Shader Specific Code begins here diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index 40d7a40ff32..977cb4e7e28 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -676,20 +676,20 @@ CONST SHADER_OPCODE IWineD3DPixelShaderImpl_shader_ins[] = { {D3DSIO_DCL, "dcl", NULL, 0, 2, pshader_dcl, NULL, NULL, 0, 0}, /* Flow control - requires GLSL or software shaders */ - {D3DSIO_REP , "rep", GLNAME_REQUIRE_GLSL, 0, 1, pshader_rep, NULL, NULL, 0, 0}, - {D3DSIO_ENDREP, "endrep", GLNAME_REQUIRE_GLSL, 0, 0, pshader_endrep, NULL, NULL, 0, 0}, - {D3DSIO_IF, "if", GLNAME_REQUIRE_GLSL, 0, 1, pshader_if, NULL, NULL, 0, 0}, - {D3DSIO_IFC, "ifc", GLNAME_REQUIRE_GLSL, 0, 2, pshader_ifc, NULL, NULL, 0, 0}, - {D3DSIO_ELSE, "else", GLNAME_REQUIRE_GLSL, 0, 0, pshader_else, NULL, NULL, 0, 0}, - {D3DSIO_ENDIF, "endif", GLNAME_REQUIRE_GLSL, 0, 0, pshader_endif, NULL, NULL, 0, 0}, - {D3DSIO_BREAK, "break", GLNAME_REQUIRE_GLSL, 0, 0, pshader_break, NULL, NULL, 0, 0}, - {D3DSIO_BREAKC, "breakc", GLNAME_REQUIRE_GLSL, 0, 2, pshader_breakc, NULL, NULL, 0, 0}, + {D3DSIO_REP , "rep", NULL, 0, 1, pshader_rep, NULL, shader_glsl_rep, D3DPS_VERSION(2,1), -1}, + {D3DSIO_ENDREP, "endrep", NULL, 0, 0, pshader_endrep, NULL, shader_glsl_end, D3DPS_VERSION(2,1), -1}, + {D3DSIO_IF, "if", NULL, 0, 1, pshader_if, NULL, shader_glsl_if, D3DPS_VERSION(2,1), -1}, + {D3DSIO_IFC, "ifc", NULL, 0, 2, pshader_ifc, NULL, shader_glsl_ifc, D3DPS_VERSION(2,1), -1}, + {D3DSIO_ELSE, "else", NULL, 0, 0, pshader_else, NULL, shader_glsl_else, D3DPS_VERSION(2,1), -1}, + {D3DSIO_ENDIF, "endif", NULL, 0, 0, pshader_endif, NULL, shader_glsl_end, D3DPS_VERSION(2,1), -1}, + {D3DSIO_BREAK, "break", NULL, 0, 0, pshader_break, NULL, shader_glsl_break, D3DPS_VERSION(2,1), -1}, + {D3DSIO_BREAKC, "breakc", NULL, 0, 2, pshader_breakc, NULL, shader_glsl_breakc, D3DPS_VERSION(2,1), -1}, {D3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, pshader_breakp, NULL, NULL, 0, 0}, {D3DSIO_CALL, "call", GLNAME_REQUIRE_GLSL, 0, 1, pshader_call, NULL, NULL, 0, 0}, {D3DSIO_CALLNZ, "callnz", GLNAME_REQUIRE_GLSL, 0, 2, pshader_callnz, NULL, NULL, 0, 0}, - {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 0, 2, pshader_loop, NULL, shader_glsl_loop, 0, 0}, + {D3DSIO_LOOP, "loop", NULL, 0, 2, pshader_loop, NULL, shader_glsl_loop, D3DPS_VERSION(3,0), -1}, {D3DSIO_RET, "ret", GLNAME_REQUIRE_GLSL, 0, 0, pshader_ret, NULL, NULL, 0, 0}, - {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, 0, pshader_endloop, NULL, shader_glsl_endloop, 0, 0}, + {D3DSIO_ENDLOOP, "endloop", NULL, 0, 0, pshader_endloop, NULL, shader_glsl_end, D3DPS_VERSION(3,0), -1}, {D3DSIO_LABEL, "label", GLNAME_REQUIRE_GLSL, 0, 1, pshader_label, NULL, NULL, 0, 0}, /* Constant definitions */ diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c index d71b5c52665..20d1d4097ea 100644 --- a/dlls/wined3d/vertexshader.c +++ b/dlls/wined3d/vertexshader.c @@ -536,20 +536,20 @@ CONST SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[] = { {D3DSIO_DEFI, "defi", GLNAME_REQUIRE_GLSL, 1, 5, vshader_defi, NULL, NULL, 0, 0}, /* Flow control - requires GLSL or software shaders */ - {D3DSIO_REP , "rep", GLNAME_REQUIRE_GLSL, 0, 1, vshader_rep, NULL, NULL, 0, 0}, - {D3DSIO_ENDREP, "endrep", GLNAME_REQUIRE_GLSL, 0, 0, vshader_endrep, NULL, NULL, 0, 0}, - {D3DSIO_IF, "if", GLNAME_REQUIRE_GLSL, 0, 1, vshader_if, NULL, NULL, 0, 0}, - {D3DSIO_IFC, "ifc", GLNAME_REQUIRE_GLSL, 0, 2, vshader_ifc, NULL, NULL, 0, 0}, - {D3DSIO_ELSE, "else", GLNAME_REQUIRE_GLSL, 0, 0, vshader_else, NULL, NULL, 0, 0}, - {D3DSIO_ENDIF, "endif", GLNAME_REQUIRE_GLSL, 0, 0, vshader_endif, NULL, NULL, 0, 0}, - {D3DSIO_BREAK, "break", GLNAME_REQUIRE_GLSL, 0, 0, vshader_break, NULL, NULL, 0, 0}, - {D3DSIO_BREAKC, "breakc", GLNAME_REQUIRE_GLSL, 0, 2, vshader_breakc, NULL, NULL, 0, 0}, + {D3DSIO_REP , "rep", NULL, 0, 1, vshader_rep, NULL, shader_glsl_rep, D3DVS_VERSION(2,0), -1}, + {D3DSIO_ENDREP, "endrep", NULL, 0, 0, vshader_endrep, NULL, shader_glsl_end, D3DVS_VERSION(2,0), -1}, + {D3DSIO_IF, "if", NULL, 0, 1, vshader_if, NULL, shader_glsl_if, D3DVS_VERSION(2,0), -1}, + {D3DSIO_IFC, "ifc", NULL, 0, 2, vshader_ifc, NULL, shader_glsl_ifc, D3DVS_VERSION(2,1), -1}, + {D3DSIO_ELSE, "else", NULL, 0, 0, vshader_else, NULL, shader_glsl_else, D3DVS_VERSION(2,0), -1}, + {D3DSIO_ENDIF, "endif", NULL, 0, 0, vshader_endif, NULL, shader_glsl_end, D3DVS_VERSION(2,0), -1}, + {D3DSIO_BREAK, "break", NULL, 0, 0, vshader_break, NULL, shader_glsl_break, D3DVS_VERSION(2,1), -1}, + {D3DSIO_BREAKC, "breakc", NULL, 0, 2, vshader_breakc, NULL, shader_glsl_breakc, D3DVS_VERSION(2,1), -1}, {D3DSIO_BREAKP, "breakp", GLNAME_REQUIRE_GLSL, 0, 1, vshader_breakp, NULL, NULL, 0, 0}, {D3DSIO_CALL, "call", GLNAME_REQUIRE_GLSL, 0, 1, vshader_call, NULL, NULL, 0, 0}, {D3DSIO_CALLNZ, "callnz", GLNAME_REQUIRE_GLSL, 0, 2, vshader_callnz, NULL, NULL, 0, 0}, - {D3DSIO_LOOP, "loop", GLNAME_REQUIRE_GLSL, 0, 2, vshader_loop, NULL, shader_glsl_loop, 0, 0}, + {D3DSIO_LOOP, "loop", NULL, 0, 2, vshader_loop, NULL, shader_glsl_loop, D3DVS_VERSION(2,0), -1}, {D3DSIO_RET, "ret", GLNAME_REQUIRE_GLSL, 0, 0, vshader_ret, NULL, NULL, 0, 0}, - {D3DSIO_ENDLOOP, "endloop", GLNAME_REQUIRE_GLSL, 0, 0, vshader_endloop, NULL, shader_glsl_endloop, 0, 0}, + {D3DSIO_ENDLOOP, "endloop", NULL, 0, 0, vshader_endloop, NULL, shader_glsl_end, D3DVS_VERSION(2,0), -1}, {D3DSIO_LABEL, "label", GLNAME_REQUIRE_GLSL, 0, 1, vshader_label, NULL, NULL, 0, 0}, {D3DSIO_MOVA, "mova", GLNAME_REQUIRE_GLSL, 1, 2, vshader_mova, NULL, shader_glsl_mov, 0, 0}, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 0fc8b3f189b..5102e7caa2a 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1318,6 +1318,19 @@ typedef struct SHADER_BUFFER { unsigned int lineNo; } SHADER_BUFFER; +/* Undocumented opcode controls */ +#define INST_CONTROLS_SHIFT 16 +#define INST_CONTROLS_MASK 0x00ff0000 + +typedef enum COMPARISON_TYPE { + COMPARISON_GT = 1, + COMPARISON_EQ = 2, + COMPARISON_GE = 3, + COMPARISON_LT = 4, + COMPARISON_NE = 5, + COMPARISON_LE = 6 +} COMPARISON_TYPE; + typedef struct SHADER_OPCODE { unsigned int opcode; const char* name; @@ -1335,6 +1348,7 @@ typedef struct SHADER_OPCODE_ARG { IWineD3DBaseShader* shader; shader_reg_maps* reg_maps; CONST SHADER_OPCODE* opcode; + DWORD opcode_token; DWORD dst; DWORD dst_addr; DWORD predicate; @@ -1442,7 +1456,13 @@ extern void shader_glsl_lit(SHADER_OPCODE_ARG* arg); extern void shader_glsl_dst(SHADER_OPCODE_ARG* arg); extern void shader_glsl_sincos(SHADER_OPCODE_ARG* arg); extern void shader_glsl_loop(SHADER_OPCODE_ARG* arg); -extern void shader_glsl_endloop(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_end(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_if(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_ifc(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_else(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_break(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_breakc(SHADER_OPCODE_ARG* arg); +extern void shader_glsl_rep(SHADER_OPCODE_ARG* arg); /** GLSL Pixel Shader Prototypes */ extern void pshader_glsl_tex(SHADER_OPCODE_ARG* arg);