[PATCH 1/2] wined3d: Implement color keying in arbfp_blit (v2).

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


This supersedes patch 110698.

Version 2: Fix the comparison. It doesn't really matter because we're
only comparing against 0.0 in practise, and the next patch changes the
code anyway, but we may as well get it right when we have the transition
code. Also use 0.0f instead of 0 to initialize a float array.

This intentionally discards on the alpha value. To do a proper color
compare we have to migrate fixed function pipeline color keying and
blits at the same time because the color keying conversion changes the
texture contents and can cause the key not to match.
---
 dlls/wined3d/arb_program_shader.c | 68 +++++++++++++++++++++++++++++++++------
 dlls/wined3d/surface.c            | 51 +++++++++++++++++++----------
 dlls/wined3d/swapchain.c          |  2 +-
 dlls/wined3d/wined3d_private.h    |  7 ++--
 4 files changed, 99 insertions(+), 29 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 79439f5..c9a3b4f 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -6825,7 +6825,8 @@ struct arbfp_blit_type
 {
     enum complex_fixup fixup : 4;
     enum wined3d_gl_resource_type res_type : 3;
-    DWORD padding : 25;
+    DWORD use_color_key : 1;
+    DWORD padding : 24;
 };
 
 struct arbfp_blit_desc
@@ -6836,6 +6837,7 @@ struct arbfp_blit_desc
 };
 
 #define ARBFP_BLIT_PARAM_SIZE 0
+#define ARBFP_BLIT_PARAM_COLOR_KEY 1
 
 struct arbfp_blit_priv
 {
@@ -7287,6 +7289,11 @@ static GLuint gen_p8_shader(struct arbfp_blit_priv *priv,
     GLint pos;
     const char *tex_target = arbfp_texture_target(type->res_type);
 
+    /* This should not happen because we only use this conversion for
+     * present blits which don't use color keying. */
+    if (type->use_color_key)
+        FIXME("Implement P8 color keying.\n");
+
     /* Shader header */
     if (!shader_buffer_init(&buffer))
     {
@@ -7382,6 +7389,9 @@ static GLuint gen_yuv_shader(struct arbfp_blit_priv *priv, const struct wined3d_
     char luminance_component;
     GLint pos;
 
+    if (type->use_color_key)
+        FIXME("Implement YUV color keying.\n");
+
     /* Shader header */
     if (!shader_buffer_init(&buffer))
     {
@@ -7539,7 +7549,24 @@ static GLuint arbfp_gen_plain_shader(struct arbfp_blit_priv *priv,
     GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader));
 
     shader_addline(&buffer, "!!ARBfp1.0\n");
-    shader_addline(&buffer, "TEX result.color, fragment.texcoord[0], texture[0], %s;\n", tex_target);
+
+    if (type->use_color_key)
+    {
+        shader_addline(&buffer, "TEMP color;\n");
+        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, "MOV result.color, color;\n");
+    }
+    else
+    {
+        shader_addline(&buffer, "TEX result.color, fragment.texcoord[0], texture[0], %s;\n", tex_target);
+    }
+
     shader_addline(&buffer, "END\n");
 
     GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
@@ -7560,7 +7587,8 @@ static GLuint arbfp_gen_plain_shader(struct arbfp_blit_priv *priv,
 }
 
 /* Context activation is done by the caller. */
-static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
+static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
+        const struct wined3d_color_key *color_key)
 {
     GLenum shader;
     float size[4] = {(float) surface->pow2Width, (float) surface->pow2Height, 1.0f, 1.0f};
@@ -7571,6 +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};
 
     if (is_complex_fixup(surface->resource.format->color_fixup))
         fixup = get_complex_fixup(surface->resource.format->color_fixup);
@@ -7604,7 +7633,7 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context,
             type.res_type = WINED3D_GL_RES_TYPE_TEX_2D;
     }
     type.fixup = fixup;
-    type.padding = 0;
+    type.use_color_key = !!color_key;
 
     entry = wine_rb_get(&priv->shaders, &type);
     if (entry)
@@ -7668,6 +7697,14 @@ err_out:
     checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader)");
     GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, ARBFP_BLIT_PARAM_SIZE, size));
     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));
+        checkGLcall("glProgramLocalParameter4fvARB");
+    }
 
     return WINED3D_OK;
 }
@@ -7688,10 +7725,15 @@ static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info, enum win
     if (!gl_info->supported[ARB_FRAGMENT_PROGRAM])
         return FALSE;
 
-    if (blit_op != WINED3D_BLIT_OP_COLOR_BLIT)
+    switch (blit_op)
     {
-        TRACE("Unsupported blit_op=%d\n", blit_op);
-        return FALSE;
+        case WINED3D_BLIT_OP_COLOR_BLIT:
+        case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
+            break;
+
+        default:
+            TRACE("Unsupported blit_op=%d\n", blit_op);
+            return FALSE;
     }
 
     if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
@@ -7742,11 +7784,16 @@ static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info, enum win
 
 HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
         struct wined3d_surface *src_surface, const RECT *src_rect_in,
-        struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
+        struct wined3d_surface *dst_surface, const RECT *dst_rect_in,
+        const struct wined3d_color_key *color_key)
 {
     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);
@@ -7775,7 +7822,7 @@ HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
     if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
 
-    arbfp_blit_set(device->blit_priv, context, src_surface);
+    arbfp_blit_set(device->blit_priv, context, src_surface, color_key);
 
     /* Draw a textured quad */
     draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
@@ -7793,6 +7840,9 @@ 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/surface.c b/dlls/wined3d/surface.c
index 7a707f6..5bcbfd4 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -3398,7 +3398,7 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
     if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
 
-    device->blitter->set_shader(device->blit_priv, context, src_surface);
+    device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
 
     if (alpha_test)
     {
@@ -4290,7 +4290,8 @@ static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK
 static void ffp_blit_free(struct wined3d_device *device) { }
 
 /* Context activation is done by the caller. */
-static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
+static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
+        const struct wined3d_color_key *color_key)
 {
     const struct wined3d_gl_info *gl_info = context->gl_info;
 
@@ -4324,6 +4325,7 @@ static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined
     switch (blit_op)
     {
         case WINED3D_BLIT_OP_COLOR_BLIT:
+        case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
             if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
                 return FALSE;
 
@@ -4434,7 +4436,8 @@ static void cpu_blit_free(struct wined3d_device *device)
 }
 
 /* Context activation is done by the caller. */
-static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
+static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
+        const struct wined3d_color_key *color_key)
 {
     return WINED3D_OK;
 }
@@ -5078,6 +5081,8 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
 
     static const DWORD simple_blit = WINEDDBLT_ASYNC
             | WINEDDBLT_COLORFILL
+            | WINEDDBLT_KEYSRC
+            | WINEDDBLT_KEYSRCOVERRIDE
             | WINEDDBLT_WAIT
             | WINEDDBLT_DEPTHFILL
             | WINEDDBLT_DONOTWAIT;
@@ -5290,12 +5295,24 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
         }
         else
         {
-            TRACE("Color blit.\n");
+            enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
+            const struct wined3d_color_key *color_key = NULL;
 
-            /* Upload */
-            if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
+            TRACE("Color blit.\n");
+            if (flags & WINEDDBLT_KEYSRCOVERRIDE)
+            {
+                color_key = &fx->ddckSrcColorkey;
+                blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
+            }
+            else if (flags & WINEDDBLT_KEYSRC)
+            {
+                color_key = &src_surface->container->async.src_blt_color_key;
+                blit_op = WINED3D_BLIT_OP_COLOR_BLIT_CKEY;
+            }
+            else if ((src_surface->locations & WINED3D_LOCATION_SYSMEM)
                     && !(dst_surface->locations & WINED3D_LOCATION_SYSMEM))
             {
+                /* Upload */
                 if (scale)
                     TRACE("Not doing upload because of scaling.\n");
                 else if (convert)
@@ -5312,17 +5329,16 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
                     }
                 }
             }
-
-            /* Use present for back -> front blits. The idea behind this is
-             * that present is potentially faster than a blit, in particular
-             * when FBO blits aren't available. Some ddraw applications like
-             * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
-             * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
-             * applications can't blit directly to the frontbuffer. */
-            if (dst_swapchain && dst_swapchain->back_buffers
+            else if (dst_swapchain && dst_swapchain->back_buffers
                     && dst_surface->container == dst_swapchain->front_buffer
                     && src_surface->container == dst_swapchain->back_buffers[0])
             {
+                /* Use present for back -> front blits. The idea behind this is
+                 * that present is potentially faster than a blit, in particular
+                 * when FBO blits aren't available. Some ddraw applications like
+                 * Half-Life and Prince of Persia 3D use Blt() from the backbuffer
+                 * to the frontbuffer instead of doing a Flip(). D3D8 and D3D9
+                 * applications can't blit directly to the frontbuffer. */
                 enum wined3d_swap_effect swap_effect = dst_swapchain->desc.swap_effect;
 
                 TRACE("Using present for backbuffer -> frontbuffer blit.\n");
@@ -5336,7 +5352,7 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
                 return WINED3D_OK;
             }
 
-            if (fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
+            if (fbo_blit_supported(&device->adapter->gl_info, blit_op,
                     &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
             {
@@ -5351,13 +5367,14 @@ HRESULT CDECL wined3d_surface_blt(struct wined3d_surface *dst_surface, const REC
                 return WINED3D_OK;
             }
 
-            if (arbfp_blit.blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
+            if (arbfp_blit.blit_supported(&device->adapter->gl_info, blit_op,
                     &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
                     &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
             {
                 TRACE("Using arbfp blit.\n");
 
-                if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect, dst_surface, &dst_rect)))
+                if (SUCCEEDED(arbfp_blit_surface(device, filter, src_surface, &src_rect,
+                        dst_surface, &dst_rect, color_key)))
                     return WINED3D_OK;
             }
         }
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 887143f..146f5d6 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -367,7 +367,7 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
 
         /* Set up the texture. The surface is not in a wined3d_texture
          * container, so there are no D3D texture settings to dirtify. */
-        device->blitter->set_shader(device->blit_priv, context2, backbuffer);
+        device->blitter->set_shader(device->blit_priv, context2, backbuffer, NULL);
         gl_info->gl_ops.gl.p_glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MIN_FILTER, gl_filter);
         gl_info->gl_ops.gl.p_glTexParameteri(backbuffer->texture_target, GL_TEXTURE_MAG_FILTER, gl_filter);
 
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 0191ba7..4a454a0 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1323,6 +1323,7 @@ HRESULT compile_state_table(struct StateEntry *StateTable, APPLYSTATEFUNC **dev_
 enum wined3d_blit_op
 {
     WINED3D_BLIT_OP_COLOR_BLIT,
+    WINED3D_BLIT_OP_COLOR_BLIT_CKEY,
     WINED3D_BLIT_OP_COLOR_FILL,
     WINED3D_BLIT_OP_DEPTH_FILL,
     WINED3D_BLIT_OP_DEPTH_BLIT,
@@ -1334,7 +1335,8 @@ struct blit_shader
 {
     HRESULT (*alloc_private)(struct wined3d_device *device);
     void (*free_private)(struct wined3d_device *device);
-    HRESULT (*set_shader)(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface);
+    HRESULT (*set_shader)(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
+            const struct wined3d_color_key *color_key);
     void (*unset_shader)(const struct wined3d_gl_info *gl_info);
     BOOL (*blit_supported)(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
             const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
@@ -1357,7 +1359,8 @@ const struct blit_shader *wined3d_select_blitter(const struct wined3d_gl_info *g
 /* Temporary blit_shader helper functions */
 HRESULT arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
         struct wined3d_surface *src_surface, const RECT *src_rect,
-        struct wined3d_surface *dst_surface, const RECT *dst_rect) DECLSPEC_HIDDEN;
+        struct wined3d_surface *dst_surface, const RECT *dst_rect,
+        const struct wined3d_color_key *color_key) DECLSPEC_HIDDEN;
 
 struct wined3d_context *context_acquire(const struct wined3d_device *device,
         struct wined3d_surface *target) DECLSPEC_HIDDEN;
-- 
2.3.4




More information about the wine-patches mailing list