wined3d: Make shader texture format fixups more generic.

Henri Verbeet hverbeet at codeweavers.com
Wed Dec 3 07:53:43 CST 2008


Based on a patch by Stefan Dösinger. This is more flexible, and allows the
shader backend implementation to be simpler, since it doesn't have to know
about specific formats. The next patch makes use of this.
---
 dlls/wined3d/arb_program_shader.c    |  468 +++++++++++++--------------------
 dlls/wined3d/ati_fragment_shader.c   |   58 +++--
 dlls/wined3d/baseshader.c            |   98 ++++++--
 dlls/wined3d/device.c                |    6 +-
 dlls/wined3d/directx.c               |   53 ++---
 dlls/wined3d/glsl_shader.c           |  297 ++++++++--------------
 dlls/wined3d/nvidia_texture_shader.c |   22 ++-
 dlls/wined3d/pixelshader.c           |    6 +-
 dlls/wined3d/state.c                 |   20 ++-
 dlls/wined3d/surface.c               |   21 ++-
 dlls/wined3d/utils.c                 |  100 ++++++--
 dlls/wined3d/wined3d_private.h       |  126 ++++++++--
 12 files changed, 686 insertions(+), 589 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 44c302b..8ec1a3b 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -36,6 +36,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_constants);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
+WINE_DECLARE_DEBUG_CHANNEL(d3d);
 
 #define GLINFO_LOCATION      (*gl_info)
 
@@ -595,229 +596,81 @@ static void shader_hw_sample(const SHADER_OPCODE_ARG *arg, DWORD sampler_idx, co
     }
 }
 
-static void gen_color_correction(SHADER_BUFFER *buffer, const char *reg, const char *writemask,
-                                 const char *one, const char *two, WINED3DFORMAT fmt,
-                                 const WineD3D_GL_Info *gl_info)
+static const char *shader_arb_get_fixup_swizzle(enum fixup_channel_source channel_source)
 {
-    switch(fmt) {
-        case WINED3DFMT_V8U8:
-        case WINED3DFMT_V16U16:
-            if(GL_SUPPORT(NV_TEXTURE_SHADER) && fmt == WINED3DFMT_V8U8) {
-                /* The 3rd channel returns 1.0 in d3d, but 0.0 in gl. Fix this while we're at it :-)
-                 * The dx7 sdk BumpEarth demo needs it because it uses BUMPENVMAPLUMINANCE with V8U8.
-                 * With the luminance(b) value = 1.0, BUMPENVMAPLUMINANCE == BUMPENVMAP, but if b is
-                 * 0.0(without this fixup), the rendering breaks.
-                 */
-                if(strlen(writemask) >= 4) {
-                    shader_addline(buffer, "MOV %s.%c, %s;\n", reg, writemask[3], one);
-                }
-            } else {
-                /* Correct the sign, but leave the blue as it is - it was loaded correctly already
-                 * ARB shaders are a bit picky wrt writemasks and swizzles. If we're free to scale
-                 * all registers, do so, this saves an instruction.
-                 */
-                if(strlen(writemask) >= 5) {
-                    shader_addline(buffer, "MAD %s, %s, %s, -%s;\n", reg, reg, two, one);
-                } else if(strlen(writemask) >= 3) {
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n",
-                                   reg, writemask[1],
-                                   reg, writemask[1],
-                                   two, one);
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n",
-                                   reg, writemask[2],
-                                   reg, writemask[2],
-                                   two, one);
-                } else if(strlen(writemask) == 2) {
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n", reg, writemask[1],
-                                   reg, writemask[1], two, one);
-                }
-            }
-            break;
-
-        case WINED3DFMT_X8L8V8U8:
-            if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
-                /* Red and blue are the signed channels, fix them up; Blue(=L) is correct already,
-                 * and a(X) is always 1.0. Cannot do a full conversion due to L(blue)
-                 */
-                if(strlen(writemask) >= 3) {
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n",
-                                   reg, writemask[1],
-                                   reg, writemask[1],
-                                   two, one);
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n",
-                                   reg, writemask[2],
-                                   reg, writemask[2],
-                                   two, one);
-                } else if(strlen(writemask) == 2) {
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n",
-                                   reg, writemask[1],
-                                   reg, writemask[1],
-                                   two, one);
-                }
-            }
-            break;
-
-        case WINED3DFMT_L6V5U5:
-            if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
-                if(strlen(writemask) >= 4) {
-                    /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */
-                    shader_addline(buffer, "MOV TMP.g, %s.%c;\n",
-                                   reg, writemask[2]);
-                    shader_addline(buffer, "MAD %s.%c%c, %s.%c%c%c%c, %s, -%s;\n",
-                                   reg, writemask[1], writemask[2],
-                                   reg, writemask[3], writemask[1], writemask[3], writemask[1],
-                                   two, one);
-                    shader_addline(buffer, "MOV %s.%c, TMP.g;\n", reg,
-                                   writemask[3]);
-                } else if(strlen(writemask) == 3) {
-                    /* This is bad: We have VL, but we need VU */
-                    FIXME("2 components sampled from a converted L6V5U5 texture\n");
-                } else {
-                    shader_addline(buffer, "MAD %s.%c, %s.%c, %s, -%s;\n",
-                                   reg, writemask[1],
-                                   reg, writemask[1],
-                                   two, one);
-                }
-            }
-            break;
-
-        case WINED3DFMT_Q8W8V8U8:
-            if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
-                /* Correct the sign in all channels */
-                switch(strlen(writemask)) {
-                    case 4:
-                        shader_addline(buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
-                                       reg, writemask[3],
-                                       reg, writemask[3]);
-                        /* drop through */
-                    case 3:
-                        shader_addline(buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
-                                       reg, writemask[2],
-                                       reg, writemask[2]);
-                        /* drop through */
-                    case 2:
-                        shader_addline(buffer, "MAD %s.%c, %s.%c, coefmul.x, -one;\n",
-                                       reg, writemask[1],
-                                       reg, writemask[1]);
-                        break;
-
-                        /* Should not occur, since it's at minimum '.' and a letter */
-                    case 1:
-                        ERR("Unexpected writemask: \"%s\"\n", writemask);
-                        break;
-
-                    case 5:
-                    default:
-                        shader_addline(buffer, "MAD %s, %s, coefmul.x, -one;\n", reg, reg);
-                }
-            }
-            break;
-
-        case WINED3DFMT_ATI2N:
-            /* GL_ATI_texture_compression_3dc returns the two channels as luminance-alpha,
-             * which means the first one is replicated across .rgb, and the 2nd one is in
-             * .a. We need the 2nd in .g
-             *
-             * GL_EXT_texture_compression_rgtc returns the values in .rg, however, they
-             * are swapped compared to d3d. So swap red and green.
-             */
-            if(GL_SUPPORT(EXT_TEXTURE_COMPRESSION_RGTC)) {
-                shader_addline(buffer, "SWZ %s, %s, %c, %c, 1, 0;\n",
-                               reg, reg, writemask[2], writemask[1]);
-            } else {
-                if(strlen(writemask) == 5) {
-                    shader_addline(buffer, "MOV %s.%c, %s.%c;\n",
-                                reg, writemask[2], reg, writemask[4]);
-                } else if(strlen(writemask) == 2) {
-                    /* Nothing to do */
-                } else {
-                    /* This is bad: We have VL, but we need VU */
-                    FIXME("2 or 3 components sampled from a converted ATI2N texture\n");
-                }
-            }
-            break;
-
-            /* stupid compiler */
+    switch(channel_source)
+    {
+        case CHANNEL_SOURCE_ZERO: return "0";
+        case CHANNEL_SOURCE_ONE: return "1";
+        case CHANNEL_SOURCE_X: return "x";
+        case CHANNEL_SOURCE_Y: return "y";
+        case CHANNEL_SOURCE_Z: return "z";
+        case CHANNEL_SOURCE_W: return "w";
         default:
-            break;
+            FIXME("Unhandled channel source %#x\n", channel_source);
+            return "undefined";
     }
 }
 
-static void shader_arb_color_correction(const SHADER_OPCODE_ARG* arg)
+static void gen_color_correction(SHADER_BUFFER *buffer, const char *reg, DWORD dst_mask,
+        const char *one, const char *two, struct color_fixup_desc fixup)
 {
-    IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader;
-    IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) shader->baseShader.device;
-    const WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
-    WINED3DFORMAT fmt;
-    WINED3DFORMAT conversion_group;
-    IWineD3DBaseTextureImpl *texture;
-    UINT i;
-    BOOL recorded = FALSE;
-    DWORD sampler_idx;
-    DWORD hex_version = shader->baseShader.hex_version;
-    char reg[256];
-    char writemask[6];
+    DWORD mask;
 
-    switch(arg->opcode->opcode) {
-        case WINED3DSIO_TEX:
-            if (hex_version < WINED3DPS_VERSION(2,0)) {
-                sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
-            } else {
-                sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK;
-            }
-            break;
+    if (is_yuv_fixup(fixup))
+    {
+        enum yuv_fixup yuv_fixup = get_yuv_fixup(fixup);
+        FIXME("YUV fixup (%#x) not supported\n", yuv_fixup);
+        return;
+    }
 
-        case WINED3DSIO_TEXLDL:
-            FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n");
-            return;
+    mask = 0;
+    if (fixup.x_source != CHANNEL_SOURCE_X) mask |= WINED3DSP_WRITEMASK_0;
+    if (fixup.y_source != CHANNEL_SOURCE_Y) mask |= WINED3DSP_WRITEMASK_1;
+    if (fixup.z_source != CHANNEL_SOURCE_Z) mask |= WINED3DSP_WRITEMASK_2;
+    if (fixup.w_source != CHANNEL_SOURCE_W) mask |= WINED3DSP_WRITEMASK_3;
+    mask &= dst_mask;
 
-        case WINED3DSIO_TEXDP3TEX:
-        case WINED3DSIO_TEXM3x3TEX:
-        case WINED3DSIO_TEXM3x3SPEC:
-        case WINED3DSIO_TEXM3x3VSPEC:
-        case WINED3DSIO_TEXBEM:
-        case WINED3DSIO_TEXREG2AR:
-        case WINED3DSIO_TEXREG2GB:
-        case WINED3DSIO_TEXREG2RGB:
-            sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
-            break;
+    if (mask)
+    {
+        shader_addline(buffer, "SWZ %s, %s, %s, %s, %s, %s;\n", reg, reg,
+                shader_arb_get_fixup_swizzle(fixup.x_source), shader_arb_get_fixup_swizzle(fixup.y_source),
+                shader_arb_get_fixup_swizzle(fixup.z_source), shader_arb_get_fixup_swizzle(fixup.w_source));
+    }
 
-        default:
-            /* Not a texture sampling instruction, nothing to do */
-            return;
-    };
+    mask = 0;
+    if (fixup.x_sign_fixup) mask |= WINED3DSP_WRITEMASK_0;
+    if (fixup.y_sign_fixup) mask |= WINED3DSP_WRITEMASK_1;
+    if (fixup.z_sign_fixup) mask |= WINED3DSP_WRITEMASK_2;
+    if (fixup.w_sign_fixup) mask |= WINED3DSP_WRITEMASK_3;
+    mask &= dst_mask;
 
-    texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx];
-    if(texture) {
-        fmt = texture->resource.format;
-        conversion_group = texture->baseTexture.shader_conversion_group;
-    } else {
-        fmt = WINED3DFMT_UNKNOWN;
-        conversion_group = WINED3DFMT_UNKNOWN;
-    }
+    if (mask)
+    {
+        char reg_mask[6];
+        char *ptr = reg_mask;
 
-    /* before doing anything, record the sampler with the format in the format conversion list,
-     * but check if it's not there already
-     */
-    for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) {
-        if(shader->baseShader.sampled_samplers[i] == sampler_idx) {
-            recorded = TRUE;
+        if (mask != WINED3DSP_WRITEMASK_ALL)
+        {
+            *ptr++ = '.';
+            if (mask & WINED3DSP_WRITEMASK_0) *ptr++ = 'x';
+            if (mask & WINED3DSP_WRITEMASK_1) *ptr++ = 'y';
+            if (mask & WINED3DSP_WRITEMASK_2) *ptr++ = 'z';
+            if (mask & WINED3DSP_WRITEMASK_3) *ptr++ = 'w';
         }
+        *ptr = '\0';
+
+        shader_addline(buffer, "MAD %s%s, %s, %s, -%s;\n", reg, reg_mask, reg, two, one);
     }
-    if(!recorded) {
-        shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx;
-        shader->baseShader.num_sampled_samplers++;
-    }
+}
 
+static void shader_arb_color_correction(const struct SHADER_OPCODE_ARG* arg, struct color_fixup_desc fixup)
+{
+    char reg[256];
     pshader_get_register_name(arg->shader, arg->dst, reg);
-    shader_arb_get_write_mask(arg, arg->dst, writemask);
-    if(strlen(writemask) == 0) strcpy(writemask, ".xyzw");
-
-    gen_color_correction(arg->buffer, reg, writemask, "one", "coefmul.x", fmt, gl_info);
-
+    gen_color_correction(arg->buffer, reg, arg->dst & WINED3DSP_WRITEMASK_ALL, "one", "coefmul.x", fixup);
 }
 
-
 static void pshader_gen_input_modifier_line (
     IWineD3DBaseShader *iface,
     SHADER_BUFFER* buffer,
@@ -2218,21 +2071,23 @@ static void shader_arb_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *g
     }
 }
 
-static BOOL shader_arb_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking shader format support for format %s:", debug_d3dformat(fmt));
-    switch(fmt) {
-        case WINED3DFMT_V8U8:
-        case WINED3DFMT_V16U16:
-        case WINED3DFMT_X8L8V8U8:
-        case WINED3DFMT_L6V5U5:
-        case WINED3DFMT_Q8W8V8U8:
-        case WINED3DFMT_ATI2N:
-            TRACE("[OK]\n");
-            return TRUE;
-        default:
-            TRACE("[FAILED\n");
-            return FALSE;
+static BOOL shader_arb_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
+    {
+        TRACE("Checking support for color_fixup:\n");
+        dump_color_fixup_desc(fixup);
     }
+
+    /* We support everything except YUV conversions. */
+    if (!is_yuv_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    TRACE("[FAILED]\n");
+    return FALSE;
 }
 
 static const SHADER_HANDLER shader_arb_instruction_handler_table[WINED3DSIH_TABLE_SIZE] =
@@ -2337,7 +2192,7 @@ const shader_backend_t arb_program_shader_backend = {
     shader_arb_generate_pshader,
     shader_arb_generate_vshader,
     shader_arb_get_caps,
-    shader_arb_conv_supported,
+    shader_arb_color_fixup_supported,
 };
 
 /* ARB_fragment_program fixed function pipeline replacement definitions */
@@ -2955,8 +2810,8 @@ static GLuint gen_arbfp_ffp_shader(const struct ffp_frag_settings *settings, IWi
         }
 
         sprintf(colorcor_dst, "tex%u", stage);
-        gen_color_correction(&buffer, colorcor_dst, ".rgba", "const.x", "const.y",
-                                settings->op[stage].color_correction, &GLINFO_LOCATION);
+        gen_color_correction(&buffer, colorcor_dst, WINED3DSP_WRITEMASK_ALL, "const.x", "const.y",
+                settings->op[stage].color_correction);
     }
 
     /* Generate the main shader */
@@ -3290,7 +3145,7 @@ const struct fragment_pipeline arbfp_fragment_pipeline = {
     arbfp_get_caps,
     arbfp_alloc,
     arbfp_free,
-    shader_arb_conv_supported,
+    shader_arb_color_fixup_supported,
     arbfp_fragmentstate_template,
     TRUE /* We can disable projected textures */
 };
@@ -3327,11 +3182,12 @@ static void arbfp_blit_free(IWineD3DDevice *iface) {
     LEAVE_GL();
 }
 
-static BOOL gen_planar_yuv_read(SHADER_BUFFER *buffer, WINED3DFORMAT fmt, GLenum textype, char *luminance) {
+static BOOL gen_planar_yuv_read(SHADER_BUFFER *buffer, enum yuv_fixup yuv_fixup, GLenum textype, char *luminance)
+{
     char chroma;
     const char *tex, *texinstr;
 
-    if(fmt == WINED3DFMT_UYVY) {
+    if (yuv_fixup == YUV_FIXUP_UYVY) {
         chroma = 'r';
         *luminance = 'a';
     } else {
@@ -3413,7 +3269,8 @@ static BOOL gen_planar_yuv_read(SHADER_BUFFER *buffer, WINED3DFORMAT fmt, GLenum
     return TRUE;
 }
 
-static BOOL gen_yv12_read(SHADER_BUFFER *buffer, WINED3DFORMAT fmt, GLenum textype, char *luminance) {
+static BOOL gen_yv12_read(SHADER_BUFFER *buffer, GLenum textype, char *luminance)
+{
     const char *tex;
 
     switch(textype) {
@@ -3558,7 +3415,8 @@ static BOOL gen_yv12_read(SHADER_BUFFER *buffer, WINED3DFORMAT fmt, GLenum texty
     return TRUE;
 }
 
-static GLuint gen_yuv_shader(IWineD3DDeviceImpl *device, WINED3DFORMAT fmt, GLenum textype) {
+static GLuint gen_yuv_shader(IWineD3DDeviceImpl *device, enum yuv_fixup yuv_fixup, GLenum textype)
+{
     GLenum shader;
     SHADER_BUFFER buffer;
     char luminance_component;
@@ -3626,16 +3484,29 @@ static GLuint gen_yuv_shader(IWineD3DDeviceImpl *device, WINED3DFORMAT fmt, GLen
     shader_addline(&buffer, "PARAM yuv_coef = {1.403, 0.344, 0.714, 1.770};\n");
     shader_addline(&buffer, "PARAM size = program.local[0];\n");
 
-    if(fmt == WINED3DFMT_UYVY || fmt ==WINED3DFMT_YUY2) {
-        if(gen_planar_yuv_read(&buffer, fmt, textype, &luminance_component) == FALSE) {
-            HeapFree(GetProcessHeap(), 0, buffer.buffer);
-            return 0;
-        }
-    } else {
-        if(gen_yv12_read(&buffer, fmt, textype, &luminance_component) == FALSE) {
+    switch (yuv_fixup)
+    {
+        case YUV_FIXUP_UYVY:
+        case YUV_FIXUP_YUY2:
+            if (!gen_planar_yuv_read(&buffer, yuv_fixup, textype, &luminance_component))
+            {
+                HeapFree(GetProcessHeap(), 0, buffer.buffer);
+                return 0;
+            }
+            break;
+
+        case YUV_FIXUP_YV12:
+            if (!gen_yv12_read(&buffer, textype, &luminance_component))
+            {
+                HeapFree(GetProcessHeap(), 0, buffer.buffer);
+                return 0;
+            }
+            break;
+
+        default:
+            FIXME("Unsupported YUV fixup %#x\n", yuv_fixup);
             HeapFree(GetProcessHeap(), 0, buffer.buffer);
             return 0;
-        }
     }
 
     /* Calculate the final result. Formula is taken from
@@ -3662,25 +3533,24 @@ static GLuint gen_yuv_shader(IWineD3DDeviceImpl *device, WINED3DFORMAT fmt, GLen
     HeapFree(GetProcessHeap(), 0, buffer.buffer);
     LEAVE_GL();
 
-    if(fmt == WINED3DFMT_YUY2) {
-        if(textype == GL_TEXTURE_RECTANGLE_ARB) {
-            priv->yuy2_rect_shader = shader;
-        } else {
-            priv->yuy2_2d_shader = shader;
-        }
-    } else if(fmt == WINED3DFMT_UYVY) {
-        if(textype == GL_TEXTURE_RECTANGLE_ARB) {
-            priv->uyvy_rect_shader = shader;
-        } else {
-            priv->uyvy_2d_shader = shader;
-        }
-    } else {
-        if(textype == GL_TEXTURE_RECTANGLE_ARB) {
-            priv->yv12_rect_shader = shader;
-        } else {
-            priv->yv12_2d_shader = shader;
-        }
+    switch (yuv_fixup)
+    {
+        case YUV_FIXUP_YUY2:
+            if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->yuy2_rect_shader = shader;
+            else priv->yuy2_2d_shader = shader;
+            break;
+
+        case YUV_FIXUP_UYVY:
+            if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->uyvy_rect_shader = shader;
+            else priv->uyvy_2d_shader = shader;
+            break;
+
+        case YUV_FIXUP_YV12:
+            if (textype == GL_TEXTURE_RECTANGLE_ARB) priv->yv12_rect_shader = shader;
+            else priv->yv12_2d_shader = shader;
+            break;
     }
+
     return shader;
 }
 
@@ -3690,12 +3560,14 @@ static HRESULT arbfp_blit_set(IWineD3DDevice *iface, WINED3DFORMAT fmt, GLenum t
     float size[4] = {width, height, 1, 1};
     struct arbfp_blit_priv *priv = (struct arbfp_blit_priv *) device->blit_priv;
     const struct GlPixelFormatDesc *glDesc;
+    enum yuv_fixup yuv_fixup;
 
     getFormatDescEntry(fmt, &GLINFO_LOCATION, &glDesc);
 
-    if(glDesc->conversion_group != WINED3DFMT_YUY2 && glDesc->conversion_group != WINED3DFMT_UYVY &&
-       glDesc->conversion_group != WINED3DFMT_YV12) {
-        TRACE("Format: %s\n", debug_d3dformat(glDesc->conversion_group));
+    if (!is_yuv_fixup(glDesc->color_fixup))
+    {
+        TRACE("Fixup:\n");
+        dump_color_fixup_desc(glDesc->color_fixup);
         /* Don't bother setting up a shader for unconverted formats */
         ENTER_GL();
         glEnable(textype);
@@ -3704,30 +3576,33 @@ static HRESULT arbfp_blit_set(IWineD3DDevice *iface, WINED3DFORMAT fmt, GLenum t
         return WINED3D_OK;
     }
 
-    if(glDesc->conversion_group == WINED3DFMT_YUY2) {
-        if(textype == GL_TEXTURE_RECTANGLE_ARB) {
-            shader = priv->yuy2_rect_shader;
-        } else {
-            shader = priv->yuy2_2d_shader;
-        }
-    } else if(glDesc->conversion_group == WINED3DFMT_UYVY) {
-        if(textype == GL_TEXTURE_RECTANGLE_ARB) {
-            shader = priv->uyvy_rect_shader;
-        } else {
-            shader = priv->uyvy_2d_shader;
-        }
-    } else {
-        if(textype == GL_TEXTURE_RECTANGLE_ARB) {
-            shader = priv->yv12_rect_shader;
-        } else {
-            shader = priv->yv12_2d_shader;
-        }
-    }
+    yuv_fixup = get_yuv_fixup(glDesc->color_fixup);
 
-    if(!shader) {
-        shader = gen_yuv_shader(device, glDesc->conversion_group, textype);
+    switch(yuv_fixup)
+    {
+        case YUV_FIXUP_YUY2:
+            shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->yuy2_rect_shader : priv->yuy2_2d_shader;
+            break;
+
+        case YUV_FIXUP_UYVY:
+            shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->uyvy_rect_shader : priv->uyvy_2d_shader;
+            break;
+
+        case YUV_FIXUP_YV12:
+            shader = textype == GL_TEXTURE_RECTANGLE_ARB ? priv->yv12_rect_shader : priv->yv12_2d_shader;
+            break;
+
+        default:
+            FIXME("Unsupported YUV fixup %#x, not setting a shader\n", yuv_fixup);
+            ENTER_GL();
+            glEnable(textype);
+            checkGLcall("glEnable(textype)");
+            LEAVE_GL();
+            return E_NOTIMPL;
     }
 
+    if (!shader) shader = gen_yuv_shader(device, yuv_fixup, textype);
+
     ENTER_GL();
     glEnable(GL_FRAGMENT_PROGRAM_ARB);
     checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)");
@@ -3759,15 +3634,40 @@ static void arbfp_blit_unset(IWineD3DDevice *iface) {
     LEAVE_GL();
 }
 
-static BOOL arbfp_blit_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking blit format support for format %s:", debug_d3dformat(fmt));
-    switch(fmt) {
-        case WINED3DFMT_YUY2:
-        case WINED3DFMT_UYVY:
-        case WINED3DFMT_YV12:
+static BOOL arbfp_blit_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    enum yuv_fixup yuv_fixup;
+
+    if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
+    }
+
+    if (is_identity_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    /* We only support YUV conversions. */
+    if (!is_yuv_fixup(fixup))
+    {
+        TRACE("[FAILED]\n");
+        return FALSE;
+    }
+
+    yuv_fixup = get_yuv_fixup(fixup);
+    switch(yuv_fixup)
+    {
+        case YUV_FIXUP_YUY2:
+        case YUV_FIXUP_UYVY:
+        case YUV_FIXUP_YV12:
             TRACE("[OK]\n");
             return TRUE;
+
         default:
+            FIXME("Unsupported YUV fixup %#x\n", yuv_fixup);
             TRACE("[FAILED]\n");
             return FALSE;
     }
@@ -3778,7 +3678,7 @@ const struct blit_shader arbfp_blit = {
     arbfp_blit_free,
     arbfp_blit_set,
     arbfp_blit_unset,
-    arbfp_blit_conv_supported
+    arbfp_blit_color_fixup_supported,
 };
 
 #undef GLINFO_LOCATION
diff --git a/dlls/wined3d/ati_fragment_shader.c b/dlls/wined3d/ati_fragment_shader.c
index b2fb23b..90ca192 100644
--- a/dlls/wined3d/ati_fragment_shader.c
+++ b/dlls/wined3d/ati_fragment_shader.c
@@ -26,6 +26,7 @@
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
+WINE_DECLARE_DEBUG_CHANNEL(d3d);
 
 /* Some private defines, Constant associations, etc.
  * Env bump matrix and per stage constant should be independent,
@@ -343,21 +344,30 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con
 
     /* Pass 2: Generate perturbation calculations */
     for(stage = 0; stage < GL_LIMITS(textures); stage++) {
+        GLuint argmodextra_x, argmodextra_y;
+        struct color_fixup_desc fixup;
+
         if(op[stage].cop == WINED3DTOP_DISABLE) break;
         if(op[stage].cop != WINED3DTOP_BUMPENVMAP &&
            op[stage].cop != WINED3DTOP_BUMPENVMAPLUMINANCE) continue;
 
-        /* Nice thing, we get the color correction for free :-) */
-        if(op[stage].color_correction == WINED3DFMT_V8U8) {
-            argmodextra = GL_2X_BIT_ATI | GL_BIAS_BIT_ATI;
-        } else {
-            argmodextra = 0;
+        if (fixup.x_source != CHANNEL_SOURCE_X || fixup.y_source != CHANNEL_SOURCE_Y)
+        {
+            FIXME("Swizzles not implemented\n");
+            argmodextra_x = GL_NONE;
+            argmodextra_y = GL_NONE;
+        }
+        else
+        {
+            /* Nice thing, we get the color correction for free :-) */
+            argmodextra_x = fixup.x_sign_fixup ? GL_2X_BIT_ATI | GL_BIAS_BIT_ATI : GL_NONE;
+            argmodextra_y = fixup.y_sign_fixup ? GL_2X_BIT_ATI | GL_BIAS_BIT_ATI : GL_NONE;
         }
 
         TRACE("glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_%d_ATI, GL_RED_BIT_ATI, GL_NONE, GL_REG_%d_ATI, GL_NONE, %s, ATI_FFP_CONST_BUMPMAT(%d), GL_NONE, GL_NONE, GL_REG_%d_ATI, GL_RED, GL_NONE)\n",
-              stage + 1, stage, debug_argmod(argmodextra), stage, stage + 1);
+              stage + 1, stage, debug_argmod(argmodextra_x), stage, stage + 1);
         GL_EXTCALL(glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_0_ATI + stage + 1, GL_RED_BIT_ATI, GL_NONE,
-                                         GL_REG_0_ATI + stage, GL_NONE, argmodextra,
+                                         GL_REG_0_ATI + stage, GL_NONE, argmodextra_x,
                                          ATI_FFP_CONST_BUMPMAT(stage), GL_NONE, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
                                          GL_REG_0_ATI + stage + 1, GL_RED, GL_NONE));
 
@@ -376,9 +386,9 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con
         GL_EXTCALL(glColorFragmentOp1ATI(GL_MOV_ATI, GL_REG_5_ATI, GL_GREEN_BIT_ATI, GL_NONE,
                                         ATI_FFP_CONST_BUMPMAT(stage), GL_ALPHA, GL_NONE));
         TRACE("glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_%d_ATI, GL_GREEN_BIT_ATI, GL_NONE, GL_REG_%d_ATI, GL_NONE, %s, GL_REG_5_ATI, GL_NONE, GL_NONE, GL_REG_%d_ATI, GL_GREEN, GL_NONE)\n",
-              stage + 1, stage, debug_argmod(argmodextra), stage + 1);
+              stage + 1, stage, debug_argmod(argmodextra_y), stage + 1);
         GL_EXTCALL(glColorFragmentOp3ATI(GL_DOT2_ADD_ATI, GL_REG_0_ATI + stage + 1, GL_GREEN_BIT_ATI, GL_NONE,
-                                         GL_REG_0_ATI + stage, GL_NONE, argmodextra,
+                                         GL_REG_0_ATI + stage, GL_NONE, argmodextra_y,
                                          GL_REG_5_ATI, GL_NONE, GL_2X_BIT_ATI | GL_BIAS_BIT_ATI,
                                          GL_REG_0_ATI + stage + 1, GL_GREEN, GL_NONE));
     }
@@ -1108,17 +1118,25 @@ static void atifs_free(IWineD3DDevice *iface) {
 }
 #undef GLINFO_LOCATION
 
-static BOOL atifs_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking shader format support for format %s:", debug_d3dformat(fmt));
-    switch(fmt) {
-        case WINED3DFMT_V8U8:
-        case WINED3DFMT_V16U16:
-            TRACE("[OK]\n");
-            return TRUE;
-        default:
-            TRACE("[FAILED\n");
-            return FALSE;
+static BOOL atifs_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
+    }
+
+    /* We only support sign fixup of the first two channels. */
+    if (fixup.x_source == CHANNEL_SOURCE_X && fixup.y_source == CHANNEL_SOURCE_Y
+            && fixup.z_source == CHANNEL_SOURCE_Z && fixup.w_source == CHANNEL_SOURCE_W
+            && !fixup.z_sign_fixup && !fixup.w_sign_fixup)
+    {
+        TRACE("[OK]\n");
+        return TRUE;
     }
+
+    TRACE("[FAILED]\n");
+    return FALSE;
 }
 
 const struct fragment_pipeline atifs_fragment_pipeline = {
@@ -1126,7 +1144,7 @@ const struct fragment_pipeline atifs_fragment_pipeline = {
     atifs_get_caps,
     atifs_alloc,
     atifs_free,
-    atifs_conv_supported,
+    atifs_color_fixup_supported,
     atifs_fragmentstate_template,
     TRUE /* We can disable projected textures */
 };
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index c9f9124..1c7c565 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -29,6 +29,7 @@
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
+WINE_DECLARE_DEBUG_CHANNEL(d3d);
 
 #define GLNAME_REQUIRE_GLSL  ((const char *)1)
 
@@ -768,6 +769,67 @@ static void shader_dump_param(IWineD3DBaseShader *iface, const DWORD param, cons
     }
 }
 
+static void shader_color_correction(IWineD3DBaseShaderImpl *shader,
+        IWineD3DDeviceImpl *device, const struct SHADER_OPCODE_ARG *arg)
+{
+    DWORD hex_version = shader->baseShader.hex_version;
+    IWineD3DBaseTextureImpl *texture;
+    struct color_fixup_desc fixup;
+    BOOL recorded = FALSE;
+    DWORD sampler_idx;
+    UINT i;
+
+    switch(arg->opcode->opcode)
+    {
+        case WINED3DSIO_TEX:
+            if (hex_version < WINED3DPS_VERSION(2,0)) sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
+            else sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK;
+            break;
+
+        case WINED3DSIO_TEXLDL:
+            FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n");
+            return;
+
+        case WINED3DSIO_TEXDP3TEX:
+        case WINED3DSIO_TEXM3x3TEX:
+        case WINED3DSIO_TEXM3x3SPEC:
+        case WINED3DSIO_TEXM3x3VSPEC:
+        case WINED3DSIO_TEXBEM:
+        case WINED3DSIO_TEXREG2AR:
+        case WINED3DSIO_TEXREG2GB:
+        case WINED3DSIO_TEXREG2RGB:
+            sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
+            break;
+
+        default:
+            /* Not a texture sampling instruction, nothing to do */
+            return;
+    };
+
+    texture = (IWineD3DBaseTextureImpl *)device->stateBlock->textures[sampler_idx];
+    if (texture) fixup = texture->baseTexture.shader_color_fixup;
+    else fixup = COLOR_FIXUP_IDENTITY;
+
+    /* before doing anything, record the sampler with the format in the format conversion list,
+     * but check if it's not there already */
+    for (i = 0; i < shader->baseShader.num_sampled_samplers; ++i)
+    {
+        if (shader->baseShader.sampled_samplers[i] == sampler_idx)
+        {
+            recorded = TRUE;
+            break;
+        }
+    }
+
+    if (!recorded)
+    {
+        shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx;
+        ++shader->baseShader.num_sampled_samplers;
+    }
+
+    device->shader_backend->shader_color_correction(arg, fixup);
+}
+
 /** Shared code in order to generate the bulk of the shader string.
     Use the shader_header_fct & shader_footer_fct to add strings
     that are specific to pixel or vertex functions
@@ -866,7 +928,7 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER* buffer,
                 hw_fct(&hw_arg);
 
                 /* Add color correction if needed */
-                device->shader_backend->shader_color_correction(&hw_arg);
+                shader_color_correction(This, device, &hw_arg);
 
                 /* Process instruction modifiers for GLSL apps ( _sat, etc. ) */
                 /* FIXME: This should be internal to the shader backend.
@@ -1083,7 +1145,7 @@ static void shader_none_select_depth_blt(IWineD3DDevice *iface, enum tex_types t
 static void shader_none_deselect_depth_blt(IWineD3DDevice *iface) {}
 static void shader_none_load_constants(IWineD3DDevice *iface, char usePS, char useVS) {}
 static void shader_none_cleanup(IWineD3DDevice *iface) {}
-static void shader_none_color_correction(const SHADER_OPCODE_ARG *arg) {}
+static void shader_none_color_correction(const struct SHADER_OPCODE_ARG *arg, struct color_fixup_desc fixup) {}
 static void shader_none_destroy(IWineD3DBaseShader *iface) {}
 static HRESULT shader_none_alloc(IWineD3DDevice *iface) {return WINED3D_OK;}
 static void shader_none_free(IWineD3DDevice *iface) {}
@@ -1105,21 +1167,23 @@ static void shader_none_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *
     pCaps->PixelShader1xMaxValue = 0.0;
 }
 #undef GLINFO_LOCATION
-static BOOL shader_none_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking shader format support for format %s", debug_d3dformat(fmt));
-    switch(fmt) {
-        /* Faked to make some apps happy. */
-        case WINED3DFMT_V8U8:
-        case WINED3DFMT_V16U16:
-        case WINED3DFMT_L6V5U5:
-        case WINED3DFMT_X8L8V8U8:
-        case WINED3DFMT_Q8W8V8U8:
-            TRACE("[OK]\n");
-            return TRUE;
-        default:
-            TRACE("[FAILED]\n");
-            return FALSE;
+static BOOL shader_none_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
     }
+
+    /* Faked to make some apps happy. */
+    if (!is_yuv_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    TRACE("[FAILED]\n");
+    return FALSE;
 }
 
 const shader_backend_t none_shader_backend = {
@@ -1137,7 +1201,7 @@ const shader_backend_t none_shader_backend = {
     shader_none_generate_pshader,
     shader_none_generate_vshader,
     shader_none_get_caps,
-    shader_none_conv_supported
+    shader_none_color_fixup_supported,
 };
 
 /* *******************************************
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index b4c82ac..836ad3b 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -891,7 +891,7 @@ static HRESULT  WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, U
         tmpW = max(1, tmpW >> 1);
         tmpH = max(1, tmpH >> 1);
     }
-    object->baseTexture.shader_conversion_group = glDesc->conversion_group;
+    object->baseTexture.shader_color_fixup = glDesc->color_fixup;
 
     TRACE("(%p) : Created  texture %p\n", This, object);
     return WINED3D_OK;
@@ -998,7 +998,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *ifa
         tmpH = max(1, tmpH >> 1);
         tmpD = max(1, tmpD >> 1);
     }
-    object->baseTexture.shader_conversion_group = glDesc->conversion_group;
+    object->baseTexture.shader_color_fixup = glDesc->color_fixup;
 
     *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
     TRACE("(%p) : Created volume texture %p\n", This, object);
@@ -1168,7 +1168,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface
         }
         tmpW = max(1, tmpW >> 1);
     }
-    object->baseTexture.shader_conversion_group = glDesc->conversion_group;
+    object->baseTexture.shader_color_fixup = glDesc->color_fixup;
 
     TRACE("(%p) : Created Cube Texture %p\n", This, object);
     *ppCubeTexture = (IWineD3DCubeTexture *) object;
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index d9b1c9d..cb66128 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -1994,24 +1994,18 @@ static BOOL CheckBumpMapCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINE
         case WINED3DFMT_L6V5U5:
         case WINED3DFMT_X8L8V8U8:
         case WINED3DFMT_Q8W8V8U8:
+            /* Ask the fixed function pipeline implementation if it can deal
+             * with the conversion. If we've got a GL extension giving native
+             * support this will be an identity conversion. */
             getFormatDescEntry(CheckFormat, &GLINFO_LOCATION, &glDesc);
-            if(glDesc->conversion_group == WINED3DFMT_UNKNOWN) {
-                /* We have a GL extension giving native support */
-                TRACE_(d3d_caps)("[OK]\n");
-                return TRUE;
-            }
-
-            /* No native support: Ask the fixed function pipeline implementation if it
-             * can deal with the conversion
-             */
             fp = select_fragment_implementation(Adapter, DeviceType);
-            if(fp->conv_supported(CheckFormat)) {
+            if (fp->color_fixup_supported(glDesc->color_fixup))
+            {
                 TRACE_(d3d_caps)("[OK]\n");
                 return TRUE;
-            } else {
-                TRACE_(d3d_caps)("[FAILED]\n");
-                return FALSE;
             }
+            TRACE_(d3d_caps)("[FAILED]\n");
+            return FALSE;
 
         default:
             TRACE_(d3d_caps)("[FAILED]\n");
@@ -2281,25 +2275,18 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINE
         case WINED3DFMT_L6V5U5:
         case WINED3DFMT_Q8W8V8U8:
         case WINED3DFMT_V16U16:
-        case WINED3DFMT_W11V11U10:
+            /* Ask the shader backend if it can deal with the conversion. If
+             * we've got a GL extension giving native support this will be an
+             * identity conversion. */
             getFormatDescEntry(CheckFormat, &GLINFO_LOCATION, &glDesc);
-            if(glDesc->conversion_group == WINED3DFMT_UNKNOWN) {
-                /* We have a GL extension giving native support */
-                TRACE_(d3d_caps)("[OK]\n");
-                return TRUE;
-            }
-
-            /* No native support: Ask the fixed function pipeline implementation if it
-             * can deal with the conversion
-             */
             shader_backend = select_shader_backend(Adapter, DeviceType);
-            if(shader_backend->shader_conv_supported(CheckFormat)) {
+            if (shader_backend->shader_color_fixup_supported(glDesc->color_fixup))
+            {
                 TRACE_(d3d_caps)("[OK]\n");
                 return TRUE;
-            } else {
-                TRACE_(d3d_caps)("[FAILED]\n");
-                return FALSE;
             }
+            TRACE_(d3d_caps)("[FAILED]\n");
+            return FALSE;
 
         case WINED3DFMT_DXT1:
         case WINED3DFMT_DXT2:
@@ -2322,6 +2309,7 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINE
         case WINED3DFMT_INDEX32:
         case WINED3DFMT_Q16W16V16U16:
         case WINED3DFMT_A2W10V10U10:
+        case WINED3DFMT_W11V11U10:
             TRACE_(d3d_caps)("[FAILED]\n"); /* Enable when implemented */
             return FALSE;
 
@@ -2404,10 +2392,12 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINE
         /* Vendor specific formats */
         case WINED3DFMT_ATI2N:
             if(GL_SUPPORT(ATI_TEXTURE_COMPRESSION_3DC) || GL_SUPPORT(EXT_TEXTURE_COMPRESSION_RGTC)) {
+                getFormatDescEntry(CheckFormat, &GLINFO_LOCATION, &glDesc);
                 shader_backend = select_shader_backend(Adapter, DeviceType);
                 fp = select_fragment_implementation(Adapter, DeviceType);
-                if(shader_backend->shader_conv_supported(CheckFormat) &&
-                   fp->conv_supported(CheckFormat)) {
+                if (shader_backend->shader_color_fixup_supported(glDesc->color_fixup)
+                        && fp->color_fixup_supported(glDesc->color_fixup))
+                {
                     TRACE_(d3d_caps)("[OK]\n");
                     return TRUE;
                 }
@@ -2440,6 +2430,7 @@ static BOOL CheckTextureCapability(UINT Adapter, WINED3DDEVTYPE DeviceType, WINE
 }
 
 static BOOL CheckSurfaceCapability(UINT Adapter, WINED3DFORMAT AdapterFormat, WINED3DDEVTYPE DeviceType, WINED3DFORMAT CheckFormat, WINED3DSURFTYPE SurfaceType) {
+    const struct GlPixelFormatDesc *format_desc;
     const struct blit_shader *blitter;
 
     if(SurfaceType == SURFACE_GDI) {
@@ -2476,8 +2467,10 @@ static BOOL CheckSurfaceCapability(UINT Adapter, WINED3DFORMAT AdapterFormat, WI
     if(CheckDepthStencilCapability(Adapter, AdapterFormat, CheckFormat)) return TRUE;
 
     /* If opengl can't process the format natively, the blitter may be able to convert it */
+    getFormatDescEntry(CheckFormat, &GLINFO_LOCATION, &format_desc);
     blitter = select_blit_implementation(Adapter, DeviceType);
-    if(blitter->conv_supported(CheckFormat)) {
+    if (blitter->color_fixup_supported(format_desc->color_fixup))
+    {
         TRACE_(d3d_caps)("[OK]\n");
         return TRUE;
     }
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index 11f48ed..f8c5869 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -35,6 +35,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_shader);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_constants);
 WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
+WINE_DECLARE_DEBUG_CHANNEL(d3d);
 
 #define GLINFO_LOCATION      (*gl_info)
 
@@ -1162,197 +1163,111 @@ static void shader_glsl_get_sample_function(DWORD sampler_type, BOOL projected,
     }
 }
 
-static void shader_glsl_color_correction(const SHADER_OPCODE_ARG *arg)
+static void shader_glsl_append_fixup_arg(char *arguments, const char *reg_name,
+        BOOL sign_fixup, enum fixup_channel_source channel_source)
 {
-    IWineD3DBaseShaderImpl* shader = (IWineD3DBaseShaderImpl*) arg->shader;
-    IWineD3DDeviceImpl* deviceImpl = (IWineD3DDeviceImpl*) shader->baseShader.device;
-    const WineD3D_GL_Info *gl_info = &deviceImpl->adapter->gl_info;
-    glsl_dst_param_t dst_param;
-    glsl_dst_param_t dst_param2;
-    WINED3DFORMAT fmt;
-    WINED3DFORMAT conversion_group;
-    IWineD3DBaseTextureImpl *texture;
-    DWORD mask, mask_size;
-    UINT i;
-    BOOL recorded = FALSE;
-    DWORD sampler_idx;
-    DWORD hex_version = shader->baseShader.hex_version;
-
-    switch(arg->opcode->opcode) {
-        case WINED3DSIO_TEX:
-            if (hex_version < WINED3DPS_VERSION(2,0)) {
-                sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
-            } else {
-                sampler_idx = arg->src[1] & WINED3DSP_REGNUM_MASK;
-            }
+    switch(channel_source)
+    {
+        case CHANNEL_SOURCE_ZERO:
+            strcat(arguments, "0.0");
             break;
 
-        case WINED3DSIO_TEXLDL:
-            FIXME("Add color fixup for vertex texture WINED3DSIO_TEXLDL\n");
-            return;
-
-        case WINED3DSIO_TEXDP3TEX:
-        case WINED3DSIO_TEXM3x3TEX:
-        case WINED3DSIO_TEXM3x3SPEC:
-        case WINED3DSIO_TEXM3x3VSPEC:
-        case WINED3DSIO_TEXBEM:
-        case WINED3DSIO_TEXREG2AR:
-        case WINED3DSIO_TEXREG2GB:
-        case WINED3DSIO_TEXREG2RGB:
-            sampler_idx = arg->dst & WINED3DSP_REGNUM_MASK;
+        case CHANNEL_SOURCE_ONE:
+            strcat(arguments, "1.0");
             break;
 
-        default:
-            /* Not a texture sampling instruction, nothing to do */
-            return;
-    };
-
-    texture = (IWineD3DBaseTextureImpl *) deviceImpl->stateBlock->textures[sampler_idx];
-    if(texture) {
-        fmt = texture->resource.format;
-        conversion_group = texture->baseTexture.shader_conversion_group;
-    } else {
-        fmt = WINED3DFMT_UNKNOWN;
-        conversion_group = WINED3DFMT_UNKNOWN;
-    }
-
-    /* before doing anything, record the sampler with the format in the format conversion list,
-     * but check if it's not there already
-     */
-    for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) {
-        if(shader->baseShader.sampled_samplers[i] == sampler_idx) {
-            recorded = TRUE;
+        case CHANNEL_SOURCE_X:
+            strcat(arguments, reg_name);
+            strcat(arguments, ".x");
             break;
-        }
-    }
-    if(!recorded) {
-        shader->baseShader.sampled_samplers[shader->baseShader.num_sampled_samplers] = sampler_idx;
-        shader->baseShader.num_sampled_samplers++;
-    }
 
-    switch(fmt) {
-        case WINED3DFMT_V8U8:
-        case WINED3DFMT_V16U16:
-            if(GL_SUPPORT(NV_TEXTURE_SHADER) && fmt == WINED3DFMT_V8U8) {
-                /* The 3rd channel returns 1.0 in d3d, but 0.0 in gl. Fix this while we're at it :-) */
-                mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_2, &dst_param);
-                mask_size = shader_glsl_get_write_mask_size(mask);
-                if(mask_size >= 3) {
-                    shader_addline(arg->buffer, "%s.%c = 1.0;\n", dst_param.reg_name, dst_param.mask_str[3]);
-                }
-            } else {
-                /* Correct the sign, but leave the blue as it is - it was loaded correctly already */
-                mask = shader_glsl_add_dst_param(arg, arg->dst,
-                                          WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1,
-                                          &dst_param);
-                mask_size = shader_glsl_get_write_mask_size(mask);
-                if(mask_size >= 2) {
-                    shader_addline(arg->buffer, "%s.%c%c = %s.%c%c * 2.0 - 1.0;\n",
-                    dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2],
-                    dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2]);
-                } else if(mask_size == 1) {
-                    shader_addline(arg->buffer, "%s.%c = %s.%c * 2.0 - 1.0;\n", dst_param.reg_name, dst_param.mask_str[1],
-                    dst_param.reg_name, dst_param.mask_str[1]);
-                }
-            }
+        case CHANNEL_SOURCE_Y:
+            strcat(arguments, reg_name);
+            strcat(arguments, ".y");
             break;
 
-        case WINED3DFMT_X8L8V8U8:
-            if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
-                /* Red and blue are the signed channels, fix them up; Blue(=L) is correct already,
-                 * and a(X) is always 1.0
-                 */
-                mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &dst_param);
-                mask_size = shader_glsl_get_write_mask_size(mask);
-                if(mask_size >= 2) {
-                    shader_addline(arg->buffer, "%s.%c%c = %s.%c%c * 2.0 - 1.0;\n",
-                                   dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2],
-                                   dst_param.reg_name, dst_param.mask_str[1], dst_param.mask_str[2]);
-                } else if(mask_size == 1) {
-                    shader_addline(arg->buffer, "%s.%c = %s.%c * 2.0 - 1.0;\n",
-                                   dst_param.reg_name, dst_param.mask_str[1],
-                                   dst_param.reg_name, dst_param.mask_str[1]);
-                }
-            }
+        case CHANNEL_SOURCE_Z:
+            strcat(arguments, reg_name);
+            strcat(arguments, ".z");
             break;
 
-        case WINED3DFMT_L6V5U5:
-            if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
-                mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &dst_param);
-                mask_size = shader_glsl_get_write_mask_size(mask);
-                shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_2, &dst_param2);
-                if(mask_size >= 3) {
-                    /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */
-                    shader_addline(arg->buffer, "tmp0.g = %s.%c;\n",
-                                   dst_param.reg_name, dst_param.mask_str[2]);
-                    shader_addline(arg->buffer, "%s.%c%c = %s.%c%c * 2.0 - 1.0;\n",
-                                   dst_param.reg_name, dst_param.mask_str[2], dst_param.mask_str[1],
-                                   dst_param2.reg_name, dst_param.mask_str[1], dst_param.mask_str[3]);
-                    shader_addline(arg->buffer, "%s.%c = tmp0.g;\n", dst_param.reg_name,
-                                   dst_param.mask_str[3]);
-                } else if(mask_size == 2) {
-                    /* This is bad: We have VL, but we need VU */
-                    FIXME("2 components sampled from a converted L6V5U5 texture\n");
-                } else {
-                    shader_addline(arg->buffer, "%s.%c = %s.%c * 2.0 - 1.0;\n",
-                                   dst_param.reg_name, dst_param.mask_str[1],
-                                   dst_param2.reg_name, dst_param.mask_str[1]);
-                }
-            }
+        case CHANNEL_SOURCE_W:
+            strcat(arguments, reg_name);
+            strcat(arguments, ".w");
             break;
 
-        case WINED3DFMT_Q8W8V8U8:
-            if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
-                /* Correct the sign in all channels. The writemask just applies as-is, no
-                 * need for checking the mask size
-                 */
-                shader_glsl_add_dst_param(arg, arg->dst,
-                                          WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1 |
-                                          WINED3DSP_WRITEMASK_2 | WINED3DSP_WRITEMASK_3,
-                                          &dst_param);
-                shader_addline(arg->buffer, "%s%s = %s%s * 2.0 - 1.0;\n", dst_param.reg_name, dst_param.mask_str,
-                               dst_param.reg_name, dst_param.mask_str);
-            }
+        default:
+            FIXME("Unhandled channel source %#x\n", channel_source);
+            strcat(arguments, "undefined");
             break;
+    }
 
-        case WINED3DFMT_ATI2N:
-            /* GL_ATI_texture_compression_3dc returns the two channels as luminance-alpha,
-             * which means the first one is replicated across .rgb, and the 2nd one is in
-             * .a. We need the 2nd in .g
-             *
-             * GL_EXT_texture_compression_rgtc returns the values in .rg, however, they
-             * are swapped compared to d3d. So swap red and green.
-             */
-            mask = shader_glsl_add_dst_param(arg, arg->dst, WINED3DSP_WRITEMASK_0 | WINED3DSP_WRITEMASK_1, &dst_param);
-            mask_size = shader_glsl_get_write_mask_size(mask);
-            if(GL_SUPPORT(EXT_TEXTURE_COMPRESSION_RGTC)) {
-                if(mask_size >= 2) {
-                    shader_addline(arg->buffer, "%s.%c%c = %s.%c%c;\n",
-                                dst_param.reg_name, dst_param.mask_str[1],
-                                                    dst_param.mask_str[2],
-                                dst_param.reg_name, dst_param.mask_str[2],
-                                                    dst_param.mask_str[1]);
-                } else {
-                    FIXME("%u components sampled from a converted ATI2N texture\n", mask_size);
-                }
-            } else {
-                if(mask_size == 4) {
-                    /* Swap y and z (U and L), and do a sign conversion on x and the new y(V and U) */
-                    shader_addline(arg->buffer, "%s.%c = %s.%c;\n",
-                                dst_param.reg_name, dst_param.mask_str[2],
-                                dst_param.reg_name, dst_param.mask_str[4]);
-                } else if(mask_size == 1) {
-                    /* Nothing to do */
-                } else {
-                    FIXME("%u components sampled from a converted ATI2N texture\n", mask_size);
-                    /* This is bad: We have .r[gb], but we need .ra */
-                }
-            }
-            break;
+    if (sign_fixup) strcat(arguments, " * 2.0 - 1.0");
+}
 
-            /* stupid compiler */
-        default:
-            break;
+static void shader_glsl_color_correction(const struct SHADER_OPCODE_ARG *arg, struct color_fixup_desc fixup)
+{
+    unsigned int mask_size, remaining;
+    glsl_dst_param_t dst_param;
+    char arguments[256];
+    DWORD mask;
+    BOOL dummy;
+
+    mask = 0;
+    if (fixup.x_sign_fixup || fixup.x_source != CHANNEL_SOURCE_X) mask |= WINED3DSP_WRITEMASK_0;
+    if (fixup.y_sign_fixup || fixup.y_source != CHANNEL_SOURCE_Y) mask |= WINED3DSP_WRITEMASK_1;
+    if (fixup.z_sign_fixup || fixup.z_source != CHANNEL_SOURCE_Z) mask |= WINED3DSP_WRITEMASK_2;
+    if (fixup.w_sign_fixup || fixup.w_source != CHANNEL_SOURCE_W) mask |= WINED3DSP_WRITEMASK_3;
+    mask &= arg->dst;
+
+    if (!mask) return; /* Nothing to do */
+
+    if (is_yuv_fixup(fixup))
+    {
+        enum yuv_fixup yuv_fixup = get_yuv_fixup(fixup);
+        FIXME("YUV fixup (%#x) not supported\n", yuv_fixup);
+        return;
+    }
+
+    mask_size = shader_glsl_get_write_mask_size(mask);
+
+    dst_param.mask_str[0] = '\0';
+    shader_glsl_get_write_mask(mask, dst_param.mask_str);
+
+    dst_param.reg_name[0] = '\0';
+    shader_glsl_get_register_name(arg->dst, arg->dst_addr, dst_param.reg_name, &dummy, arg);
+
+    arguments[0] = '\0';
+    remaining = mask_size;
+    if (mask & WINED3DSP_WRITEMASK_0)
+    {
+        shader_glsl_append_fixup_arg(arguments, dst_param.reg_name, fixup.x_sign_fixup, fixup.x_source);
+        if (--remaining) strcat(arguments, ", ");
+    }
+    if (mask & WINED3DSP_WRITEMASK_1)
+    {
+        shader_glsl_append_fixup_arg(arguments, dst_param.reg_name, fixup.y_sign_fixup, fixup.y_source);
+        if (--remaining) strcat(arguments, ", ");
+    }
+    if (mask & WINED3DSP_WRITEMASK_2)
+    {
+        shader_glsl_append_fixup_arg(arguments, dst_param.reg_name, fixup.z_sign_fixup, fixup.z_source);
+        if (--remaining) strcat(arguments, ", ");
+    }
+    if (mask & WINED3DSP_WRITEMASK_3)
+    {
+        shader_glsl_append_fixup_arg(arguments, dst_param.reg_name, fixup.w_sign_fixup, fixup.w_source);
+        if (--remaining) strcat(arguments, ", ");
+    }
+
+    if (mask_size > 1)
+    {
+        shader_addline(arg->buffer, "%s%s = vec%u(%s);\n",
+                dst_param.reg_name, dst_param.mask_str, mask_size, arguments);
+    }
+    else
+    {
+        shader_addline(arg->buffer, "%s%s = %s;\n", dst_param.reg_name, dst_param.mask_str, arguments);
     }
 }
 
@@ -3834,21 +3749,23 @@ static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *
     TRACE_(d3d_caps)("Hardware pixel shader version %d.%d enabled (GLSL)\n", (pCaps->PixelShaderVersion >> 8) & 0xff, pCaps->PixelShaderVersion & 0xff);
 }
 
-static BOOL shader_glsl_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking shader format support for format %s:", debug_d3dformat(fmt));
-    switch(fmt) {
-        case WINED3DFMT_V8U8:
-        case WINED3DFMT_V16U16:
-        case WINED3DFMT_X8L8V8U8:
-        case WINED3DFMT_L6V5U5:
-        case WINED3DFMT_Q8W8V8U8:
-        case WINED3DFMT_ATI2N:
-            TRACE("[OK]\n");
-            return TRUE;
-        default:
-            TRACE("[FAILED\n");
-            return FALSE;
+static BOOL shader_glsl_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d_shader) && TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
     }
+
+    /* We support everything except YUV conversions. */
+    if (!is_yuv_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    TRACE("[FAILED]\n");
+    return FALSE;
 }
 
 static const SHADER_HANDLER shader_glsl_instruction_handler_table[WINED3DSIH_TABLE_SIZE] =
@@ -3953,5 +3870,5 @@ const shader_backend_t glsl_shader_backend = {
     shader_glsl_generate_pshader,
     shader_glsl_generate_vshader,
     shader_glsl_get_caps,
-    shader_glsl_conv_supported,
+    shader_glsl_color_fixup_supported,
 };
diff --git a/dlls/wined3d/nvidia_texture_shader.c b/dlls/wined3d/nvidia_texture_shader.c
index c0194d6..77f5365 100644
--- a/dlls/wined3d/nvidia_texture_shader.c
+++ b/dlls/wined3d/nvidia_texture_shader.c
@@ -673,8 +673,22 @@ static void nvrc_fragment_free(IWineD3DDevice *iface) {}
  * register combiners extension(Pre-GF3).
  */
 
-static BOOL nvts_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking shader format support for format %s: [FAILED]\n", debug_d3dformat(fmt));
+static BOOL nvts_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
+    }
+
+    /* We only support identity conversions. */
+    if (is_identity_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    TRACE("[FAILED]\n");
     return FALSE;
 }
 
@@ -810,7 +824,7 @@ const struct fragment_pipeline nvts_fragment_pipeline = {
     nvrc_fragment_get_caps,
     nvrc_fragment_alloc,
     nvrc_fragment_free,
-    nvts_conv_supported,
+    nvts_color_fixup_supported,
     nvrc_fragmentstate_template,
     FALSE /* we cannot disable projected textures. The vertex pipe has to do it */
 };
@@ -820,7 +834,7 @@ const struct fragment_pipeline nvrc_fragment_pipeline = {
     nvrc_fragment_get_caps,
     nvrc_fragment_alloc,
     nvrc_fragment_free,
-    nvts_conv_supported,
+    nvts_color_fixup_supported,
     nvrc_fragmentstate_template,
     FALSE /* we cannot disable projected textures. The vertex pipe has to do it */
 };
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 153e72d..0557d86 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -435,15 +435,15 @@ void find_ps_compile_args(IWineD3DPixelShaderImpl *shader, IWineD3DStateBlockImp
 
     args->srgb_correction = stateblock->renderState[WINED3DRS_SRGBWRITEENABLE] ? 1 : 0;
 
-    memset(args->format_conversion, 0, sizeof(args->format_conversion));
+    memset(args->color_fixup, 0, sizeof(args->color_fixup));
     for(i = 0; i < shader->baseShader.num_sampled_samplers; i++) {
         sampler = shader->baseShader.sampled_samplers[i];
         tex = (IWineD3DBaseTextureImpl *) stateblock->textures[sampler];
         if(!tex) {
-            args->format_conversion[sampler] = WINED3DFMT_UNKNOWN;
+            args->color_fixup[sampler] = COLOR_FIXUP_IDENTITY;
             continue;
         }
-        args->format_conversion[sampler] = tex->baseTexture.shader_conversion_group;
+        args->color_fixup[sampler] = tex->baseTexture.shader_color_fixup;
     }
     if(shader->baseShader.hex_version >= WINED3DPS_VERSION(3,0)) {
         if(((IWineD3DDeviceImpl *) shader->baseShader.device)->strided_streams.u.s.position_transformed) {
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index aa2795d..2b02481 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -5471,8 +5471,22 @@ static void ffp_fragment_get_caps(WINED3DDEVTYPE devtype, const WineD3D_GL_Info
 
 static HRESULT ffp_fragment_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
 static void ffp_fragment_free(IWineD3DDevice *iface) {}
-static BOOL ffp_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking shader format support for format %s: [FAILED]\n", debug_d3dformat(fmt));
+static BOOL ffp_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
+    }
+
+    /* We only support identity conversions. */
+    if (is_identity_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    TRACE("[FAILED]\n");
     return FALSE;
 }
 
@@ -5481,7 +5495,7 @@ const struct fragment_pipeline ffp_fragment_pipeline = {
     ffp_fragment_get_caps,
     ffp_fragment_alloc,
     ffp_fragment_free,
-    ffp_conv_supported,
+    ffp_color_fixup_supported,
     ffp_fragmentstate_template,
     FALSE /* we cannot disable projected textures. The vertex pipe has to do it */
 };
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 12c1516..b34ab49 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -31,6 +31,7 @@
 #include "wined3d_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
+WINE_DECLARE_DEBUG_CHANNEL(d3d);
 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
 
 static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey);
@@ -4847,8 +4848,22 @@ static void ffp_blit_unset(IWineD3DDevice *iface) {
     }
 }
 
-static BOOL ffp_blit_conv_supported(WINED3DFORMAT fmt) {
-    TRACE("Checking blit format support for format %s: [FAILED]\n", debug_d3dformat(fmt));
+static BOOL ffp_blit_color_fixup_supported(struct color_fixup_desc fixup)
+{
+    if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
+    {
+        TRACE("Checking support for fixup:\n");
+        dump_color_fixup_desc(fixup);
+    }
+
+    /* We only support identity conversions. */
+    if (is_identity_fixup(fixup))
+    {
+        TRACE("[OK]\n");
+        return TRUE;
+    }
+
+    TRACE("[FAILED]\n");
     return FALSE;
 }
 
@@ -4857,5 +4872,5 @@ const struct blit_shader ffp_blit =  {
     ffp_blit_free,
     ffp_blit_set,
     ffp_blit_unset,
-    ffp_blit_conv_supported
+    ffp_blit_color_fixup_supported
 };
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index c6a1ad4..cd7ff06 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -318,7 +318,7 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info)
         gl_info->gl_formats[dst].glGammaInternal = gl_formats_template[src].glGammaInternal;
         gl_info->gl_formats[dst].glFormat        = gl_formats_template[src].glFormat;
         gl_info->gl_formats[dst].glType          = gl_formats_template[src].glType;
-        gl_info->gl_formats[dst].conversion_group= WINED3DFMT_UNKNOWN;
+        gl_info->gl_formats[dst].color_fixup     = COLOR_FIXUP_IDENTITY;
         gl_info->gl_formats[dst].Flags           = gl_formats_template[src].Flags;
         gl_info->gl_formats[dst].heightscale     = 1.0;
 
@@ -372,21 +372,38 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info)
      * returns 0.0 when sampling from it, DirectX 1.0. So we always have in-shader
      * conversion for this format.
      */
-    dst = getFmtIdx(WINED3DFMT_V8U8);
-    gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8;
-    dst = getFmtIdx(WINED3DFMT_V16U16);
-    gl_info->gl_formats[dst].conversion_group = WINED3DFMT_V8U8;
+    if (!GL_SUPPORT(NV_TEXTURE_SHADER))
+    {
+        dst = getFmtIdx(WINED3DFMT_V8U8);
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                1, CHANNEL_SOURCE_X, 1, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_ONE, 0, CHANNEL_SOURCE_ONE);
+        dst = getFmtIdx(WINED3DFMT_V16U16);
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                1, CHANNEL_SOURCE_X, 1, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_ONE, 0, CHANNEL_SOURCE_ONE);
+    }
+    else
+    {
+        dst = getFmtIdx(WINED3DFMT_V8U8);
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_ONE, 0, CHANNEL_SOURCE_ONE);
+        dst = getFmtIdx(WINED3DFMT_V16U16);
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_ONE, 0, CHANNEL_SOURCE_ONE);
+    }
 
     if(!GL_SUPPORT(NV_TEXTURE_SHADER)) {
         /* If GL_NV_texture_shader is not supported, those formats are converted, incompatibly
          * with each other
          */
         dst = getFmtIdx(WINED3DFMT_L6V5U5);
-        gl_info->gl_formats[dst].conversion_group = WINED3DFMT_L6V5U5;
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                1, CHANNEL_SOURCE_X, 1, CHANNEL_SOURCE_Z, 0, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_ONE);
         dst = getFmtIdx(WINED3DFMT_X8L8V8U8);
-        gl_info->gl_formats[dst].conversion_group = WINED3DFMT_X8L8V8U8;
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                1, CHANNEL_SOURCE_X, 1, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_Z, 0, CHANNEL_SOURCE_W);
         dst = getFmtIdx(WINED3DFMT_Q8W8V8U8);
-        gl_info->gl_formats[dst].conversion_group = WINED3DFMT_Q8W8V8U8;
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                1, CHANNEL_SOURCE_X, 1, CHANNEL_SOURCE_Y, 1, CHANNEL_SOURCE_Z, 1, CHANNEL_SOURCE_W);
     } else {
         /* If GL_NV_texture_shader is supported, WINED3DFMT_L6V5U5 and WINED3DFMT_X8L8V8U8
          * are converted at surface loading time, but they do not need any modification in
@@ -399,12 +416,14 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info)
         dst = getFmtIdx(WINED3DFMT_ATI2N);
         gl_info->gl_formats[dst].glInternal = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
         gl_info->gl_formats[dst].glGammaInternal = GL_COMPRESSED_RED_GREEN_RGTC2_EXT;
-        gl_info->gl_formats[dst].conversion_group= WINED3DFMT_ATI2N;
+        gl_info->gl_formats[dst].color_fixup = create_color_fixup_desc(
+                0, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_ONE, 0, CHANNEL_SOURCE_ONE);
     } else if(GL_SUPPORT(ATI_TEXTURE_COMPRESSION_3DC)) {
         dst = getFmtIdx(WINED3DFMT_ATI2N);
         gl_info->gl_formats[dst].glInternal = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
         gl_info->gl_formats[dst].glGammaInternal = GL_COMPRESSED_LUMINANCE_ALPHA_3DC_ATI;
-        gl_info->gl_formats[dst].conversion_group= WINED3DFMT_ATI2N;
+        gl_info->gl_formats[dst].color_fixup= create_color_fixup_desc(
+                0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_W, 0, CHANNEL_SOURCE_ONE, 0, CHANNEL_SOURCE_ONE);
     }
 
     if(!GL_SUPPORT(APPLE_YCBCR_422)) {
@@ -413,19 +432,19 @@ BOOL initPixelFormats(WineD3D_GL_Info *gl_info)
         gl_info->gl_formats[dst].glGammaInternal = GL_LUMINANCE_ALPHA; /* not srgb */
         gl_info->gl_formats[dst].glFormat = GL_LUMINANCE_ALPHA;
         gl_info->gl_formats[dst].glType = GL_UNSIGNED_BYTE;
-        gl_info->gl_formats[dst].conversion_group = WINED3DFMT_YUY2;
+        gl_info->gl_formats[dst].color_fixup = create_yuv_fixup_desc(YUV_FIXUP_YUY2);
 
         dst = getFmtIdx(WINED3DFMT_UYVY);
         gl_info->gl_formats[dst].glInternal = GL_LUMINANCE_ALPHA;
         gl_info->gl_formats[dst].glGammaInternal = GL_LUMINANCE_ALPHA; /* not srgb */
         gl_info->gl_formats[dst].glFormat = GL_LUMINANCE_ALPHA;
         gl_info->gl_formats[dst].glType = GL_UNSIGNED_BYTE;
-        gl_info->gl_formats[dst].conversion_group = WINED3DFMT_UYVY;
+        gl_info->gl_formats[dst].color_fixup = create_yuv_fixup_desc(YUV_FIXUP_UYVY);
     }
 
     dst = getFmtIdx(WINED3DFMT_YV12);
     gl_info->gl_formats[dst].heightscale = 1.5;
-    gl_info->gl_formats[dst].conversion_group = WINED3DFMT_YV12;
+    gl_info->gl_formats[dst].color_fixup = create_yuv_fixup_desc(YUV_FIXUP_YV12);
 
     return TRUE;
 }
@@ -1115,6 +1134,55 @@ const char *debug_d3ddegree(WINED3DDEGREETYPE degree) {
     }
 }
 
+const char *debug_fixup_channel_source(enum fixup_channel_source source)
+{
+    switch(source)
+    {
+#define WINED3D_TO_STR(x) case x: return #x
+        WINED3D_TO_STR(CHANNEL_SOURCE_ZERO);
+        WINED3D_TO_STR(CHANNEL_SOURCE_ONE);
+        WINED3D_TO_STR(CHANNEL_SOURCE_X);
+        WINED3D_TO_STR(CHANNEL_SOURCE_Y);
+        WINED3D_TO_STR(CHANNEL_SOURCE_Z);
+        WINED3D_TO_STR(CHANNEL_SOURCE_W);
+        WINED3D_TO_STR(CHANNEL_SOURCE_YUV0);
+        WINED3D_TO_STR(CHANNEL_SOURCE_YUV1);
+#undef WINED3D_TO_STR
+        default:
+            FIXME("Unrecognized fixup_channel_source %#x\n", source);
+            return "unrecognized";
+    }
+}
+
+const char *debug_yuv_fixup(enum yuv_fixup yuv_fixup)
+{
+    switch(yuv_fixup)
+    {
+#define WINED3D_TO_STR(x) case x: return #x
+        WINED3D_TO_STR(YUV_FIXUP_YUY2);
+        WINED3D_TO_STR(YUV_FIXUP_UYVY);
+        WINED3D_TO_STR(YUV_FIXUP_YV12);
+#undef WINED3D_TO_STR
+        default:
+            FIXME("Unrecognized YUV fixup %#x\n", yuv_fixup);
+            return "unrecognized";
+    }
+}
+
+void dump_color_fixup_desc(struct color_fixup_desc fixup)
+{
+    if (is_yuv_fixup(fixup))
+    {
+        TRACE("\tYUV: %s\n", debug_yuv_fixup(get_yuv_fixup(fixup)));
+        return;
+    }
+
+    TRACE("\tX: %s%s\n", debug_fixup_channel_source(fixup.x_source), fixup.x_sign_fixup ? ", SIGN_FIXUP" : "");
+    TRACE("\tY: %s%s\n", debug_fixup_channel_source(fixup.y_source), fixup.y_sign_fixup ? ", SIGN_FIXUP" : "");
+    TRACE("\tZ: %s%s\n", debug_fixup_channel_source(fixup.z_source), fixup.z_sign_fixup ? ", SIGN_FIXUP" : "");
+    TRACE("\tW: %s%s\n", debug_fixup_channel_source(fixup.w_source), fixup.w_sign_fixup ? ", SIGN_FIXUP" : "");
+}
+
 /*****************************************************************************
  * Useful functions mapping GL <-> D3D values
  */
@@ -1829,7 +1897,7 @@ void gen_ffp_frag_op(IWineD3DStateBlockImpl *stateblock, struct ffp_frag_setting
             settings->op[i].aop = WINED3DTOP_DISABLE;
             settings->op[i].carg0 = settings->op[i].carg1 = settings->op[i].carg2 = ARG_UNUSED;
             settings->op[i].aarg0 = settings->op[i].aarg1 = settings->op[i].aarg2 = ARG_UNUSED;
-            settings->op[i].color_correction = WINED3DFMT_UNKNOWN;
+            settings->op[i].color_correction = COLOR_FIXUP_IDENTITY;
             settings->op[i].dst = resultreg;
             settings->op[i].tex_type = tex_1d;
             settings->op[i].projected = proj_none;
@@ -1839,7 +1907,7 @@ void gen_ffp_frag_op(IWineD3DStateBlockImpl *stateblock, struct ffp_frag_setting
 
         texture = (IWineD3DBaseTextureImpl *) stateblock->textures[i];
         if(texture) {
-            settings->op[i].color_correction = texture->baseTexture.shader_conversion_group;
+            settings->op[i].color_correction = texture->baseTexture.shader_color_fixup;
             if(ignore_textype) {
                 settings->op[i].tex_type = tex_1d;
             } else {
@@ -1862,7 +1930,7 @@ void gen_ffp_frag_op(IWineD3DStateBlockImpl *stateblock, struct ffp_frag_setting
                 }
             }
         } else {
-            settings->op[i].color_correction = WINED3DFMT_UNKNOWN;
+            settings->op[i].color_correction = COLOR_FIXUP_IDENTITY;
             settings->op[i].tex_type = tex_1d;
         }
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 931f9b2..2aa74e7 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -43,6 +43,90 @@
 #include "wined3d_gl.h"
 #include "wine/list.h"
 
+/* Texture format fixups */
+
+enum fixup_channel_source
+{
+    CHANNEL_SOURCE_ZERO = 0,
+    CHANNEL_SOURCE_ONE = 1,
+    CHANNEL_SOURCE_X = 2,
+    CHANNEL_SOURCE_Y = 3,
+    CHANNEL_SOURCE_Z = 4,
+    CHANNEL_SOURCE_W = 5,
+    CHANNEL_SOURCE_YUV0 = 6,
+    CHANNEL_SOURCE_YUV1 = 7,
+};
+
+enum yuv_fixup
+{
+    YUV_FIXUP_YUY2 = 0,
+    YUV_FIXUP_UYVY = 1,
+    YUV_FIXUP_YV12 = 2,
+};
+
+#include <pshpack2.h>
+struct color_fixup_desc
+{
+    unsigned x_sign_fixup : 1;
+    unsigned x_source : 3;
+    unsigned y_sign_fixup : 1;
+    unsigned y_source : 3;
+    unsigned z_sign_fixup : 1;
+    unsigned z_source : 3;
+    unsigned w_sign_fixup : 1;
+    unsigned w_source : 3;
+};
+#include <poppack.h>
+
+static const struct color_fixup_desc COLOR_FIXUP_IDENTITY =
+        {0, CHANNEL_SOURCE_X, 0, CHANNEL_SOURCE_Y, 0, CHANNEL_SOURCE_Z, 0, CHANNEL_SOURCE_W};
+
+static inline struct color_fixup_desc create_color_fixup_desc(
+        int sign0, enum fixup_channel_source src0, int sign1, enum fixup_channel_source src1,
+        int sign2, enum fixup_channel_source src2, int sign3, enum fixup_channel_source src3)
+{
+    struct color_fixup_desc fixup =
+    {
+        sign0, src0,
+        sign1, src1,
+        sign2, src2,
+        sign3, src3,
+    };
+    return fixup;
+}
+
+static inline struct color_fixup_desc create_yuv_fixup_desc(enum yuv_fixup yuv_fixup)
+{
+    struct color_fixup_desc fixup =
+    {
+        0, yuv_fixup & (1 << 0) ? CHANNEL_SOURCE_YUV1 : CHANNEL_SOURCE_YUV0,
+        0, yuv_fixup & (1 << 1) ? CHANNEL_SOURCE_YUV1 : CHANNEL_SOURCE_YUV0,
+        0, yuv_fixup & (1 << 2) ? CHANNEL_SOURCE_YUV1 : CHANNEL_SOURCE_YUV0,
+        0, yuv_fixup & (1 << 3) ? CHANNEL_SOURCE_YUV1 : CHANNEL_SOURCE_YUV0,
+    };
+    return fixup;
+}
+
+static inline BOOL is_identity_fixup(struct color_fixup_desc fixup)
+{
+    return !memcmp(&fixup, &COLOR_FIXUP_IDENTITY, sizeof(fixup));
+}
+
+static inline BOOL is_yuv_fixup(struct color_fixup_desc fixup)
+{
+    return fixup.x_source == CHANNEL_SOURCE_YUV0 || fixup.x_source == CHANNEL_SOURCE_YUV1;
+}
+
+static inline enum yuv_fixup get_yuv_fixup(struct color_fixup_desc fixup)
+{
+    enum yuv_fixup yuv_fixup = 0;
+    if (fixup.x_source == CHANNEL_SOURCE_YUV1) yuv_fixup |= (1 << 0);
+    if (fixup.y_source == CHANNEL_SOURCE_YUV1) yuv_fixup |= (1 << 1);
+    if (fixup.z_source == CHANNEL_SOURCE_YUV1) yuv_fixup |= (1 << 2);
+    if (fixup.w_source == CHANNEL_SOURCE_YUV1) yuv_fixup |= (1 << 3);
+    return yuv_fixup;
+}
+
 /* Hash table functions */
 typedef unsigned int (hash_function_t)(const void *key);
 typedef BOOL (compare_function_t)(const void *keya, const void *keyb);
@@ -350,7 +434,7 @@ typedef struct {
     void (*shader_deselect_depth_blt)(IWineD3DDevice *iface);
     void (*shader_load_constants)(IWineD3DDevice *iface, char usePS, char useVS);
     void (*shader_cleanup)(IWineD3DDevice *iface);
-    void (*shader_color_correction)(const struct SHADER_OPCODE_ARG *arg);
+    void (*shader_color_correction)(const struct SHADER_OPCODE_ARG *arg, struct color_fixup_desc fixup);
     void (*shader_destroy)(IWineD3DBaseShader *iface);
     HRESULT (*shader_alloc_private)(IWineD3DDevice *iface);
     void (*shader_free_private)(IWineD3DDevice *iface);
@@ -358,7 +442,7 @@ typedef struct {
     GLuint (*shader_generate_pshader)(IWineD3DPixelShader *iface, SHADER_BUFFER *buffer);
     void (*shader_generate_vshader)(IWineD3DVertexShader *iface, SHADER_BUFFER *buffer);
     void (*shader_get_caps)(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct shader_caps *caps);
-    BOOL (*shader_conv_supported)(WINED3DFORMAT conv);
+    BOOL (*shader_color_fixup_supported)(struct color_fixup_desc fixup);
 } shader_backend_t;
 
 extern const shader_backend_t glsl_shader_backend;
@@ -655,7 +739,7 @@ struct fragment_pipeline {
     void (*get_caps)(WINED3DDEVTYPE devtype, const WineD3D_GL_Info *gl_info, struct fragment_caps *caps);
     HRESULT (*alloc_private)(IWineD3DDevice *iface);
     void (*free_private)(IWineD3DDevice *iface);
-    BOOL (*conv_supported)(WINED3DFORMAT conv);
+    BOOL (*color_fixup_supported)(struct color_fixup_desc fixup);
     const struct StateEntryTemplate *states;
     BOOL ffp_proj_control;
 };
@@ -679,7 +763,7 @@ struct blit_shader {
     void (*free_private)(IWineD3DDevice *iface);
     HRESULT (*set_shader)(IWineD3DDevice *iface, WINED3DFORMAT fmt, GLenum textype, UINT width, UINT height);
     void (*unset_shader)(IWineD3DDevice *iface);
-    BOOL (*conv_supported)(WINED3DFORMAT conv);
+    BOOL (*color_fixup_supported)(struct color_fixup_desc fixup);
 };
 
 extern const struct blit_shader ffp_blit;
@@ -852,17 +936,24 @@ enum dst_arg
 /*****************************************************************************
  * Fixed function pipeline replacements
  */
+#define ARG_UNUSED          0x3f
 struct texture_stage_op
 {
-    unsigned                cop : 5, aop : 5;
-#define ARG_UNUSED          0x3f
-    unsigned                carg1 : 6, carg2 : 6, carg0 : 6;
+    unsigned                cop : 8;
+    unsigned                carg1 : 8;
+    unsigned                carg2 : 8;
+    unsigned                carg0 : 8;
+
+    unsigned                aop : 8;
+    unsigned                aarg1 : 8;
+    unsigned                aarg2 : 8;
+    unsigned                aarg0 : 8;
+
+    struct color_fixup_desc color_correction;
     unsigned                tex_type : 3;
-    unsigned                dst : 1;                        /* Total of 32 bits */
-    unsigned                aarg1 : 6, aarg2 : 6, aarg0 : 6;
+    unsigned                dst : 1;
     unsigned                projected : 2;
-    unsigned                padding : 12;                   /* Total of 64 bits */
-    WINED3DFORMAT           color_correction;
+    unsigned                padding : 10;
 };
 
 struct ffp_frag_settings {
@@ -1235,20 +1326,20 @@ typedef enum winetexturestates {
  */
 typedef struct IWineD3DBaseTextureClass
 {
+    DWORD                   states[MAX_WINETEXTURESTATES];
     UINT                    levels;
     BOOL                    dirty;
     UINT                    textureName;
+    float                   pow2Matrix[16];
     UINT                    LOD;
     WINED3DTEXTUREFILTERTYPE filterType;
-    DWORD                   states[MAX_WINETEXTURESTATES];
     LONG                    bindCount;
     DWORD                   sampler;
     BOOL                    is_srgb;
     UINT                    srgb_mode_change_count;
-    WINED3DFORMAT           shader_conversion_group;
-    float                   pow2Matrix[16];
     const struct min_lookup *minMipLookup;
     const GLenum            *magLookup;
+    struct color_fixup_desc shader_color_fixup;
 } IWineD3DBaseTextureClass;
 
 typedef struct IWineD3DBaseTextureImpl
@@ -1929,6 +2020,9 @@ const char *debug_glerror(GLenum error);
 const char *debug_d3dbasis(WINED3DBASISTYPE basis);
 const char *debug_d3ddegree(WINED3DDEGREETYPE order);
 const char* debug_d3dtop(WINED3DTEXTUREOP d3dtop);
+const char *debug_fixup_channel_source(enum fixup_channel_source source);
+const char *debug_yuv_fixup(enum yuv_fixup yuv_fixup);
+void dump_color_fixup_desc(struct color_fixup_desc fixup);
 
 /* Routines for GL <-> D3D values */
 GLenum StencilOp(DWORD op);
@@ -2291,8 +2385,8 @@ struct stb_const_desc {
  * into the shader code
  */
 struct ps_compile_args {
+    struct color_fixup_desc     color_fixup[MAX_FRAGMENT_SAMPLERS];
     BOOL                        srgb_correction;
-    WINED3DFORMAT               format_conversion[MAX_FRAGMENT_SAMPLERS];
     enum vertexprocessing_mode  vp_mode;
     /* Projected textures(ps 1.0-1.3) */
     /* Texture types(2D, Cube, 3D) in ps 1.x */
@@ -2380,9 +2474,9 @@ struct GlPixelFormatDesc
     GLint rtInternal;
     GLint glFormat;
     GLint glType;
-    WINED3DFORMAT conversion_group;
     unsigned int Flags;
     float heightscale;
+    struct color_fixup_desc color_fixup;
 };
 
 typedef struct {
-- 
1.5.6.4



--------------060308070006020206090204--



More information about the wine-patches mailing list