Module: wine Branch: master Commit: 6dc11616d56323b7ea39fd85debeef589d52ac01 URL: http://source.winehq.org/git/wine.git/?a=commit;h=6dc11616d56323b7ea39fd85de... Author: Stefan Dösinger <stefan(a)codeweavers.com> Date: Sun Sep 9 16:54:51 2007 +0200 wined3d: Take care against overwriting a source register in cmp. --- dlls/wined3d/glsl_shader.c | 41 +++++++++++++++++++++++++++++++++++++---- 1 files changed, 37 insertions(+), 4 deletions(-) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 47859fe..d82d24c 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1513,6 +1513,17 @@ void shader_glsl_cmp(SHADER_OPCODE_ARG* arg) { glsl_src_param_t src2_param; DWORD write_mask, cmp_channel = 0; unsigned int i, j; + char mask_char[6]; + BOOL temp_destination = FALSE; + + DWORD src0reg = arg->src[0] & WINED3DSP_REGNUM_MASK; + DWORD src1reg = arg->src[1] & WINED3DSP_REGNUM_MASK; + DWORD src2reg = arg->src[2] & WINED3DSP_REGNUM_MASK; + DWORD src0regtype = shader_get_regtype(arg->src[0]); + DWORD src1regtype = shader_get_regtype(arg->src[1]); + DWORD src2regtype = shader_get_regtype(arg->src[2]); + DWORD dstreg = arg->dst & WINED3DSP_REGNUM_MASK; + DWORD dstregtype = shader_get_regtype(arg->dst); /* Cycle through all source0 channels */ for (i=0; i<4; i++) { @@ -1524,16 +1535,38 @@ void shader_glsl_cmp(SHADER_OPCODE_ARG* arg) { cmp_channel = WINED3DSP_WRITEMASK_0 << j; } } - write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask)); - if (!write_mask) continue; + + /* Splitting the cmp instruction up in multiple lines imposes a problem: + * The first lines may overwrite source parameters of the following lines. + * Deal with that by using a temporary destination register if needed + */ + if((src0reg == dstreg && src0regtype == dstregtype) || + (src1reg == dstreg && src1regtype == dstregtype) || + (src2reg == dstreg && src2regtype == dstregtype)) { + + write_mask = shader_glsl_get_write_mask(arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask), mask_char); + if (!write_mask) continue; + shader_addline(arg->buffer, "tmp0%s = (", mask_char); + temp_destination = TRUE; + } else { + write_mask = shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst & (~WINED3DSP_SWIZZLE_MASK | write_mask)); + if (!write_mask) continue; + } shader_glsl_add_src_param(arg, arg->src[0], arg->src_addr[0], cmp_channel, &src0_param); shader_glsl_add_src_param(arg, arg->src[1], arg->src_addr[1], write_mask, &src1_param); shader_glsl_add_src_param(arg, arg->src[2], arg->src_addr[2], write_mask, &src2_param); - shader_addline(arg->buffer, "%s >= 0.0 ? %s : %s);\n", - src0_param.param_str, src1_param.param_str, src2_param.param_str); + shader_addline(arg->buffer, "%s >= 0.0 ? %s : %s);\n", + src0_param.param_str, src1_param.param_str, src2_param.param_str); } + + if(temp_destination) { + shader_glsl_get_write_mask(arg->dst, mask_char); + shader_glsl_append_dst_ext(arg->buffer, arg, arg->dst); + shader_addline(arg->buffer, "tmp0%s);\n", mask_char); + } + } /** Process the CND opcode in GLSL (dst = (src0 > 0.5) ? src1 : src2) */