[PATCH 2/2] wined3d: Implement color keying in the glsl fragment pipeline (v2).

Stefan Dösinger stefan at codeweavers.com
Fri Apr 10 05:05:54 CDT 2015


This supersedes patch 110699.

Version 2: Rebased on top of the changed previous patch. No functional
changes.

Note that state_alpha() currently always updates the alpha op and thus
the pixel shader when color keying is enabled or has been enabled in the
previous draw. That's not ideal, but right now I am using it to reduce
the complexity of this patch. The next patches will address this.
Changing texture 0 updates the colorkey state when pixel shaders are
disabled.
---
 dlls/ddraw/tests/ddraw1.c         | 22 ++++++----------------
 dlls/ddraw/tests/ddraw2.c         | 22 ++++++----------------
 dlls/ddraw/tests/ddraw4.c         | 22 ++++++----------------
 dlls/ddraw/tests/ddraw7.c         | 22 ++++++----------------
 dlls/wined3d/arb_program_shader.c | 25 +++++++++----------------
 dlls/wined3d/cs.c                 |  3 +++
 dlls/wined3d/directx.c            |  1 +
 dlls/wined3d/glsl_shader.c        | 29 +++++++++++++++++++++++++++--
 dlls/wined3d/state.c              |  3 +++
 dlls/wined3d/texture.c            | 18 ++++++++++++------
 dlls/wined3d/utils.c              |  9 +++++++++
 dlls/wined3d/wined3d_private.h    | 10 +++++++---
 12 files changed, 95 insertions(+), 91 deletions(-)

diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index efb00b2..597251c 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -1329,14 +1329,9 @@ static void test_ck_rgba(void)
         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
 
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
-        else
-            ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
+        ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result1, i, color);
 
         U5(fx).dwFillColor = 0xff0000ff;
         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
@@ -1353,14 +1348,9 @@ static void test_ck_rgba(void)
         /* This tests that fragments that are masked out by the color key are
          * discarded, instead of just fully transparent. */
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
-        else
-            ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
+        ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result2, i, color);
     }
 
     IDirectDrawSurface_Release(rt);
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index 5f59f06..104bf5b 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -1577,14 +1577,9 @@ static void test_ck_rgba(void)
         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
 
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
-        else
-            ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
+        ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result1, i, color);
 
         U5(fx).dwFillColor = 0xff0000ff;
         hr = IDirectDrawSurface_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
@@ -1600,14 +1595,9 @@ static void test_ck_rgba(void)
         /* This tests that fragments that are masked out by the color key are
          * discarded, instead of just fully transparent. */
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
-        else
-            ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
+        ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result2, i, color);
     }
 
     IDirectDrawSurface_Release(rt);
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 70ca117..ac31e24 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -1766,14 +1766,9 @@ static void test_ck_rgba(void)
         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
 
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
-        else
-            ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
+        ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result1, i, color);
 
         U5(fx).dwFillColor = 0xff0000ff;
         hr = IDirectDrawSurface4_Blt(surface, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
@@ -1789,14 +1784,9 @@ static void test_ck_rgba(void)
         /* This tests that fragments that are masked out by the color key are
          * discarded, instead of just fully transparent. */
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
-        else
-            ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
+        ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result2, i, color);
     }
 
     IDirectDrawSurface4_Release(rt);
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 21ba3390..8d679ca 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -1471,14 +1471,9 @@ static void test_ck_rgba(void)
         ok(SUCCEEDED(hr), "Failed to end scene, hr %#x.\n", hr);
 
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
-        else
-            ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result1, i, color);
+        ok(compare_color(color, tests[i].result1, 1) || compare_color(color, tests[i].result1_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result1, i, color);
 
         U5(fx).dwFillColor = 0xff0000ff;
         hr = IDirectDrawSurface7_Blt(texture, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &fx);
@@ -1494,14 +1489,9 @@ static void test_ck_rgba(void)
         /* This tests that fragments that are masked out by the color key are
          * discarded, instead of just fully transparent. */
         color = get_surface_color(rt, 320, 240);
-        if (i == 2)
-            todo_wine ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
-        else
-            ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
-                    "Expected color 0x%08x for test %u, got 0x%08x.\n",
-                    tests[i].result2, i, color);
+        ok(compare_color(color, tests[i].result2, 1) || compare_color(color, tests[i].result2_broken, 1),
+                "Expected color 0x%08x for test %u, got 0x%08x.\n",
+                tests[i].result2, i, color);
     }
 
     IDirectDrawSurface7_Release(rt);
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index c9a3b4f..5d7d975 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -7556,10 +7556,10 @@ static GLuint arbfp_gen_plain_shader(struct arbfp_blit_priv *priv,
         shader_addline(&buffer, "TEMP compare;\n");
         shader_addline(&buffer, "PARAM color_key = program.local[%u];\n", ARBFP_BLIT_PARAM_COLOR_KEY);
         shader_addline(&buffer, "TEX color, fragment.texcoord[0], texture[0], %s;\n", tex_target);
-        shader_addline(&buffer, "SGE compare.r, color.a, color_key.a;\n");
-        shader_addline(&buffer, "SGE compare.g, -color.a, -color_key.a;\n");
-        shader_addline(&buffer, "MUL compare, compare.r, -compare.g;\n");
-        shader_addline(&buffer, "KIL compare;\n");
+        shader_addline(&buffer, "SUB compare, color, color_key;\n");
+        shader_addline(&buffer, "DP4 compare.r, compare, compare;\n");
+        shader_addline(&buffer, "SGE compare, -compare.r, 0.0;\n");
+        shader_addline(&buffer, "KIL -compare;\n");
         shader_addline(&buffer, "MOV result.color, color;\n");
     }
     else
@@ -7599,7 +7599,7 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context,
     struct wine_rb_entry *entry;
     struct arbfp_blit_type type;
     struct arbfp_blit_desc *desc;
-    float float_color_key[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+    struct wined3d_color float_color_key;
 
     if (is_complex_fixup(surface->resource.format->color_fixup))
         fixup = get_complex_fixup(surface->resource.format->color_fixup);
@@ -7699,10 +7699,10 @@ err_out:
     checkGLcall("glProgramLocalParameter4fvARB");
     if (type.use_color_key)
     {
-        if (surface->resource.format->id == WINED3DFMT_P8_UINT)
-            float_color_key[3] = color_key->color_space_low_value / 255.0f;
-
-        GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARBFP_BLIT_PARAM_COLOR_KEY, float_color_key));
+        wined3d_format_convert_color_to_float(surface->resource.format, NULL,
+                surface->container->async.src_blt_color_key.color_space_high_value, &float_color_key);
+        GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB,
+                ARBFP_BLIT_PARAM_COLOR_KEY, &float_color_key.r));
         checkGLcall("glProgramLocalParameter4fvARB");
     }
 
@@ -7790,10 +7790,6 @@ HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
     struct wined3d_context *context;
     RECT src_rect = *src_rect_in;
     RECT dst_rect = *dst_rect_in;
-    struct wined3d_color_key old_color_key = src_surface->container->async.src_blt_color_key;
-    DWORD old_color_key_flags = src_surface->container->async.color_key_flags;
-
-    wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT, color_key);
 
     /* Activate the destination context, set it up for blitting */
     context = context_acquire(device, dst_surface);
@@ -7840,9 +7836,6 @@ HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
     surface_validate_location(dst_surface, dst_surface->container->resource.draw_binding);
     surface_invalidate_location(dst_surface, ~dst_surface->container->resource.draw_binding);
 
-    wined3d_texture_set_color_key(src_surface->container, WINED3D_CKEY_SRC_BLT,
-            (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_color_key : NULL);
-
     return WINED3D_OK;
 }
 
diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c
index 4ed68f3..6bdf969 100644
--- a/dlls/wined3d/cs.c
+++ b/dlls/wined3d/cs.c
@@ -931,6 +931,9 @@ static void wined3d_cs_exec_set_color_key(struct wined3d_cs *cs, const void *dat
                 break;
         }
     }
+
+    if (texture->resource.bind_count && op->flags & WINED3D_CKEY_SRC_BLT)
+        device_invalidate_state(cs->device, STATE_RENDER(WINED3D_RS_COLORKEYENABLE));
 }
 
 void wined3d_cs_emit_set_color_key(struct wined3d_cs *cs, struct wined3d_texture *texture,
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 13061f4..36fc4ed 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -3563,6 +3563,7 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter)
     adapter->fragment_pipe->get_caps(gl_info, &fragment_caps);
     adapter->d3d_info.limits.ffp_blend_stages = fragment_caps.MaxTextureBlendStages;
     adapter->d3d_info.limits.ffp_textures = fragment_caps.MaxSimultaneousTextures;
+    adapter->d3d_info.shader_color_key = fragment_caps.wined3d_caps & WINED3D_FRAGMENT_CAP_COLOR_KEY;
     TRACE("Max texture stages: %u.\n", adapter->d3d_info.limits.ffp_blend_stages);
 
     if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT])
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index f7edc0f..39c58cc 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -143,6 +143,7 @@ struct glsl_ps_program
     GLint specular_enable_location;
     GLint ycorrection_location;
     GLint np2_fixup_location;
+    GLint color_key_location;
     const struct ps_np2fixup_info *np2_fixup_info;
 };
 
@@ -834,6 +835,18 @@ static void shader_glsl_ffp_vertex_normalmatrix_uniform(const struct wined3d_con
 }
 
 /* Context activation is done by the caller (state handler). */
+static void shader_glsl_load_color_key_constant(const struct glsl_ps_program *ps,
+        const struct wined3d_gl_info *gl_info, const struct wined3d_state *state)
+{
+    struct wined3d_color float_key;
+    const struct wined3d_texture *texture = state->textures[0];
+
+    wined3d_format_convert_color_to_float(texture->resource.format, NULL,
+            texture->async.src_blt_color_key.color_space_high_value, &float_key);
+    GL_EXTCALL(glUniform4fv(ps->color_key_location, 1, &float_key.r));
+}
+
+/* Context activation is done by the caller (state handler). */
 static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context *context,
         const struct wined3d_state *state)
 {
@@ -947,6 +960,8 @@ static void shader_glsl_load_constants(void *shader_priv, struct wined3d_context
 
     if (update_mask & WINED3D_SHADER_CONST_PS_NP2_FIXUP)
         shader_glsl_load_np2fixup_constants(&prog->ps, gl_info, state);
+    if (update_mask & WINED3D_SHADER_CONST_FFP_COLOR_KEY)
+        shader_glsl_load_color_key_constant(&prog->ps, gl_info, state);
 
     if (update_mask & WINED3D_SHADER_CONST_FFP_PS)
     {
@@ -5499,7 +5514,8 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf
         arg1 = settings->op[stage].carg1 & WINED3DTA_SELECTMASK;
         arg2 = settings->op[stage].carg2 & WINED3DTA_SELECTMASK;
 
-        if (arg0 == WINED3DTA_TEXTURE || arg1 == WINED3DTA_TEXTURE || arg2 == WINED3DTA_TEXTURE)
+        if (arg0 == WINED3DTA_TEXTURE || arg1 == WINED3DTA_TEXTURE || arg2 == WINED3DTA_TEXTURE
+                || (stage == 0 && settings->color_key_enabled))
             tex_map |= 1 << stage;
         if (arg0 == WINED3DTA_TFACTOR || arg1 == WINED3DTA_TFACTOR || arg2 == WINED3DTA_TFACTOR)
             tfactor_used = TRUE;
@@ -5603,6 +5619,8 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf
     }
     if (tfactor_used)
         shader_addline(buffer, "uniform vec4 tex_factor;\n");
+    if (settings->color_key_enabled)
+        shader_addline(buffer, "uniform vec4 color_key;\n");
     shader_addline(buffer, "uniform vec4 specular_enable;\n");
 
     if (settings->sRGB_write)
@@ -5759,6 +5777,9 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct wined3d_shader_buf
                 settings->op[stage].color_fixup);
     }
 
+    if (settings->color_key_enabled)
+        shader_addline(buffer, "if (all(equal(tex0, color_key))) discard;\n");
+
     /* Generate the main shader */
     for (stage = 0; stage < MAX_TEXTURES; ++stage)
     {
@@ -5949,6 +5970,7 @@ static void shader_glsl_init_ps_uniform_locations(const struct wined3d_gl_info *
     ps->specular_enable_location = GL_EXTCALL(glGetUniformLocation(program_id, "specular_enable"));
     ps->np2_fixup_location = GL_EXTCALL(glGetUniformLocation(program_id, "ps_samplerNP2Fixup"));
     ps->ycorrection_location = GL_EXTCALL(glGetUniformLocation(program_id, "ycorrection"));
+    ps->color_key_location = GL_EXTCALL(glGetUniformLocation(program_id, "color_key"));
 }
 
 static void shader_glsl_init_uniform_block_bindings(const struct wined3d_gl_info *gl_info, GLuint program_id,
@@ -6245,6 +6267,8 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const
 
         if (entry->ps.np2_fixup_location != -1)
             entry->constant_update_mask |= WINED3D_SHADER_CONST_PS_NP2_FIXUP;
+        if (entry->ps.color_key_location != -1)
+            entry->constant_update_mask |= WINED3D_SHADER_CONST_FFP_COLOR_KEY;
     }
 }
 
@@ -7405,7 +7429,8 @@ static void glsl_fragment_pipe_enable(const struct wined3d_gl_info *gl_info, BOO
 static void glsl_fragment_pipe_get_caps(const struct wined3d_gl_info *gl_info, struct fragment_caps *caps)
 {
     caps->wined3d_caps = WINED3D_FRAGMENT_CAP_PROJ_CONTROL
-            | WINED3D_FRAGMENT_CAP_SRGB_WRITE;
+            | WINED3D_FRAGMENT_CAP_SRGB_WRITE
+            | WINED3D_FRAGMENT_CAP_COLOR_KEY;
     caps->PrimitiveMiscCaps = WINED3DPMISCCAPS_TSSARGTEMP
             | WINED3DPMISCCAPS_PERSTAGECONSTANT;
     caps->TextureOpCaps = WINED3DTEXOPCAPS_DISABLE
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index f5c1b4f..26bb7dd 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -528,6 +528,9 @@ static void state_alpha(struct wined3d_context *context, const struct wined3d_st
         context_apply_state(context, state, STATE_TEXTURESTAGE(0, WINED3D_TSS_ALPHA_OP));
     context->last_was_ckey = enable_ckey;
 
+    if (context->d3d_info->shader_color_key)
+        enable_ckey = FALSE;
+
     if (state->render_states[WINED3D_RS_ALPHATESTENABLE]
             || (state->render_states[WINED3D_RS_COLORKEYENABLE] && enable_ckey))
     {
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 7c47189..34c69d1 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -449,6 +449,7 @@ void wined3d_texture_load(struct wined3d_texture *texture,
 {
     UINT sub_count = texture->level_count * texture->layer_count;
     const struct wined3d_gl_info *gl_info = context->gl_info;
+    const struct wined3d_d3d_info *d3d_info = context->d3d_info;
     DWORD flag;
     UINT i;
 
@@ -462,10 +463,11 @@ void wined3d_texture_load(struct wined3d_texture *texture,
     else
         flag = WINED3D_TEXTURE_RGB_VALID;
 
-    if (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
+    if (!d3d_info->shader_color_key
+            && (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
             != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
             || (texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY
-            && !color_key_equal(&texture->async.gl_color_key, &texture->async.src_blt_color_key)))
+            && !color_key_equal(&texture->async.gl_color_key, &texture->async.src_blt_color_key))))
     {
         unsigned int sub_count = texture->level_count * texture->layer_count;
         unsigned int i;
@@ -664,17 +666,21 @@ HRESULT CDECL wined3d_texture_update_desc(struct wined3d_texture *texture, UINT
 void wined3d_texture_prepare_texture(struct wined3d_texture *texture, struct wined3d_context *context, BOOL srgb)
 {
     DWORD alloc_flag = srgb ? WINED3D_TEXTURE_SRGB_ALLOCATED : WINED3D_TEXTURE_RGB_ALLOCATED;
+    const struct wined3d_d3d_info *d3d_info = context->d3d_info;
 
-    if (!(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
+    if (!d3d_info->shader_color_key
+            && !(texture->async.flags & WINED3D_TEXTURE_ASYNC_COLOR_KEY)
             != !(texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT))
+    {
         wined3d_texture_force_reload(texture);
 
+        if (texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
+            texture->async.flags |= WINED3D_TEXTURE_ASYNC_COLOR_KEY;
+    }
+
     if (texture->flags & alloc_flag)
         return;
 
-    if (texture->async.color_key_flags & WINED3D_CKEY_SRC_BLT)
-        texture->async.flags |= WINED3D_TEXTURE_ASYNC_COLOR_KEY;
-
     texture->texture_ops->texture_prepare_texture(texture, context, srgb);
     texture->flags |= alloc_flag;
 }
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 41326de..4d9f88a 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -3688,6 +3688,8 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d
     const struct wined3d_gl_info *gl_info = context->gl_info;
     const struct wined3d_d3d_info *d3d_info = context->d3d_info;
 
+    settings->padding = 0;
+
     for (i = 0; i < d3d_info->limits.ffp_blend_stages; ++i)
     {
         const struct wined3d_texture *texture;
@@ -3915,6 +3917,13 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d
     } else {
         settings->emul_clipplanes = 1;
     }
+
+    if (state->render_states[WINED3D_RS_COLORKEYENABLE] && state->textures[0]
+            && state->textures[0]->async.color_key_flags & WINED3D_CKEY_SRC_BLT
+            && settings->op[0].cop != WINED3D_TOP_DISABLE)
+        settings->color_key_enabled = 1;
+    else
+        settings->color_key_enabled = 0;
 }
 
 const struct ffp_frag_desc *find_ffp_frag_shader(const struct wine_rb_tree *fragment_shaders,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 4a454a0..5ea4150 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -309,6 +309,7 @@ enum wined3d_shader_resource_type
 #define WINED3D_SHADER_CONST_FFP_MODELVIEW  0x00000400
 #define WINED3D_SHADER_CONST_FFP_PROJ       0x00000800
 #define WINED3D_SHADER_CONST_FFP_PS         0x00001000
+#define WINED3D_SHADER_CONST_FFP_COLOR_KEY  0x00002000
 
 enum wined3d_shader_register_type
 {
@@ -1258,6 +1259,7 @@ struct StateEntryTemplate
 
 #define WINED3D_FRAGMENT_CAP_PROJ_CONTROL   0x00000001
 #define WINED3D_FRAGMENT_CAP_SRGB_WRITE     0x00000002
+#define WINED3D_FRAGMENT_CAP_COLOR_KEY      0x00000004
 
 struct fragment_caps
 {
@@ -1743,6 +1745,7 @@ struct wined3d_d3d_info
     struct wined3d_ffp_attrib_ops ffp_attrib_ops;
     BOOL xyzrhw;
     BOOL vs_clipping;
+    BOOL shader_color_key;
     DWORD valid_rt_mask;
 };
 
@@ -1815,9 +1818,10 @@ struct ffp_frag_settings
 {
     struct texture_stage_op op[MAX_TEXTURES];
     enum wined3d_ffp_ps_fog_mode fog;
-    /* Use shorts instead of chars to get dword alignment */
-    unsigned short sRGB_write;
-    unsigned short emul_clipplanes;
+    unsigned char sRGB_write;
+    unsigned char emul_clipplanes;
+    unsigned char color_key_enabled;
+    unsigned char padding;
 };
 
 struct ffp_frag_desc
-- 
2.3.4




More information about the wine-patches mailing list