Stefan Dösinger : wined3d: Initialize output texcoord .w to 1.0 if needed.

Alexandre Julliard julliard at winehq.org
Fri Dec 7 11:01:51 CST 2007


Module: wine
Branch: master
Commit: 54fa7129816a4d20bbd3d0649be539707e68311a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=54fa7129816a4d20bbd3d0649be539707e68311a

Author: Stefan Dösinger <stefan at codeweavers.com>
Date:   Thu Dec  6 22:10:11 2007 +0100

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.

---

 dlls/wined3d/baseshader.c      |    9 +++++++++
 dlls/wined3d/directx.c         |   14 ++++++++++++++
 dlls/wined3d/glsl_shader.c     |   28 +++++++++++++++++++++++-----
 dlls/wined3d/vertexshader.c    |   10 ++++++++++
 dlls/wined3d/wined3d_private.h |    5 +++++
 include/wine/wined3d_gl.h      |    1 +
 6 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index 5f94a29..0a0c10e 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -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);
+                }
             }
         }
     }
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index c712bb4..a269988 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -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;
+        }
     }
 }
 
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 0b68c78..80b8ea9 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -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 */
-        shader_addline(&buffer, "void order_ps_input() { /* do nothing */ }\n");
+        /* 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);
+                                        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;
 
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index f67cbae..13349de 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -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);
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index c0e1265..86a6bb8 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -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) {
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 86ad677..c364f09 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -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];
 




More information about the wine-cvs mailing list