diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index d5136bb99e0..ecb6f0b5499 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -42,6 +42,13 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d); #define GLINFO_LOCATION (*gl_info) /* GL locking for state handlers is done by the caller. */ +static BOOL need_mova_const(IWineD3DBaseShader *shader, const WineD3D_GL_Info *gl_info) { + IWineD3DBaseShaderImpl *This = (IWineD3DBaseShaderImpl *) shader; + if(!This->baseShader.reg_maps.usesmova) return FALSE; + /* TODO: ARR from GL_NV_vertex_program2_option */ + return TRUE; +} + static BOOL need_helper_const(const WineD3D_GL_Info *gl_info) { if(!GL_SUPPORT(NV_VERTEX_PROGRAM) || /* Need to init colors */ gl_info->arb_vs_offset_limit || /* Have to init texcoords */ @@ -51,12 +58,14 @@ static BOOL need_helper_const(const WineD3D_GL_Info *gl_info) { return FALSE; } -static unsigned int reserved_vs_const(const WineD3D_GL_Info *gl_info) { +static unsigned int reserved_vs_const(IWineD3DBaseShader *shader, const WineD3D_GL_Info *gl_info) { + unsigned int ret = 1; /* We use one PARAM for the pos fixup, and in some cases one to load * some immediate values into the shader */ - if(need_helper_const(gl_info)) return 2; - else return 1; + if(need_helper_const(gl_info)) ret++; + if(need_mova_const(shader, gl_info)) ret++; + return ret; } /* Internally used shader constants. Applications can use constants 0 to GL_LIMITS(vshader_constantsF) - 1, @@ -328,7 +337,7 @@ static void shader_generate_arb_declarations(IWineD3DBaseShader *iface, const sh max_constantsF = GL_LIMITS(pshader_constantsF); } else { if(This->baseShader.reg_maps.usesrelconstF) { - max_constantsF = GL_LIMITS(vshader_constantsF) - reserved_vs_const(gl_info); + max_constantsF = GL_LIMITS(vshader_constantsF) - reserved_vs_const(iface, gl_info); } else { max_constantsF = GL_LIMITS(vshader_constantsF) - 1; } @@ -998,17 +1007,35 @@ static void shader_hw_mov(const struct wined3d_shader_instruction *ins) { IWineD3DBaseShaderImpl *shader = (IWineD3DBaseShaderImpl *)ins->ctx->shader; - 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) - || ins->handler_idx == WINED3DSIH_MOVA) + SHADER_BUFFER *buffer = ins->ctx->buffer; + char src0_param[256]; + + if(ins->handler_idx == WINED3DSIH_MOVA) { + struct wined3d_shader_src_param tmp_src = ins->src[0]; + tmp_src.swizzle = (tmp_src.swizzle & 0x3) * 0x55; + shader_arb_get_src_param(ins, &tmp_src, 0, src0_param); + + /* 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 + * in this case: + * mova A0.x, 0.0 + * + * A0.x = arl(floor(abs(0.0) + 0.5) * 1.0) = floor(0.5) = 0.0 since arl does a floor + * + * 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, "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"); + } 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) { - SHADER_BUFFER *buffer = ins->ctx->buffer; - char src0_param[256]; - - if (ins->handler_idx == WINED3DSIH_MOVA) - FIXME("mova should round\n"); - src0_param[0] = '\0'; if (((IWineD3DVertexShaderImpl *)shader)->rel_offset) { @@ -2010,6 +2037,9 @@ static GLuint shader_arb_generate_vshader(IWineD3DVertexShader *iface, if(need_helper_const(gl_info)) { shader_addline(buffer, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This->rel_offset); } + if(need_mova_const((IWineD3DBaseShader *) iface, gl_info)) { + shader_addline(buffer, "PARAM mova_const = { 0.5, 0.0, 2.0, 1.0 };\n"); + } /* Mesa supports only 95 constants */ if (GL_VEND(MESA) || GL_VEND(WINE)) diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c index 1746917e6bb..cf8171b1057 100644 --- a/dlls/wined3d/baseshader.c +++ b/dlls/wined3d/baseshader.c @@ -611,6 +611,10 @@ HRESULT shader_get_registers_used(IWineD3DBaseShader *iface, const struct wined3 { reg_maps->usestexldd = 1; } + else if(ins.handler_idx == WINED3DSIH_MOVA) + { + reg_maps->usesmova = 1; + } limit = ins.src_count + (ins.predicate ? 1 : 0); for (i = 0; i < limit; ++i) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index a0dcddb3416..526ba24ee9e 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -632,7 +632,7 @@ typedef struct shader_reg_maps WINED3DSAMPLER_TEXTURE_TYPE sampler_type[max(MAX_FRAGMENT_SAMPLERS, MAX_VERTEX_SAMPLERS)]; BOOL bumpmat[MAX_TEXTURES], luminanceparams[MAX_TEXTURES]; - char usesnrm, vpos, usesdsy, usestexldd; + char usesnrm, vpos, usesdsy, usestexldd, usesmova; char usesrelconstF; /* Whether or not loops are used in this shader, and nesting depth */