[PATCH 1/5] wined3d: Get rid of wined3d_select_blitter().

Henri Verbeet hverbeet at codeweavers.com
Tue Apr 4 02:07:43 CDT 2017


Instead, chain the blitters themselves. This also fixes the issue that
currently only a single blitter can store extra data in the "blit_priv" field
of struct wined3d_device.

Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/arb_program_shader.c | 141 ++++++++++------
 dlls/wined3d/device.c             |  27 +--
 dlls/wined3d/directx.c            |  12 --
 dlls/wined3d/surface.c            | 335 ++++++++++++++++++++++----------------
 dlls/wined3d/swapchain.c          |  14 +-
 dlls/wined3d/utils.c              |  31 ----
 dlls/wined3d/wined3d_private.h    |  40 +++--
 7 files changed, 313 insertions(+), 287 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 8d187ac..995900f 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -6879,8 +6879,9 @@ struct arbfp_blit_desc
 #define ARBFP_BLIT_PARAM_COLOR_KEY_LOW 1
 #define ARBFP_BLIT_PARAM_COLOR_KEY_HIGH 2
 
-struct arbfp_blit_priv
+struct wined3d_arbfp_blitter
 {
+    struct wined3d_blitter blitter;
     struct wine_rb_tree shaders;
     GLuint palette_texture;
 };
@@ -6894,44 +6895,39 @@ static int arbfp_blit_type_compare(const void *key, const struct wine_rb_entry *
 }
 
 /* Context activation is done by the caller. */
-static void arbfp_free_blit_shader(struct wine_rb_entry *entry, void *context)
+static void arbfp_free_blit_shader(struct wine_rb_entry *entry, void *ctx)
 {
-    const struct wined3d_gl_info *gl_info = context;
     struct arbfp_blit_desc *entry_arb = WINE_RB_ENTRY_VALUE(entry, struct arbfp_blit_desc, entry);
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context *context;
+
+    context = ctx;
+    gl_info = context->gl_info;
 
     GL_EXTCALL(glDeleteProgramsARB(1, &entry_arb->shader));
     checkGLcall("glDeleteProgramsARB(1, &entry_arb->shader)");
     HeapFree(GetProcessHeap(), 0, entry_arb);
 }
 
-static HRESULT arbfp_blit_alloc(struct wined3d_device *device)
+/* Context activation is done by the caller. */
+static void arbfp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
 {
-    struct arbfp_blit_priv *priv;
-
-    if (!(priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*priv))))
-        return E_OUTOFMEMORY;
-
-    wine_rb_init(&priv->shaders, arbfp_blit_type_compare);
-
-    device->blit_priv = priv;
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+    struct wined3d_arbfp_blitter *arbfp_blitter;
+    struct wined3d_blitter *next;
 
-    return WINED3D_OK;
-}
+    if ((next = blitter->next))
+        next->ops->blitter_destroy(next, context);
 
-/* Context activation is done by the caller. */
-static void arbfp_blit_free(struct wined3d_device *device)
-{
-    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
-    struct arbfp_blit_priv *priv = device->blit_priv;
+    arbfp_blitter = CONTAINING_RECORD(blitter, struct wined3d_arbfp_blitter, blitter);
 
-    wine_rb_destroy(&priv->shaders, arbfp_free_blit_shader, &device->adapter->gl_info);
+    wine_rb_destroy(&arbfp_blitter->shaders, arbfp_free_blit_shader, context);
     checkGLcall("Delete blit programs");
 
-    if (priv->palette_texture)
-        gl_info->gl_ops.gl.p_glDeleteTextures(1, &priv->palette_texture);
+    if (arbfp_blitter->palette_texture)
+        gl_info->gl_ops.gl.p_glDeleteTextures(1, &arbfp_blitter->palette_texture);
 
-    HeapFree(GetProcessHeap(), 0, device->blit_priv);
-    device->blit_priv = NULL;
+    HeapFree(GetProcessHeap(), 0, arbfp_blitter);
 }
 
 static BOOL gen_planar_yuv_read(struct wined3d_string_buffer *buffer, const struct arbfp_blit_type *type,
@@ -7358,18 +7354,17 @@ static GLuint gen_p8_shader(const struct wined3d_gl_info *gl_info, const struct
 }
 
 /* Context activation is done by the caller. */
-static void upload_palette(const struct wined3d_texture *texture, struct wined3d_context *context)
+static void upload_palette(struct wined3d_arbfp_blitter *blitter,
+        const struct wined3d_texture *texture, struct wined3d_context *context)
 {
     const struct wined3d_palette *palette = texture->swapchain ? texture->swapchain->palette : NULL;
-    struct wined3d_device *device = texture->resource.device;
     const struct wined3d_gl_info *gl_info = context->gl_info;
-    struct arbfp_blit_priv *priv = device->blit_priv;
 
-    if (!priv->palette_texture)
-        gl_info->gl_ops.gl.p_glGenTextures(1, &priv->palette_texture);
+    if (!blitter->palette_texture)
+        gl_info->gl_ops.gl.p_glGenTextures(1, &blitter->palette_texture);
 
     GL_EXTCALL(glActiveTexture(GL_TEXTURE1));
-    gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, priv->palette_texture);
+    gl_info->gl_ops.gl.p_glBindTexture(GL_TEXTURE_1D, blitter->palette_texture);
 
     gl_info->gl_ops.gl.p_glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
@@ -7573,11 +7568,10 @@ static GLuint arbfp_gen_plain_shader(const struct wined3d_gl_info *gl_info, cons
 }
 
 /* Context activation is done by the caller. */
-static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface,
-        const struct wined3d_color_key *color_key)
+static HRESULT arbfp_blit_set(struct wined3d_arbfp_blitter *blitter, struct wined3d_context *context,
+        const struct wined3d_surface *surface, const struct wined3d_color_key *color_key)
 {
     const struct wined3d_texture *texture = surface->container;
-    struct arbfp_blit_priv *priv = blit_priv;
     enum complex_fixup fixup;
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct wine_rb_entry *entry;
@@ -7627,8 +7621,7 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context,
     type.use_color_key = !!color_key;
     type.padding = 0;
 
-    entry = wine_rb_get(&priv->shaders, &type);
-    if (entry)
+    if ((entry = wine_rb_get(&blitter->shaders, &type)))
     {
         desc = WINE_RB_ENTRY_VALUE(entry, struct arbfp_blit_desc, entry);
         shader = desc->shader;
@@ -7667,7 +7660,7 @@ static HRESULT arbfp_blit_set(void *blit_priv, struct wined3d_context *context,
 
         desc->type = type;
         desc->shader = shader;
-        if (wine_rb_put(&priv->shaders, &desc->type, &desc->entry) == -1)
+        if (wine_rb_put(&blitter->shaders, &desc->type, &desc->entry) == -1)
         {
 err_out:
             ERR("Out of memory\n");
@@ -7681,7 +7674,7 @@ err_out:
     }
 
     if (fixup == COMPLEX_FIXUP_P8)
-        upload_palette(texture, context);
+        upload_palette(blitter, texture, context);
 
     gl_info->gl_ops.gl.p_glEnable(GL_FRAGMENT_PROGRAM_ARB);
     checkGLcall("glEnable(GL_FRAGMENT_PROGRAM_ARB)");
@@ -7711,8 +7704,8 @@ static void arbfp_blit_unset(const struct wined3d_gl_info *gl_info)
 
 static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info,
         const struct wined3d_d3d_info *d3d_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,
-        const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
+        enum wined3d_pool src_pool, const struct wined3d_format *src_format,
+        enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
 {
     enum complex_fixup src_fixup;
     BOOL decompress;
@@ -7786,16 +7779,31 @@ static BOOL arbfp_blit_supported(const struct wined3d_gl_info *gl_info,
     }
 }
 
-static void arbfp_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op, struct wined3d_context *context,
-        struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
-        struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect,
+static void arbfp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
+        struct wined3d_context *context, struct wined3d_surface *src_surface, DWORD src_location,
+        const RECT *src_rect, struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect,
         const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
 {
     struct wined3d_texture *src_texture = src_surface->container;
     struct wined3d_texture *dst_texture = dst_surface->container;
+    struct wined3d_device *device = dst_texture->resource.device;
+    struct wined3d_arbfp_blitter *arbfp_blitter;
     struct wined3d_color_key alpha_test_key;
+    struct wined3d_blitter *next;
     RECT s, d;
 
+    if (!arbfp_blit_supported(&device->adapter->gl_info, &device->adapter->d3d_info, op,
+            src_texture->resource.pool, src_texture->resource.format,
+            dst_texture->resource.pool, dst_texture->resource.format))
+    {
+        if ((next = blitter->next))
+            next->ops->blitter_blit(next, op, context, src_surface, src_location,
+                    src_rect, dst_surface, dst_location, dst_rect, color_key, filter);
+        return;
+    }
+
+    arbfp_blitter = CONTAINING_RECORD(blitter, struct wined3d_arbfp_blitter, blitter);
+
     /* Now load the surface */
     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
             && (surface_get_sub_resource(src_surface)->locations
@@ -7855,7 +7863,7 @@ static void arbfp_blit_surface(struct wined3d_device *device, enum wined3d_blit_
         color_key = &alpha_test_key;
     }
 
-    arbfp_blit_set(device->blit_priv, context, src_surface, color_key);
+    arbfp_blit_set(arbfp_blitter, context, src_surface, color_key);
 
     /* Draw a textured quad */
     draw_textured_quad(src_surface, context, src_rect, dst_rect, filter);
@@ -7868,17 +7876,46 @@ static void arbfp_blit_surface(struct wined3d_device *device, enum wined3d_blit_
         context->gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
 }
 
-static void arbfp_blit_clear(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
-        const RECT *rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
+static void arbfp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
+        struct wined3d_rendertarget_view *view, const RECT *rect, DWORD flags,
+        const struct wined3d_color *colour, float depth, DWORD stencil)
 {
-    ERR("This blitter does not implement clears.\n");
+    struct wined3d_blitter *next;
+
+    if ((next = blitter->next))
+        next->ops->blitter_clear(next, device, view, rect, flags, colour, depth, stencil);
 }
 
-const struct wined3d_blitter_ops arbfp_blit =
+static const struct wined3d_blitter_ops arbfp_blitter_ops =
 {
-    arbfp_blit_alloc,
-    arbfp_blit_free,
-    arbfp_blit_supported,
-    arbfp_blit_clear,
-    arbfp_blit_surface,
+    arbfp_blitter_destroy,
+    arbfp_blitter_clear,
+    arbfp_blitter_blit,
 };
+
+void wined3d_arbfp_blitter_create(struct wined3d_blitter **next, const struct wined3d_device *device)
+{
+    const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
+    struct wined3d_arbfp_blitter *blitter;
+
+    if (device->shader_backend != &arb_program_shader_backend
+            && device->shader_backend != &glsl_shader_backend)
+        return;
+
+    if (!gl_info->supported[ARB_FRAGMENT_PROGRAM])
+        return;
+
+    if (!(blitter = HeapAlloc(GetProcessHeap(), 0, sizeof(*blitter))))
+    {
+        ERR("Failed to allocate blitter.\n");
+        return;
+    }
+
+    TRACE("Created blitter %p.\n", blitter);
+
+    blitter->blitter.ops = &arbfp_blitter_ops;
+    blitter->blitter.next = *next;
+    wine_rb_init(&blitter->shaders, arbfp_blit_type_compare);
+    blitter->palette_texture = 0;
+    *next = &blitter->blitter;
+}
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index fe2c4ba..59d9769 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -979,7 +979,7 @@ static void wined3d_device_delete_opengl_contexts_cs(void *object)
     }
 
     context = context_acquire(device, NULL, 0);
-    device->blitter->free_private(device);
+    device->blitter->ops->blitter_destroy(device->blitter, context);
     device->shader_backend->shader_free_private(device);
     destroy_dummy_textures(device, context);
     destroy_default_samplers(device, context);
@@ -1014,12 +1014,15 @@ static void wined3d_device_create_primary_opengl_context_cs(void *object)
         return;
     }
 
-    if (FAILED(hr = device->blitter->alloc_private(device)))
+    if (!(device->blitter = wined3d_cpu_blitter_create()))
     {
-        ERR("Failed to allocate blitter private data, hr %#x.\n", hr);
+        ERR("Failed to create CPU blitter.\n");
         device->shader_backend->shader_free_private(device);
         return;
     }
+    wined3d_ffp_blitter_create(&device->blitter, &device->adapter->gl_info);
+    wined3d_arbfp_blitter_create(&device->blitter, device);
+    wined3d_fbo_blitter_create(&device->blitter, &device->adapter->gl_info);
 
     swapchain = device->swapchains[0];
     target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer;
@@ -4144,9 +4147,7 @@ HRESULT CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *devi
         struct wined3d_rendertarget_view *view, const RECT *rect, DWORD flags,
         const struct wined3d_color *color, float depth, DWORD stencil)
 {
-    const struct wined3d_blitter_ops *blitter;
     struct wined3d_resource *resource;
-    enum wined3d_blit_op blit_op;
     RECT r;
 
     TRACE("device %p, view %p, rect %s, flags %#x, color %s, depth %.8e, stencil %u.\n",
@@ -4184,19 +4185,7 @@ HRESULT CDECL wined3d_device_clear_rendertarget_view(struct wined3d_device *devi
             return hr;
     }
 
-    if (flags & WINED3DCLEAR_TARGET)
-        blit_op = WINED3D_BLIT_OP_COLOR_FILL;
-    else
-        blit_op = WINED3D_BLIT_OP_DEPTH_FILL;
-
-    if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info,
-            blit_op, NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format)))
-    {
-        FIXME("No blitter is capable of performing the requested fill operation.\n");
-        return WINED3DERR_INVALIDCALL;
-    }
-
-    blitter->blitter_clear(device, view, rect, flags, color, depth, stencil);
+    device->blitter->ops->blitter_clear(device->blitter, device, view, rect, flags, color, depth, stencil);
 
     return WINED3D_OK;
 }
@@ -4981,8 +4970,6 @@ HRESULT device_init(struct wined3d_device *device, struct wined3d *wined3d,
         return hr;
     }
 
-    device->blitter = adapter->blitter;
-
     state_init(&device->state, &device->fb, &adapter->gl_info,
             &adapter->d3d_info, WINED3D_STATE_INIT_DEFAULT);
     device->update_state = &device->state;
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index 82abcfa..3d70507 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -2599,16 +2599,6 @@ static const struct wined3d_shader_backend_ops *select_shader_backend(const stru
     return &none_shader_backend;
 }
 
-static const struct wined3d_blitter_ops *select_blit_implementation(const struct wined3d_gl_info *gl_info,
-        const struct wined3d_shader_backend_ops *shader_backend_ops)
-{
-    if ((shader_backend_ops == &glsl_shader_backend
-            || shader_backend_ops == &arb_program_shader_backend)
-            && gl_info->supported[ARB_FRAGMENT_PROGRAM])
-        return &arbfp_blit;
-    return &ffp_blit;
-}
-
 static void parse_extension_string(struct wined3d_gl_info *gl_info, const char *extensions,
         const struct wined3d_extension_map *map, UINT entry_count)
 {
@@ -4169,7 +4159,6 @@ static BOOL wined3d_adapter_init_gl_caps(struct wined3d_adapter *adapter,
     adapter->shader_backend = select_shader_backend(gl_info);
     adapter->vertex_pipe = select_vertex_implementation(gl_info, adapter->shader_backend);
     adapter->fragment_pipe = select_fragment_implementation(gl_info, adapter->shader_backend);
-    adapter->blitter = select_blit_implementation(gl_info, adapter->shader_backend);
 
     adapter->shader_backend->shader_get_caps(gl_info, &shader_caps);
     adapter->d3d_info.vs_clipping = shader_caps.wined3d_caps & WINED3D_SHADER_CAP_VS_CLIPPING;
@@ -6567,7 +6556,6 @@ static BOOL wined3d_adapter_init_nogl(struct wined3d_adapter *adapter, UINT ordi
     adapter->vertex_pipe = &none_vertex_pipe;
     adapter->fragment_pipe = &none_fragment_pipe;
     adapter->shader_backend = &none_shader_backend;
-    adapter->blitter = &cpu_blit;
 
     display_device.cb = sizeof(display_device);
     EnumDisplayDevicesW(NULL, ordinal, &display_device, 0);
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 9d82dcb..35d540e 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -497,10 +497,9 @@ static void surface_blt_fbo(const struct wined3d_device *device,
         context_restore(context, restore_rt);
 }
 
-static BOOL fbo_blitter_supported(const struct wined3d_gl_info *gl_info,
-        const struct wined3d_d3d_info *d3d_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,
-        const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
+static BOOL fbo_blitter_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
+        DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
+        DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
 {
     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
         return FALSE;
@@ -2196,7 +2195,7 @@ static BOOL surface_load_drawable(struct wined3d_surface *surface,
 
     surface_get_rect(surface, NULL, &r);
     wined3d_texture_load_location(texture, sub_resource_idx, context, WINED3D_LOCATION_TEXTURE_RGB);
-    device->blitter->blit_surface(device, WINED3D_BLIT_OP_COLOR_BLIT, context,
+    device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context,
             surface, WINED3D_LOCATION_TEXTURE_RGB, &r,
             surface, WINED3D_LOCATION_DRAWABLE, &r,
             NULL, WINED3D_TEXF_POINT);
@@ -2242,9 +2241,9 @@ static BOOL surface_load_texture(struct wined3d_surface *surface,
 
     if (!depth && sub_resource->locations & (WINED3D_LOCATION_TEXTURE_SRGB | WINED3D_LOCATION_TEXTURE_RGB)
             && (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
-            && fbo_blitter_supported(gl_info, &device->adapter->d3d_info, WINED3D_BLIT_OP_COLOR_BLIT,
-                NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
-                NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
+            && fbo_blitter_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
+                    texture->resource.usage, texture->resource.pool, texture->resource.format,
+                    texture->resource.usage, texture->resource.pool, texture->resource.format))
     {
         if (srgb)
             surface_blt_fbo(device, context, WINED3D_TEXF_POINT, surface, WINED3D_LOCATION_TEXTURE_RGB,
@@ -2258,9 +2257,9 @@ static BOOL surface_load_texture(struct wined3d_surface *surface,
 
     if (!depth && sub_resource->locations & (WINED3D_LOCATION_RB_MULTISAMPLE | WINED3D_LOCATION_RB_RESOLVED)
             && (!srgb || (texture->resource.format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
-            && fbo_blitter_supported(gl_info, &device->adapter->d3d_info, WINED3D_BLIT_OP_COLOR_BLIT,
-                NULL, texture->resource.usage, texture->resource.pool, texture->resource.format,
-                NULL, texture->resource.usage, texture->resource.pool, texture->resource.format))
+            && fbo_blitter_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
+                    texture->resource.usage, texture->resource.pool, texture->resource.format,
+                    texture->resource.usage, texture->resource.pool, texture->resource.format))
     {
         DWORD src_location = sub_resource->locations & WINED3D_LOCATION_RB_RESOLVED ?
                 WINED3D_LOCATION_RB_RESOLVED : WINED3D_LOCATION_RB_MULTISAMPLE;
@@ -2440,27 +2439,45 @@ BOOL surface_load_location(struct wined3d_surface *surface, struct wined3d_conte
     }
 }
 
-static HRESULT fbo_blitter_alloc(struct wined3d_device *device)
-{
-    return WINED3D_OK;
-}
-
 /* Context activation is done by the caller. */
-static void fbo_blitter_free(struct wined3d_device *device)
+static void fbo_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
 {
+    struct wined3d_blitter *next;
+
+    if ((next = blitter->next))
+        next->ops->blitter_destroy(next, context);
 }
 
-static void fbo_blitter_clear(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
-        const RECT *rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
+static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
+        struct wined3d_rendertarget_view *view, const RECT *rect, DWORD flags,
+        const struct wined3d_color *colour, float depth, DWORD stencil)
 {
-    ERR("This blitter does not implement clears.\n");
+    struct wined3d_blitter *next;
+
+    if ((next = blitter->next))
+        next->ops->blitter_clear(next, device, view, rect, flags, colour, depth, stencil);
 }
 
-static void fbo_blitter_blit(struct wined3d_device *device, enum wined3d_blit_op op,
+static void fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
         struct wined3d_context *context, struct wined3d_surface *src_surface, DWORD src_location,
         const RECT *src_rect, struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect,
         const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
 {
+    struct wined3d_resource *src_resource = &src_surface->container->resource;
+    struct wined3d_resource *dst_resource = &dst_surface->container->resource;
+    struct wined3d_device *device = dst_resource->device;
+    struct wined3d_blitter *next;
+
+    if (!fbo_blitter_supported(&device->adapter->gl_info, op,
+            src_resource->usage, src_resource->pool, src_resource->format,
+            src_resource->usage, dst_resource->pool, dst_resource->format))
+    {
+        if ((next = blitter->next))
+            next->ops->blitter_blit(next, op, context, src_surface, src_location,
+                    src_rect, dst_surface, dst_location, dst_rect, colour_key, filter);
+        return;
+    }
+
     if (op == WINED3D_BLIT_OP_COLOR_BLIT)
     {
         TRACE("Colour blit.\n");
@@ -2479,23 +2496,43 @@ static void fbo_blitter_blit(struct wined3d_device *device, enum wined3d_blit_op
     ERR("This blitter does not implement blit op %#x.\n", op);
 }
 
-const struct wined3d_blitter_ops fbo_blitter_ops =
+static const struct wined3d_blitter_ops fbo_blitter_ops =
 {
-    fbo_blitter_alloc,
-    fbo_blitter_free,
-    fbo_blitter_supported,
+    fbo_blitter_destroy,
     fbo_blitter_clear,
     fbo_blitter_blit,
 };
 
-static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
+void wined3d_fbo_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
+{
+    struct wined3d_blitter *blitter;
+
+    if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
+        return;
+
+    if (!(blitter = HeapAlloc(GetProcessHeap(), 0, sizeof(*blitter))))
+        return;
+
+    TRACE("Created blitter %p.\n", blitter);
+
+    blitter->ops = &fbo_blitter_ops;
+    blitter->next = *next;
+    *next = blitter;
+}
+
 /* Context activation is done by the caller. */
-static void ffp_blit_free(struct wined3d_device *device) { }
+static void ffp_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
+{
+    struct wined3d_blitter *next;
+
+    if ((next = blitter->next))
+        next->ops->blitter_destroy(next, context);
+}
 
 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
         const struct wined3d_d3d_info *d3d_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,
-        const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
+        DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
+        DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
 {
     BOOL decompress;
 
@@ -2517,6 +2554,9 @@ static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
             }
         case WINED3D_BLIT_OP_COLOR_BLIT:
         case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
+            if (!gl_info->supported[WINED3D_GL_LEGACY_CONTEXT])
+                return FALSE;
+
             if (TRACE_ON(d3d))
             {
                 TRACE("Checking support for fixup:\n");
@@ -2538,38 +2578,23 @@ static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info,
             }
             return TRUE;
 
-        case WINED3D_BLIT_OP_COLOR_FILL:
-            if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
-            {
-                if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
-                        || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
-                    return FALSE;
-            }
-            else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
-            {
-                TRACE("Color fill not supported\n");
-                return FALSE;
-            }
-
-            /* FIXME: We should reject color fills on formats with fixups,
-             * but this would break P8 color fills for example. */
-
-            return TRUE;
-
-        case WINED3D_BLIT_OP_DEPTH_FILL:
-            return TRUE;
-
         default:
             TRACE("Unsupported blit_op=%d\n", blit_op);
             return FALSE;
     }
 }
 
-static void ffp_blit_clear(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
-        const RECT *rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
+static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
+        struct wined3d_rendertarget_view *view, const RECT *rect, DWORD flags,
+        const struct wined3d_color *colour, float depth, DWORD stencil)
 {
     const RECT draw_rect = {0, 0, view->width, view->height};
+    struct wined3d_resource *resource = view->resource;
     struct wined3d_fb_state fb = {&view, NULL};
+    struct wined3d_blitter *next;
+
+    if (resource->pool == WINED3D_POOL_SYSTEM_MEM)
+        goto next;
 
     if (flags != WINED3DCLEAR_TARGET)
     {
@@ -2579,10 +2604,29 @@ static void ffp_blit_clear(struct wined3d_device *device, struct wined3d_rendert
         return;
     }
 
+    if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
+    {
+        if (!((view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE)
+                || (resource->usage & WINED3DUSAGE_RENDERTARGET)))
+            goto next;
+    }
+    else if (!(resource->usage & WINED3DUSAGE_RENDERTARGET))
+    {
+        goto next;
+    }
+
+    /* FIXME: We should reject colour fills on formats with fixups, but this
+     * would break P8 colour fills for example. */
+
     device_clear_render_targets(device, 1, &fb, 1, rect, &draw_rect, flags, colour, 0.0f, 0);
+    return;
+
+next:
+    if ((next = blitter->next))
+        next->ops->blitter_clear(next, device, view, rect, flags, colour, depth, stencil);
 }
 
-static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op,
+static void ffp_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
         struct wined3d_context *context, struct wined3d_surface *src_surface, DWORD src_location,
         const RECT *src_rect, struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect,
         const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
@@ -2590,10 +2634,27 @@ static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_bl
     struct wined3d_texture *src_texture = src_surface->container;
     struct wined3d_texture *dst_texture = dst_surface->container;
     const struct wined3d_gl_info *gl_info = context->gl_info;
+    struct wined3d_resource *src_resource, *dst_resource;
     struct wined3d_color_key old_blt_key;
+    struct wined3d_device *device;
+    struct wined3d_blitter *next;
     DWORD old_color_key_flags;
     RECT r;
 
+    src_resource = &src_texture->resource;
+    dst_resource = &dst_texture->resource;
+    device = dst_resource->device;
+
+    if (!ffp_blit_supported(&device->adapter->gl_info, &device->adapter->d3d_info, op,
+            src_resource->usage, src_resource->pool, src_resource->format,
+            dst_resource->usage, dst_resource->pool, dst_resource->format))
+    {
+        if ((next = blitter->next))
+            next->ops->blitter_blit(next, op, context, src_surface, src_location,
+                    src_rect, dst_surface, dst_location, dst_rect, color_key, filter);
+        return;
+    }
+
     TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
 
     old_blt_key = src_texture->async.src_blt_color_key;
@@ -2688,43 +2749,34 @@ static void ffp_blit_blit_surface(struct wined3d_device *device, enum wined3d_bl
             (old_color_key_flags & WINED3D_CKEY_SRC_BLT) ? &old_blt_key : NULL);
 }
 
-const struct wined3d_blitter_ops ffp_blit =
+static const struct wined3d_blitter_ops ffp_blitter_ops =
 {
-    ffp_blit_alloc,
-    ffp_blit_free,
-    ffp_blit_supported,
-    ffp_blit_clear,
-    ffp_blit_blit_surface,
+    ffp_blitter_destroy,
+    ffp_blitter_clear,
+    ffp_blitter_blit,
 };
 
-static HRESULT cpu_blit_alloc(struct wined3d_device *device)
+void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wined3d_gl_info *gl_info)
 {
-    return WINED3D_OK;
-}
+    struct wined3d_blitter *blitter;
 
-/* Context activation is done by the caller. */
-static void cpu_blit_free(struct wined3d_device *device)
-{
+    if (!(blitter = HeapAlloc(GetProcessHeap(), 0, sizeof(*blitter))))
+        return;
+
+    TRACE("Created blitter %p.\n", blitter);
+
+    blitter->ops = &ffp_blitter_ops;
+    blitter->next = *next;
+    *next = blitter;
 }
 
-static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info,
-        const struct wined3d_d3d_info *d3d_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,
-        const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
+/* Context activation is done by the caller. */
+static void cpu_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
 {
-    switch (blit_op)
-    {
-        case WINED3D_BLIT_OP_COLOR_BLIT:
-        case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
-        case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
-        case WINED3D_BLIT_OP_COLOR_FILL:
-        case WINED3D_BLIT_OP_DEPTH_FILL:
-        case WINED3D_BLIT_OP_DEPTH_BLIT:
-            return TRUE;
+    struct wined3d_blitter *next;
 
-        default:
-            return FALSE;
-    }
+    if ((next = blitter->next))
+        next->ops->blitter_destroy(next, context);
 }
 
 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
@@ -3361,8 +3413,9 @@ static void surface_cpu_blt_colour_fill(struct wined3d_rendertarget_view *view,
     wined3d_resource_unmap(view->resource, view->sub_resource_idx);
 }
 
-static void cpu_blit_clear(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
-        const RECT *rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
+static void cpu_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
+        struct wined3d_rendertarget_view *view, const RECT *rect, DWORD flags,
+        const struct wined3d_color *colour, float depth, DWORD stencil)
 {
     const struct wined3d_box box = {rect->left, rect->top, rect->right, rect->bottom, 0, 1};
     struct wined3d_color c = {depth, 0.0f, 0.0f, 0.0f};
@@ -3382,7 +3435,7 @@ static void cpu_blit_clear(struct wined3d_device *device, struct wined3d_rendert
     FIXME("flags %#x not implemented.\n", flags);
 }
 
-static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_blit_op op,
+static void cpu_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
         struct wined3d_context *context, struct wined3d_surface *src_surface, DWORD src_location,
         const RECT *src_rect, struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect,
         const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter)
@@ -3397,14 +3450,21 @@ static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_bl
     DWORD flags = 0;
 
     memset(&fx, 0, sizeof(fx));
-    if (op == WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST)
-    {
-        flags |= WINED3D_BLT_ALPHA_TEST;
-    }
-    else if (op == WINED3D_BLIT_OP_COLOR_BLIT_CKEY)
+    switch (op)
     {
-        flags |= WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_FX;
-        fx.src_color_key = *color_key;
+        case WINED3D_BLIT_OP_COLOR_BLIT:
+        case WINED3D_BLIT_OP_DEPTH_BLIT:
+            break;
+        case WINED3D_BLIT_OP_COLOR_BLIT_ALPHATEST:
+            flags |= WINED3D_BLT_ALPHA_TEST;
+            break;
+        case WINED3D_BLIT_OP_COLOR_BLIT_CKEY:
+            flags |= WINED3D_BLT_SRC_CKEY_OVERRIDE | WINED3D_BLT_FX;
+            fx.src_color_key = *color_key;
+            break;
+        default:
+            FIXME("Unhandled op %#x.\n", op);
+            break;
     }
 
     if (FAILED(surface_cpu_blt(dst_texture, dst_sub_resource_idx, &dst_box,
@@ -3413,15 +3473,28 @@ static void cpu_blit_blit_surface(struct wined3d_device *device, enum wined3d_bl
     wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
 }
 
-const struct wined3d_blitter_ops cpu_blit =
+static const struct wined3d_blitter_ops cpu_blitter_ops =
 {
-    cpu_blit_alloc,
-    cpu_blit_free,
-    cpu_blit_supported,
-    cpu_blit_clear,
-    cpu_blit_blit_surface,
+    cpu_blitter_destroy,
+    cpu_blitter_clear,
+    cpu_blitter_blit,
 };
 
+struct wined3d_blitter *wined3d_cpu_blitter_create(void)
+{
+    struct wined3d_blitter *blitter;
+
+    if (!(blitter = HeapAlloc(GetProcessHeap(), 0, sizeof(*blitter))))
+        return NULL;
+
+    TRACE("Created blitter %p.\n", blitter);
+
+    blitter->ops = &cpu_blitter_ops;
+    blitter->next = NULL;
+
+    return blitter;
+}
+
 HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
         const struct wined3d_blt_fx *fx, enum wined3d_texture_filter_type filter)
@@ -3435,6 +3508,7 @@ HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst
     struct wined3d_device *device = dst_texture->resource.device;
     struct wined3d_swapchain *src_swapchain, *dst_swapchain;
     DWORD src_ds_flags, dst_ds_flags;
+    struct wined3d_context *context;
     BOOL scale, convert;
     DWORD dst_location;
 
@@ -3533,39 +3607,29 @@ HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst
 
     if (src_ds_flags || dst_ds_flags)
     {
-        const struct wined3d_blitter_ops *blitter;
-        struct wined3d_context *context;
-
         TRACE("Depth/stencil blit.\n");
 
-        if ((blitter = wined3d_select_blitter(&device->adapter->gl_info,
-                &device->adapter->d3d_info, WINED3D_BLIT_OP_DEPTH_BLIT,
-                src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
-                dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format)))
-        {
-            if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
-                dst_location = dst_texture->resource.map_binding;
-            else
-                dst_location = dst_texture->resource.draw_binding;
+        if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
+            dst_location = dst_texture->resource.map_binding;
+        else
+            dst_location = dst_texture->resource.draw_binding;
 
-            context = context_acquire(device, dst_texture, dst_sub_resource_idx);
-            blitter->blit_surface(device, WINED3D_BLIT_OP_DEPTH_BLIT, context,
-                    src_surface, src_texture->resource.draw_binding, src_rect,
-                    dst_surface, dst_location, dst_rect, NULL, filter);
-            context_release(context);
+        context = context_acquire(device, dst_texture, dst_sub_resource_idx);
+        device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_DEPTH_BLIT, context,
+                src_surface, src_texture->resource.draw_binding, src_rect,
+                dst_surface, dst_location, dst_rect, NULL, filter);
+        context_release(context);
 
-            wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
-            wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
+        wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
+        wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
 
-            return WINED3D_OK;
-        }
+        return WINED3D_OK;
     }
     else
     {
         struct wined3d_texture_sub_resource *src_sub_resource, *dst_sub_resource;
         enum wined3d_blit_op blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
         const struct wined3d_color_key *colour_key = NULL;
-        const struct wined3d_blitter_ops *blitter;
 
         TRACE("Colour blit.\n");
 
@@ -3615,7 +3679,7 @@ HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst
                 {
                     if (!wined3d_resource_is_offscreen(&dst_texture->resource))
                     {
-                        struct wined3d_context *context = context_acquire(device,
+                        context = context_acquire(device,
                                 dst_texture, dst_sub_resource_idx);
                         wined3d_texture_load_location(dst_texture, dst_sub_resource_idx,
                                 context, dst_texture->resource.draw_binding);
@@ -3648,28 +3712,21 @@ HRESULT wined3d_surface_blt(struct wined3d_surface *dst_surface, const RECT *dst
             return WINED3D_OK;
         }
 
-        if ((blitter = wined3d_select_blitter(&device->adapter->gl_info, &device->adapter->d3d_info, blit_op,
-                src_rect, src_texture->resource.usage, src_texture->resource.pool, src_texture->resource.format,
-                dst_rect, dst_texture->resource.usage, dst_texture->resource.pool, dst_texture->resource.format)))
-        {
-            struct wined3d_context *context;
-
-            if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
-                dst_location = dst_texture->resource.map_binding;
-            else
-                dst_location = dst_texture->resource.draw_binding;
+        if (dst_texture->resource.pool == WINED3D_POOL_SYSTEM_MEM)
+            dst_location = dst_texture->resource.map_binding;
+        else
+            dst_location = dst_texture->resource.draw_binding;
 
-            context = context_acquire(device, dst_texture, dst_sub_resource_idx);
-            blitter->blit_surface(device, blit_op, context,
-                    src_surface, src_texture->resource.draw_binding, src_rect,
-                    dst_surface, dst_location, dst_rect, colour_key, filter);
-            context_release(context);
+        context = context_acquire(device, dst_texture, dst_sub_resource_idx);
+        device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
+                src_surface, src_texture->resource.draw_binding, src_rect,
+                dst_surface, dst_location, dst_rect, colour_key, filter);
+        context_release(context);
 
-            wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
-            wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
+        wined3d_texture_validate_location(dst_texture, dst_sub_resource_idx, dst_location);
+        wined3d_texture_invalidate_location(dst_texture, dst_sub_resource_idx, ~dst_location);
 
-            return WINED3D_OK;
-        }
+        return WINED3D_OK;
     }
 
 fallback:
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 07ca476..454a775 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -306,22 +306,12 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
     struct wined3d_texture *texture = swapchain->back_buffers[0];
     struct wined3d_surface *back_buffer = texture->sub_resources[0].u.surface;
     struct wined3d_device *device = swapchain->device;
-    const struct wined3d_blitter_ops *blitter;
     enum wined3d_texture_filter_type filter;
     DWORD location;
 
     TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n",
             swapchain, context, wine_dbgstr_rect(src_rect), wine_dbgstr_rect(dst_rect));
 
-    if (!(blitter = wined3d_select_blitter(&device->adapter->gl_info,
-            &device->adapter->d3d_info, WINED3D_BLIT_OP_COLOR_BLIT,
-            src_rect, texture->resource.usage, texture->resource.pool, texture->resource.format,
-            dst_rect, texture->resource.usage, texture->resource.pool, texture->resource.format)))
-    {
-        FIXME("No blitter supports the requested blit.\n");
-        return;
-    }
-
     if ((src_rect->right - src_rect->left == dst_rect->right - dst_rect->left
             && src_rect->bottom - src_rect->top == dst_rect->bottom - dst_rect->top)
             || is_complex_fixup(texture->resource.format->color_fixup))
@@ -334,8 +324,8 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
         location = WINED3D_LOCATION_RB_RESOLVED;
 
     wined3d_texture_validate_location(texture, 0, WINED3D_LOCATION_DRAWABLE);
-    blitter->blit_surface(device, WINED3D_BLIT_OP_COLOR_BLIT, context, back_buffer, location,
-            src_rect, back_buffer, WINED3D_LOCATION_DRAWABLE, dst_rect, NULL, filter);
+    device->blitter->ops->blitter_blit(device->blitter, WINED3D_BLIT_OP_COLOR_BLIT, context, back_buffer,
+            location, src_rect, back_buffer, WINED3D_LOCATION_DRAWABLE, dst_rect, NULL, filter);
     wined3d_texture_invalidate_location(texture, 0, WINED3D_LOCATION_DRAWABLE);
 }
 
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index e773129..959635b 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -5794,37 +5794,6 @@ int wined3d_ffp_vertex_program_key_compare(const void *key, const struct wine_rb
     return memcmp(ka, kb, sizeof(*ka));
 }
 
-const struct wined3d_blitter_ops *wined3d_select_blitter(const struct wined3d_gl_info *gl_info,
-        const struct wined3d_d3d_info *d3d_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,
-        const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
-{
-    static const struct wined3d_blitter_ops * const blitters[] =
-    {
-        &fbo_blitter_ops,
-        &arbfp_blit,
-        &ffp_blit,
-        &cpu_blit,
-    };
-    unsigned int i;
-
-    TRACE("gl_info %p, d3d_info %p, blit_op %#x, src_rect %s, src_usage %s, src_pool %s, src_format %s, "
-            "dst_rect %s, dst_usage %s, dst_pool %s, dst_format %s.\n", gl_info, d3d_info, blit_op,
-            wine_dbgstr_rect(src_rect), debug_d3dusage(src_usage), debug_d3dpool(src_pool),
-            src_format ? debug_d3dformat(src_format->id) : "(null)", wine_dbgstr_rect(dst_rect),
-            debug_d3dusage(dst_usage), debug_d3dpool(dst_pool), debug_d3dformat(dst_format->id));
-
-    for (i = 0; i < sizeof(blitters) / sizeof(*blitters); ++i)
-    {
-        if (blitters[i]->blit_supported(gl_info, d3d_info, blit_op,
-                src_rect, src_usage, src_pool, src_format,
-                dst_rect, dst_usage, dst_pool, dst_format))
-            return blitters[i];
-    }
-
-    return NULL;
-}
-
 void wined3d_get_draw_rect(const struct wined3d_state *state, RECT *rect)
 {
     const struct wined3d_viewport *vp = &state->viewport;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 9a388ac..799f63b 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1867,33 +1867,33 @@ enum wined3d_blit_op
     WINED3D_BLIT_OP_DEPTH_BLIT,
 };
 
+struct wined3d_blitter
+{
+    const struct wined3d_blitter_ops *ops;
+    struct wined3d_blitter *next;
+};
+
 struct wined3d_blitter_ops
 {
-    HRESULT (*alloc_private)(struct wined3d_device *device);
-    void (*free_private)(struct wined3d_device *device);
-    BOOL (*blit_supported)(const struct wined3d_gl_info *gl_info,
-            const struct wined3d_d3d_info *d3d_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,
-            const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format);
-    void (*blitter_clear)(struct wined3d_device *device, struct wined3d_rendertarget_view *view,
-            const RECT *rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil);
-    void (*blit_surface)(struct wined3d_device *device, enum wined3d_blit_op op, struct wined3d_context *context,
+    void (*blitter_destroy)(struct wined3d_blitter *blitter, struct wined3d_context *context);
+    void (*blitter_clear)(struct wined3d_blitter *blitter, struct wined3d_device *device,
+            struct wined3d_rendertarget_view *view, const RECT *rect, DWORD flags,
+            const struct wined3d_color *colour, float depth, DWORD stencil);
+    void (*blitter_blit)(struct wined3d_blitter *blitter, enum wined3d_blit_op op, struct wined3d_context *context,
             struct wined3d_surface *src_surface, DWORD src_location, const RECT *src_rect,
             struct wined3d_surface *dst_surface, DWORD dst_location, const RECT *dst_rect,
             const struct wined3d_color_key *color_key, enum wined3d_texture_filter_type filter);
 };
 
-extern const struct wined3d_blitter_ops fbo_blitter_ops DECLSPEC_HIDDEN;
-extern const struct wined3d_blitter_ops arbfp_blit DECLSPEC_HIDDEN;
-extern const struct wined3d_blitter_ops ffp_blit DECLSPEC_HIDDEN;
-extern const struct wined3d_blitter_ops cpu_blit DECLSPEC_HIDDEN;
+void wined3d_arbfp_blitter_create(struct wined3d_blitter **next,
+        const struct wined3d_device *device) DECLSPEC_HIDDEN;
+struct wined3d_blitter *wined3d_cpu_blitter_create(void) DECLSPEC_HIDDEN;
+void wined3d_fbo_blitter_create(struct wined3d_blitter **next,
+        const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN;
+void wined3d_ffp_blitter_create(struct wined3d_blitter **next,
+        const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN;
 
 BOOL wined3d_clip_blit(const RECT *clip_rect, RECT *clipped, RECT *other) DECLSPEC_HIDDEN;
-const struct wined3d_blitter_ops *wined3d_select_blitter(const struct wined3d_gl_info *gl_info,
-        const struct wined3d_d3d_info *d3d_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,
-        const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
-        DECLSPEC_HIDDEN;
 
 struct wined3d_context *context_acquire(const struct wined3d_device *device,
         struct wined3d_texture *texture, unsigned int sub_resource_idx) DECLSPEC_HIDDEN;
@@ -2361,7 +2361,6 @@ struct wined3d_adapter
     const struct wined3d_vertex_pipe_ops *vertex_pipe;
     const struct fragment_pipeline *fragment_pipe;
     const struct wined3d_shader_backend_ops *shader_backend;
-    const struct wined3d_blitter_ops *blitter;
 };
 
 struct wined3d_caps_gl_ctx
@@ -2624,11 +2623,10 @@ struct wined3d_device
     void *shader_priv;
     void *fragment_priv;
     void *vertex_priv;
-    void *blit_priv;
     struct StateEntry StateTable[STATE_HIGHEST + 1];
     /* Array of functions for states which are handled by more than one pipeline part */
     APPLYSTATEFUNC *multistate_funcs[STATE_HIGHEST + 1];
-    const struct wined3d_blitter_ops *blitter;
+    struct wined3d_blitter *blitter;
 
     BYTE vertexBlendUsed : 1;           /* To avoid needless setting of the blend matrices */
     BYTE bCursorVisible : 1;
-- 
2.1.4




More information about the wine-patches mailing list