diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 87a1d4c0d79..d871fc978b2 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -84,6 +84,10 @@ struct shader_arb_priv { struct hash_table_t *fragment_shaders; }; +struct shader_arb_ctx_priv { + char addr_reg[20]; +}; + /******************************************************** * ARB_[vertex/fragment]_program helper functions follow ********************************************************/ @@ -503,6 +507,17 @@ static void shader_arb_get_swizzle(const struct wined3d_shader_src_param *param, *ptr = '\0'; } +static void shader_arb_request_a0(const struct wined3d_shader_instruction *ins, const char *src) +{ + struct shader_arb_ctx_priv *priv = ins->ctx->backend_data; + SHADER_BUFFER *buffer = ins->ctx->buffer; + + if(strcmp(priv->addr_reg, src) == 0) return; + + strcpy(priv->addr_reg, src); + shader_addline(buffer, "ARL A0.x, %s;\n", src); +} + static void shader_arb_get_src_param(const struct wined3d_shader_instruction *ins, const struct wined3d_shader_src_param *src, unsigned int tmpreg, char *outregstr); @@ -543,7 +558,9 @@ static void shader_arb_get_register_name(const struct wined3d_shader_instruction if(This->baseShader.reg_maps.shader_version.major < 2) { sprintf(rel_reg, "A0.x"); } else { + shader_arb_get_src_param(ins, reg->rel_addr, 0, rel_reg); /* FIXME: GL_NV_vertex_progam2_option */ + shader_arb_request_a0(ins, rel_reg); sprintf(rel_reg, "A0.x"); } if (reg->idx >= rel_offset) @@ -574,7 +591,17 @@ static void shader_arb_get_register_name(const struct wined3d_shader_instruction sprintf(register_name, "fragment.texcoord[%u]", reg->idx); } } - else sprintf(register_name, "A%u", reg->idx); + else + { + if(This->baseShader.reg_maps.shader_version.major == 1) + { + sprintf(register_name, "A%u", reg->idx); + } + else + { + sprintf(register_name, "A%u_SHADOW", reg->idx); + } + } break; case WINED3DSPR_COLOROUT: @@ -1016,9 +1043,11 @@ static void shader_hw_mov(const struct wined3d_shader_instruction *ins) if(ins->handler_idx == WINED3DSIH_MOVA) { struct wined3d_shader_src_param tmp_src = ins->src[0]; + char write_mask[6]; tmp_src.swizzle = (tmp_src.swizzle & 0x3) * 0x55; shader_arb_get_src_param(ins, &tmp_src, 0, src0_param); + shader_arb_get_write_mask(ins, &ins->dst[0], write_mask); /* This implements the mova formula used in GLSL. The first two instructions * prepare the sign() part. Note that it is fine to have my_sign(0.0) = 1.0 @@ -1027,16 +1056,20 @@ static void shader_hw_mov(const struct wined3d_shader_instruction *ins) * * A0.x = arl(floor(abs(0.0) + 0.5) * 1.0) = floor(0.5) = 0.0 since arl does a floor * + * The ARL is performed when A0 is used - the requested component is read from A0_SHADOW into + * A0.x. We can use the overwritten component of A0_shadow as temporary storage for the sign. + * * TODO: ARR from GL_NV_vertex_program2_option */ - shader_addline(buffer, "SGE TA.y, %s, mova_const.y;\n", src0_param); - shader_addline(buffer, "MAD TA.y, TA.y, mova_const.z, -mova_const.w;\n"); + shader_addline(buffer, "SGE A0_SHADOW%s, %s, mova_const.y;\n", write_mask, src0_param); + shader_addline(buffer, "MAD A0_SHADOW%s, A0_SHADOW, mova_const.z, -mova_const.w;\n", write_mask); - shader_addline(buffer, "ABS TA.x, %s;\n", src0_param); - shader_addline(buffer, "ADD TA.x, TA.x, mova_const.x;\n"); - shader_addline(buffer, "FLR TA.x, TA.x;\n"); - shader_addline(buffer, "MUL TA.x, TA.x, TA.y;\n"); - shader_addline(buffer, "ARL A0.x, TA.x;\n"); + shader_addline(buffer, "ABS TA%s, %s;\n", write_mask, src0_param); + shader_addline(buffer, "ADD TA%s, TA, mova_const.x;\n", write_mask); + shader_addline(buffer, "FLR TA%s, TA;\n", write_mask); + shader_addline(buffer, "MUL A0_SHADOW%s, TA, A0_SHADOW;\n", write_mask); + + ((struct shader_arb_ctx_priv *)ins->ctx->backend_data)->addr_reg[0] = '\0'; } else if (ins->ctx->reg_maps->shader_version.major == 1 && !shader_is_pshader_version(ins->ctx->reg_maps->shader_version.type) && ins->dst[0].reg.type == WINED3DSPR_ADDR) @@ -1982,7 +2015,7 @@ static GLuint shader_arb_generate_pshader(IWineD3DPixelShader *iface, shader_generate_arb_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION, lconst_map); /* Base Shader Body */ - shader_generate_main((IWineD3DBaseShader *)This, buffer, reg_maps, function); + shader_generate_main((IWineD3DBaseShader *)This, buffer, reg_maps, function, NULL); if(args->srgb_correction) { arbfp_add_sRGB_correction(buffer, fragcolor, "TA", "TB", "TC"); @@ -2036,7 +2069,9 @@ static GLuint shader_arb_generate_vshader(IWineD3DVertexShader *iface, const local_constant *lconst; GLuint ret; DWORD *lconst_map = local_const_mapping((IWineD3DBaseShaderImpl *) This); + struct shader_arb_ctx_priv priv_ctx; + memset(&priv_ctx, 0, sizeof(priv_ctx)); /* Create the hw ARB shader */ shader_addline(buffer, "!!ARBvp1.0\n"); @@ -2045,6 +2080,7 @@ static GLuint shader_arb_generate_vshader(IWineD3DVertexShader *iface, } if(need_mova_const((IWineD3DBaseShader *) iface, gl_info)) { shader_addline(buffer, "PARAM mova_const = { 0.5, 0.0, 2.0, 1.0 };\n"); + shader_addline(buffer, "TEMP A0_SHADOW;\n"); } /* Mesa supports only 95 constants */ @@ -2086,7 +2122,7 @@ static GLuint shader_arb_generate_vshader(IWineD3DVertexShader *iface, } /* Base Shader Body */ - shader_generate_main((IWineD3DBaseShader *)This, buffer, reg_maps, function); + shader_generate_main((IWineD3DBaseShader *)This, buffer, reg_maps, function, &priv_ctx); /* The D3DRS_FOGTABLEMODE render state defines if the shader-generated fog coord is used * or if the fragment depth is used. If the fragment depth is used(FOGTABLEMODE != NONE), diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index cf8171b1057..2fd79ff738c 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -929,7 +929,7 @@ void shader_dump_src_param(const struct wined3d_shader_src_param *param, /* Shared code in order to generate the bulk of the shader string. * NOTE: A description of how to parse tokens can be found on msdn */ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER *buffer, - const shader_reg_maps *reg_maps, const DWORD *pFunction) + const shader_reg_maps *reg_maps, const DWORD *pFunction, void *backend_ctx) { IWineD3DBaseShaderImpl* This = (IWineD3DBaseShaderImpl*) iface; IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->baseShader.device; /* To access shader backend callbacks */ @@ -951,6 +951,7 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER *buffer, ctx.shader = iface; ctx.reg_maps = reg_maps; ctx.buffer = buffer; + ctx.backend_data = backend_ctx; ins.ctx = &ctx; ins.dst = &dst_param; diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 13d82ba3ee0..c978e5b0c5a 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -4142,7 +4142,7 @@ static GLuint shader_glsl_generate_pshader(IWineD3DPixelShader *iface, } /* Base Shader Body */ - shader_generate_main((IWineD3DBaseShader *)This, buffer, reg_maps, function); + shader_generate_main((IWineD3DBaseShader *)This, buffer, reg_maps, function, NULL); /* Pixel shaders < 2.0 place the resulting color in R0 implicitly */ if (reg_maps->shader_version.major < 2) @@ -4229,7 +4229,7 @@ static GLuint shader_glsl_generate_vshader(IWineD3DVertexShader *iface, shader_generate_glsl_declarations( (IWineD3DBaseShader*) This, reg_maps, buffer, &GLINFO_LOCATION, NULL); /* Base Shader Body */ - shader_generate_main((IWineD3DBaseShader*)This, buffer, reg_maps, function); + shader_generate_main((IWineD3DBaseShader*)This, buffer, reg_maps, function, NULL); /* Unpack 3.0 outputs */ if (reg_maps->shader_version.major >= 3) shader_addline(buffer, "order_ps_input(OUT);\n"); diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 526ba24ee9e..79ac60b2dab 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -648,6 +648,7 @@ struct wined3d_shader_context IWineD3DBaseShader *shader; const struct shader_reg_maps *reg_maps; SHADER_BUFFER *buffer; + void *backend_data; }; struct wined3d_shader_register @@ -2575,7 +2576,7 @@ void shader_dump_src_param(const struct wined3d_shader_src_param *param, void shader_dump_dst_param(const struct wined3d_shader_dst_param *param, const struct wined3d_shader_version *shader_version); void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER *buffer, - const shader_reg_maps *reg_maps, const DWORD *pFunction); + const shader_reg_maps *reg_maps, const DWORD *pFunction, void *backend_ctx); HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3d_shader_frontend *fe, struct shader_reg_maps *reg_maps, struct wined3d_shader_semantic *semantics_in, struct wined3d_shader_semantic *semantics_out, const DWORD *byte_code, DWORD constf_size);