Commit 54fa7129 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Initialize output texcoord .w to 1.0 if needed.

The GL_ARB_vertex_program extension does not define a standard value for output texture coordinates. This makes problems when using vertex shaders with fixed function fragment processing because fffp divides the texture coords by its .w component. This means that gl shaders have to write to the .w component of texture coords. Direct3D shaders however do not.
parent 6cdbb96b
......@@ -463,6 +463,15 @@ HRESULT shader_get_registers_used(
reg_maps->usesrelconstF = TRUE;
}
}
/* WINED3DSPR_TEXCRDOUT is the same as WINED3DSPR_OUTPUT. _OUTPUT can be > MAX_REG_TEXCRD and is used
* in >= 3.0 shaders. Filter 3.0 shaders to prevent overflows, and also filter pixel shaders because TECRDOUT
* isn't used in them, but future register types might cause issues
*/
else if(WINED3DSPR_TEXCRDOUT == regtype && i == 0 /* Only look at writes */ &&
!pshader && WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) < 3) {
reg_maps->texcoord_mask[reg] |= shader_get_writemask(param);
}
}
}
}
......
......@@ -2860,6 +2860,20 @@ static void fixup_extensions(WineD3D_GL_Info *gl_info) {
gl_info->supported[ARB_TEXTURE_RECTANGLE] = TRUE;
}
}
/* The Intel GPUs on MacOS set the .w register of texcoords to 0.0 by default, which causes problems
* with fixed function fragment processing. Ideally this flag should be detected with a test shader
* and opengl feedback mode, but some GL implementations(MacOS ATI at least, propably all macos ones)
* do not like vertex shaders in feedback mode and return an error, even though it should be valid
* according to the spec.
*
* We don't want to enable this on all cards, as it adds an extra instruction per texcoord used. This
* makes the shader slower and eats instruction slots which should be available to the d3d app.
*/
if(gl_info->gl_vendor == VENDOR_INTEL) {
TRACE("Enabling vertex texture coord fixes in vertex shaders\n");
gl_info->set_texcoord_w = TRUE;
}
}
}
......
......@@ -2870,7 +2870,7 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs
SHADER_BUFFER buffer;
DWORD usage_token;
DWORD register_token;
DWORD usage, usage_idx;
DWORD usage, usage_idx, writemask;
char reg_mask[6];
semantic *semantics_out, *semantics_in;
......@@ -2880,8 +2880,21 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs
buffer.newline = TRUE;
if(vs_major < 3 && ps_major < 3) {
/* That one is easy: The vertex shader writes to the builtin varyings, the pixel shader reads from them */
/* 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) {
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 &&
vs->baseShader.reg_maps.texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) {
shader_addline(&buffer, "gl_TexCoord[%u].w = 1.0;\n", i);
}
}
shader_addline(&buffer, "}\n");
} else {
shader_addline(&buffer, "void order_ps_input() { /* do nothing */ }\n");
}
} else if(ps_major < 3 && vs_major >= 3) {
/* The vertex shader writes to its own varyings, the pixel shader needs them in the builtin ones */
semantics_out = vs->semantics_out;
......@@ -2894,7 +2907,7 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs
usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
usage_idx = (usage_token & WINED3DSP_DCL_USAGEINDEX_MASK) >> WINED3DSP_DCL_USAGEINDEX_SHIFT;
shader_glsl_get_write_mask(register_token, reg_mask);
writemask = shader_glsl_get_write_mask(register_token, reg_mask);
switch(usage) {
case WINED3DDECLUSAGE_COLOR:
......@@ -2910,8 +2923,13 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs
case WINED3DDECLUSAGE_TEXCOORD:
if (usage_idx < 8) {
if(!(GLINFO_LOCATION).set_texcoord_w || ps_major > 0) writemask |= WINED3DSP_WRITEMASK_3;
shader_addline(&buffer, "gl_TexCoord[%u]%s = OUT[%u]%s;\n",
usage_idx, reg_mask, i, reg_mask);
if(!(writemask & WINED3DSP_WRITEMASK_3)) {
shader_addline(&buffer, "gl_TexCoord[%u].w = 1.0;\n", usage_idx);
}
}
break;
......
......@@ -455,6 +455,16 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
/* We need a constant to fixup the final position */
shader_addline(&buffer, "PARAM posFixup = program.env[%d];\n", ARB_SHADER_PRIVCONST_POS);
if((GLINFO_LOCATION).set_texcoord_w) {
int i;
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
if(This->baseShader.reg_maps.texcoord_mask[i] != 0 &&
This->baseShader.reg_maps.texcoord_mask[i] != WINED3DSP_WRITEMASK_ALL) {
shader_addline(&buffer, "MOV result.texcoord[%u].w, -helper_const.y;\n", i);
}
}
}
/* Base Shader Body */
shader_generate_main( (IWineD3DBaseShader*) This, &buffer, reg_maps, pFunction);
......
......@@ -1672,6 +1672,7 @@ typedef struct shader_reg_maps {
char packed_output[MAX_REG_OUTPUT]; /* vertex >= 3.0 */
char attributes[MAX_ATTRIBS]; /* vertex */
char labels[MAX_LABELS]; /* pixel, vertex */
DWORD texcoord_mask[MAX_REG_TEXCRD]; /* vertex < 3.0 */
/* Sampler usage tokens
* Use 0 as default (bit 31 is always 1 on a valid token) */
......@@ -2012,6 +2013,10 @@ static inline int shader_get_regtype(const DWORD param) {
((param & WINED3DSP_REGTYPE_MASK2) >> WINED3DSP_REGTYPE_SHIFT2));
}
static inline int shader_get_writemask(const DWORD param) {
return param & WINED3DSP_WRITEMASK_ALL;
}
extern unsigned int shader_get_float_offset(const DWORD reg);
static inline BOOL shader_is_pshader_version(DWORD token) {
......
......@@ -3685,6 +3685,7 @@ typedef struct _WineD3D_GL_Info {
GL_VSVersion vs_ati_version;
BOOL arb_vs_offset_limit;
BOOL set_texcoord_w;
BOOL supported[OPENGL_SUPPORTED_EXT_END + 1];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment