diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 616c12ee510..2f18ddce71f 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -2066,7 +2066,8 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; shader_reg_maps* reg_maps = &This->baseShader.reg_maps; CONST DWORD *function = This->baseShader.function; - WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info; + IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)This->baseShader.device; + WineD3D_GL_Info *gl_info = &device->adapter->gl_info; local_constant* lconst; /* Create the hw ARB shader */ @@ -2100,7 +2101,7 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF if(!GL_SUPPORT(NV_VERTEX_PROGRAM)) { shader_addline(buffer, "MOV result.color.secondary, -helper_const.wwwy;\n"); - if((GLINFO_LOCATION).set_texcoord_w) { + if((GLINFO_LOCATION).set_texcoord_w && !device->frag_pipe->ffp_proj_control) { int i; for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) { if(This->baseShader.reg_maps.texcoord_mask[i] != 0 && @@ -2746,11 +2747,12 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB if(settings->op[stage].projected == proj_none) { instr = "TEX"; - } else if(settings->op[stage].projected == proj_count4) { + } else if(settings->op[stage].projected == proj_count4 || + settings->op[stage].projected == proj_count3) { instr = "TXP"; } else { + FIXME("Unexpected projection mode %d\n", settings->op[stage].projected); instr = "TXP"; - ERR("Implement proj_count3\n"); } if(stage > 0 && @@ -2768,7 +2770,11 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB /* Note: Currently always divide by .a because the vertex pipeline moves the correct value * into the 4th component */ - shader_addline(&buffer, "RCP arg1.a, fragment.texcoord[%u].a;\n", stage); + if(settings->op[stage].projected == proj_count4) { + shader_addline(&buffer, "RCP arg1.a, fragment.texcoord[%u].a;\n", stage); + } else { + shader_addline(&buffer, "RCP arg1.a, fragment.texcoord[%u].b;\n", stage); + } shader_addline(&buffer, "MUL arg1.rg, fragment.texcoord[%u], arg1.a;\n", stage); shader_addline(&buffer, "ADD ret, ret, arg1;\n"); } else { @@ -2782,6 +2788,11 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB stage - 1, stage - 1, stage - 1); shader_addline(&buffer, "MUL tex%u, tex%u, ret.r;\n", stage, stage); } + } else if(settings->op[stage].projected == proj_count3) { + shader_addline(&buffer, "MOV ret, fragment.texcoord[%u];\n", stage); + shader_addline(&buffer, "MOV ret.a, ret.b;\n"); + shader_addline(&buffer, "%s%s tex%u, ret, texture[%u], %s;\n", + instr, sat, stage, stage, textype); } else { shader_addline(&buffer, "%s%s tex%u, fragment.texcoord[%u], texture[%u], %s;\n", instr, sat, stage, stage, stage, textype); @@ -3122,7 +3133,8 @@ const struct fragment_pipeline arbfp_fragment_pipeline = { arbfp_alloc, arbfp_free, shader_arb_conv_supported, - arbfp_fragmentstate_template + arbfp_fragmentstate_template, + TRUE /* We can disable projected textures */ }; #define GLINFO_LOCATION device->adapter->gl_info diff --git a/dlls/wined3d/ati_fragment_shader.c b/dlls/wined3d/ati_fragment_shader.c index 7707a2a43ca..97875c7362f 100644 --- a/dlls/wined3d/ati_fragment_shader.c +++ b/dlls/wined3d/ati_fragment_shader.c @@ -314,8 +314,10 @@ static GLuint gen_ati_shader(struct texture_stage_op op[MAX_TEXTURES], WineD3D_G GL_SWIZZLE_STR_ATI)); if(op[stage + 1].projected == proj_none) { swizzle = GL_SWIZZLE_STR_ATI; - } else { + } else if(op[stage + 1].projected == proj_count4) { swizzle = GL_SWIZZLE_STQ_DQ_ATI; + } else { + swizzle = GL_SWIZZLE_STR_DR_ATI; } TRACE("glPassTexCoordATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n", stage + 1, stage + 1, debug_swizzle(swizzle)); @@ -382,15 +384,7 @@ static GLuint gen_ati_shader(struct texture_stage_op op[MAX_TEXTURES], WineD3D_G if(op[stage].projected == proj_none) { swizzle = GL_SWIZZLE_STR_ATI; } else if(op[stage].projected == proj_count3) { - /* TODO: D3DTTFF_COUNT3 | D3DTTFF_PROJECTED would be GL_SWIZZLE_STR_DR_ATI. - * However, the FFP vertex processing texture transform matrix handler does - * some transformations in the texture matrix which makes the 3rd coordinate - * arrive in Q, not R in that case. This is needed for opengl fixed function - * fragment processing which always divides by Q. In this backend we can - * handle that properly and be compatible with vertex shader output and avoid - * side effects of the texture matrix games - */ - swizzle = GL_SWIZZLE_STQ_DQ_ATI; + swizzle = GL_SWIZZLE_STR_DR_ATI; } else { swizzle = GL_SWIZZLE_STQ_DQ_ATI; } @@ -875,6 +869,13 @@ static void set_bumpmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat)); checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)"); } + +static void textransform(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) { + if(!isStateDirty(context, STATE_PIXELSHADER)) { + set_tex_op_atifs(state, stateblock, context); + } +} + #undef GLINFO_LOCATION static const struct StateEntryTemplate atifs_fragmentstate_template[] = { @@ -991,6 +992,14 @@ static const struct StateEntryTemplate atifs_fragmentstate_template[] = { { STATE_SAMPLER(5), { STATE_SAMPLER(5), sampler_texdim }, 0 }, { STATE_SAMPLER(6), { STATE_SAMPLER(6), sampler_texdim }, 0 }, { STATE_SAMPLER(7), { STATE_SAMPLER(7), sampler_texdim }, 0 }, + {STATE_TEXTURESTAGE(0,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(0, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(1,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(1, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(2,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(2, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(3,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(3, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(4,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(4, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(5,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(5, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(6,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(6, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, + {STATE_TEXTURESTAGE(7,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(7, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 }, {0 /* Terminate */, { 0, 0 }, 0 }, }; @@ -1107,5 +1116,6 @@ const struct fragment_pipeline atifs_fragment_pipeline = { atifs_alloc, atifs_free, atifs_conv_supported, - atifs_fragmentstate_template + atifs_fragmentstate_template, + TRUE /* We can disable projected textures */ }; diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index ee38ffc51c0..e89dbf30398 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -3008,6 +3008,7 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs GLhandleARB ret = 0; IWineD3DVertexShaderImpl *vs = (IWineD3DVertexShaderImpl *) vertexshader; IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) pixelshader; + IWineD3DDeviceImpl *device; DWORD vs_major = vs ? WINED3DSHADER_VERSION_MAJOR(vs->baseShader.hex_version) : 0; DWORD ps_major = ps ? WINED3DSHADER_VERSION_MAJOR(ps->baseShader.hex_version) : 0; unsigned int i; @@ -3029,7 +3030,9 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs /* That one is easy: The vertex shader writes to the builtin varyings, the pixel shader reads from them. * Take care about the texcoord .w fixup though if we're using the fixed function fragment pipeline */ - if((GLINFO_LOCATION).set_texcoord_w && ps_major == 0 && vs_major > 0) { + device = (IWineD3DDeviceImpl *) vs->baseShader.device; + if((GLINFO_LOCATION).set_texcoord_w && ps_major == 0 && vs_major > 0 && + !device->frag_pipe->ffp_proj_control) { shader_addline(&buffer, "void order_ps_input() {\n"); for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) { if(vs->baseShader.reg_maps.texcoord_mask[i] != 0 && diff --git a/dlls/wined3d/nvidia_texture_shader.c b/dlls/wined3d/nvidia_texture_shader.c index 5f3666875c0..ca21ba0659d 100644 --- a/dlls/wined3d/nvidia_texture_shader.c +++ b/dlls/wined3d/nvidia_texture_shader.c @@ -810,7 +810,8 @@ const struct fragment_pipeline nvts_fragment_pipeline = { nvrc_fragment_alloc, nvrc_fragment_free, nvts_conv_supported, - nvrc_fragmentstate_template + nvrc_fragmentstate_template, + FALSE /* we cannot disable projected textures. The vertex pipe has to do it */ }; const struct fragment_pipeline nvrc_fragment_pipeline = { @@ -819,5 +820,6 @@ const struct fragment_pipeline nvrc_fragment_pipeline = { nvrc_fragment_alloc, nvrc_fragment_free, nvts_conv_supported, - nvrc_fragmentstate_template + nvrc_fragmentstate_template, + FALSE /* we cannot disable projected textures. The vertex pipe has to do it */ }; diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index c53f398b0a0..d97df5af0d3 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -1,3 +1,4 @@ + /* * Direct3D state management * @@ -3139,7 +3140,8 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W context->last_was_rhw, stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwStride ? stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwType: - WINED3DDECLTYPE_UNUSED); + WINED3DDECLTYPE_UNUSED, + stateblock->wineD3DDevice->frag_pipe->ffp_proj_control); /* The sampler applying function calls us if this changes */ if(context->lastWasPow2Texture[texUnit] && stateblock->textures[texUnit]) { @@ -5565,7 +5567,8 @@ const struct fragment_pipeline ffp_fragment_pipeline = { ffp_fragment_alloc, ffp_fragment_free, ffp_conv_supported, - ffp_fragmentstate_template + ffp_fragmentstate_template, + FALSE /* we cannot disable projected textures. The vertex pipe has to do it */ }; static int num_handlers(APPLYSTATEFUNC *funcs) { diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index c0e1ccfeac0..a577e28a132 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -1166,7 +1166,8 @@ BOOL is_invalid_op(IWineD3DDeviceImpl *This, int stage, WINED3DTEXTUREOP op, DWO } /* Setup this textures matrix according to the texture flags*/ -void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype) +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype, + BOOL ffp_proj_control) { float mat[16]; @@ -1187,15 +1188,17 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B memcpy(mat, smat, 16 * sizeof(float)); if (flags & WINED3DTTFF_PROJECTED) { - switch (flags & ~WINED3DTTFF_PROJECTED) { - case WINED3DTTFF_COUNT2: - mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13]; - mat[1] = mat[5] = mat[9] = mat[13] = 0; - break; - case WINED3DTTFF_COUNT3: - mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14]; - mat[2] = mat[6] = mat[10] = mat[14] = 0; - break; + if(!ffp_proj_control) { + switch (flags & ~WINED3DTTFF_PROJECTED) { + case WINED3DTTFF_COUNT2: + mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13]; + mat[1] = mat[5] = mat[9] = mat[13] = 0; + break; + case WINED3DTTFF_COUNT3: + mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14]; + mat[2] = mat[6] = mat[10] = mat[14] = 0; + break; + } } } else { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */ if(!calculatedCoords) { @@ -1231,23 +1234,25 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B FIXME("Unexpected fixed function texture coord input\n"); } } - switch (flags & ~WINED3DTTFF_PROJECTED) { - /* case WINED3DTTFF_COUNT1: Won't ever get here */ - case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; - /* OpenGL divides the first 3 vertex coord by the 4th by default, - * which is essentially the same as D3DTTFF_PROJECTED. Make sure that - * the 4th coord evaluates to 1.0 to eliminate that. - * - * If the fixed function pipeline is used, the 4th value remains unused, - * so there is no danger in doing this. With vertex shaders we have a - * problem. Should an app hit that problem, the code here would have to - * check for pixel shaders, and the shader has to undo the default gl divide. - * - * A more serious problem occurs if the app passes 4 coordinates in, and the - * 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow - * or a replacement shader - */ - default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1; + if(!ffp_proj_control) { + switch (flags & ~WINED3DTTFF_PROJECTED) { + /* case WINED3DTTFF_COUNT1: Won't ever get here */ + case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; + /* OpenGL divides the first 3 vertex coord by the 4th by default, + * which is essentially the same as D3DTTFF_PROJECTED. Make sure that + * the 4th coord evaluates to 1.0 to eliminate that. + * + * If the fixed function pipeline is used, the 4th value remains unused, + * so there is no danger in doing this. With vertex shaders we have a + * problem. Should an app hit that problem, the code here would have to + * check for pixel shaders, and the shader has to undo the default gl divide. + * + * A more serious problem occurs if the app passes 4 coordinates in, and the + * 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow + * or a replacement shader + */ + default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1; + } } } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 72e9aee0d6b..897e65482d3 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -559,6 +559,7 @@ struct fragment_pipeline { void (*free_private)(IWineD3DDevice *iface); BOOL (*conv_supported)(WINED3DFORMAT conv); const struct StateEntryTemplate *states; + BOOL ffp_proj_control; }; extern const struct StateEntryTemplate misc_state_template[]; @@ -1816,7 +1817,7 @@ GLenum StencilOp(DWORD op); GLenum CompareFunc(DWORD func); BOOL is_invalid_op(IWineD3DDeviceImpl *This, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3); void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx, DWORD dst); -void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype); +void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype, BOOL ffp_can_disable_proj); void texture_activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context); void sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context); void tex_alphaop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context);