[PATCH 4/5] wined3d: Move the FBO blitter to texture.c.

Henri Verbeet hverbeet at codeweavers.com
Wed Apr 22 16:34:57 CDT 2020


Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/surface.c         | 370 -------------------------------
 dlls/wined3d/texture.c         | 382 +++++++++++++++++++++++++++++++++
 dlls/wined3d/wined3d_private.h |   9 -
 3 files changed, 382 insertions(+), 379 deletions(-)

diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 2c072454f32..0dd8c4266b6 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -57,265 +57,6 @@ static BOOL texture2d_is_full_rect(const struct wined3d_texture *texture, unsign
     return TRUE;
 }
 
-static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
-        struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
-        const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
-        DWORD dst_location, const RECT *dst_rect)
-{
-    struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
-    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
-    DWORD src_mask, dst_mask;
-    GLbitfield gl_mask;
-
-    TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
-            "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
-            src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
-            dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
-
-    src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
-    dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
-
-    if (src_mask != dst_mask)
-    {
-        ERR("Incompatible formats %s and %s.\n",
-                debug_d3dformat(src_texture->resource.format->id),
-                debug_d3dformat(dst_texture->resource.format->id));
-        return;
-    }
-
-    if (!src_mask)
-    {
-        ERR("Not a depth / stencil format: %s.\n",
-                debug_d3dformat(src_texture->resource.format->id));
-        return;
-    }
-
-    gl_mask = 0;
-    if (src_mask & WINED3DFMT_FLAG_DEPTH)
-        gl_mask |= GL_DEPTH_BUFFER_BIT;
-    if (src_mask & WINED3DFMT_FLAG_STENCIL)
-        gl_mask |= GL_STENCIL_BUFFER_BIT;
-
-    /* Make sure the locations are up-to-date. Loading the destination
-     * surface isn't required if the entire surface is overwritten. */
-    wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
-    if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
-        wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
-    else
-        wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
-
-    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0,
-            &src_texture->resource, src_sub_resource_idx, src_location);
-    wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
-
-    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER, NULL, 0,
-            &dst_texture->resource, dst_sub_resource_idx, dst_location);
-    wined3d_context_gl_set_draw_buffer(context_gl, GL_NONE);
-    wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
-    context_invalidate_state(context, STATE_FRAMEBUFFER);
-
-    if (gl_mask & GL_DEPTH_BUFFER_BIT)
-    {
-        gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
-        context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
-    }
-    if (gl_mask & GL_STENCIL_BUFFER_BIT)
-    {
-        if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
-        {
-            gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
-            context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
-        }
-        gl_info->gl_ops.gl.p_glStencilMask(~0U);
-        context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
-    }
-
-    gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
-    context_invalidate_state(context, STATE_RASTERIZER);
-
-    gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
-            dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
-    checkGLcall("glBlitFramebuffer()");
-}
-
-/* Blit between surface locations. Onscreen on different swapchains is not supported.
- * Depth / stencil is not supported. Context activation is done by the caller. */
-void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
-        enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
-        unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
-        struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
-        const RECT *dst_rect)
-{
-    struct wined3d_texture *required_texture, *restore_texture;
-    const struct wined3d_gl_info *gl_info;
-    struct wined3d_context_gl *context_gl;
-    unsigned int restore_idx;
-    BOOL scaled_resolve;
-    GLenum gl_filter;
-    GLenum buffer;
-    RECT s, d;
-
-    TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
-            "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n",
-            device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
-            wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
-            dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
-
-    scaled_resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location)
-            && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
-            || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
-
-    if (filter == WINED3D_TEXF_LINEAR)
-        gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR;
-    else
-        gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
-
-    /* Make sure the locations are up-to-date. Loading the destination
-     * surface isn't required if the entire surface is overwritten. (And is
-     * in fact harmful if we're being called by surface_load_location() with
-     * the purpose of loading the destination surface.) */
-    wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
-    if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
-        wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
-    else
-        wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
-
-    /* Acquire a context for the front-buffer, even though we may be blitting
-     * to/from a back-buffer. Since context_acquire() doesn't take the
-     * resource location into account, it may consider the back-buffer to be
-     * offscreen. */
-    if (src_location == WINED3D_LOCATION_DRAWABLE)
-        required_texture = src_texture->swapchain->front_buffer;
-    else if (dst_location == WINED3D_LOCATION_DRAWABLE)
-        required_texture = dst_texture->swapchain->front_buffer;
-    else
-        required_texture = NULL;
-
-    restore_texture = context->current_rt.texture;
-    restore_idx = context->current_rt.sub_resource_idx;
-    if (restore_texture != required_texture)
-        context = context_acquire(device, required_texture, 0);
-    else
-        restore_texture = NULL;
-
-    context_gl = wined3d_context_gl(context);
-    if (!context_gl->valid)
-    {
-        context_release(context);
-        WARN("Invalid context, skipping blit.\n");
-        return;
-    }
-
-    gl_info = context_gl->gl_info;
-
-    if (src_location == WINED3D_LOCATION_DRAWABLE)
-    {
-        TRACE("Source texture %p is onscreen.\n", src_texture);
-        buffer = wined3d_texture_get_gl_buffer(src_texture);
-        s = *src_rect;
-        wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s);
-        src_rect = &s;
-    }
-    else
-    {
-        TRACE("Source texture %p is offscreen.\n", src_texture);
-        buffer = GL_COLOR_ATTACHMENT0;
-    }
-
-    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER,
-            &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
-    gl_info->gl_ops.gl.p_glReadBuffer(buffer);
-    checkGLcall("glReadBuffer()");
-    wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
-
-    if (dst_location == WINED3D_LOCATION_DRAWABLE)
-    {
-        TRACE("Destination texture %p is onscreen.\n", dst_texture);
-        buffer = wined3d_texture_get_gl_buffer(dst_texture);
-        d = *dst_rect;
-        wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d);
-        dst_rect = &d;
-    }
-    else
-    {
-        TRACE("Destination texture %p is offscreen.\n", dst_texture);
-        buffer = GL_COLOR_ATTACHMENT0;
-    }
-
-    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER,
-            &dst_texture->resource, dst_sub_resource_idx, NULL, 0, dst_location);
-    wined3d_context_gl_set_draw_buffer(context_gl, buffer);
-    wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
-    context_invalidate_state(context, STATE_FRAMEBUFFER);
-
-    gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-    context_invalidate_state(context, STATE_BLEND);
-
-    gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
-    context_invalidate_state(context, STATE_RASTERIZER);
-
-    gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
-            dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter);
-    checkGLcall("glBlitFramebuffer()");
-
-    if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
-        gl_info->gl_ops.gl.p_glFlush();
-
-    if (restore_texture)
-        context_restore(context, restore_texture, restore_idx);
-}
-
-BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
-        const struct wined3d_resource *src_resource, DWORD src_location,
-        const struct wined3d_resource *dst_resource, DWORD dst_location)
-{
-    const struct wined3d_format *src_format = src_resource->format;
-    const struct wined3d_format *dst_format = dst_resource->format;
-
-    if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
-        return FALSE;
-
-    /* Source and/or destination need to be on the GL side */
-    if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
-        return FALSE;
-
-    if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
-        return FALSE;
-
-    switch (blit_op)
-    {
-        case WINED3D_BLIT_OP_COLOR_BLIT:
-            if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
-                    || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
-                return FALSE;
-            if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
-                    || (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
-                return FALSE;
-            if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
-                    && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
-                return FALSE;
-            break;
-
-        case WINED3D_BLIT_OP_DEPTH_BLIT:
-            if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
-                return FALSE;
-            if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
-                return FALSE;
-            /* Accept pure swizzle fixups for depth formats. In general we
-             * ignore the stencil component (if present) at the moment and the
-             * swizzle is not relevant with just the depth component. */
-            if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
-                    || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
-                return FALSE;
-            break;
-
-        default:
-            return FALSE;
-    }
-
-    return TRUE;
-}
-
 /* See also float_16_to_32() in wined3d_private.h */
 static inline unsigned short float_32_to_16(const float *in)
 {
@@ -859,117 +600,6 @@ void texture2d_load_fb_texture(struct wined3d_texture_gl *texture_gl,
         context_restore(context, restore_texture, restore_idx);
 }
 
-/* Context activation is done by the caller. */
-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);
-
-    heap_free(blitter);
-}
-
-static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
-        unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
-        const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
-{
-    struct wined3d_blitter *next;
-
-    if ((next = blitter->next))
-        next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
-                clear_rects, draw_rect, flags, colour, depth, stencil);
-}
-
-static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
-        struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
-        DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
-        unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
-        const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
-{
-    struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
-    struct wined3d_resource *src_resource, *dst_resource;
-    enum wined3d_blit_op blit_op = op;
-    struct wined3d_device *device;
-    struct wined3d_blitter *next;
-
-    TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
-            "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
-            blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
-            wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
-            wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
-
-    src_resource = &src_texture->resource;
-    dst_resource = &dst_texture->resource;
-
-    device = dst_resource->device;
-
-    if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
-    {
-        if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
-            blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
-        else
-            blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
-    }
-
-    if (!fbo_blitter_supported(blit_op, context_gl->gl_info,
-            src_resource, src_location, dst_resource, dst_location))
-    {
-        if (!(next = blitter->next))
-        {
-            ERR("No blitter to handle blit op %#x.\n", op);
-            return dst_location;
-        }
-
-        TRACE("Forwarding to blitter %p.\n", next);
-        return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
-                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
-    }
-
-    if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
-    {
-        TRACE("Colour blit.\n");
-        texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
-                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
-        return dst_location;
-    }
-
-    if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
-    {
-        TRACE("Depth/stencil blit.\n");
-        texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
-                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
-        return dst_location;
-    }
-
-    ERR("This blitter does not implement blit op %#x.\n", blit_op);
-    return dst_location;
-}
-
-static const struct wined3d_blitter_ops fbo_blitter_ops =
-{
-    fbo_blitter_destroy,
-    fbo_blitter_clear,
-    fbo_blitter_blit,
-};
-
-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 = heap_alloc(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 raw_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_context *context)
 {
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index c11490057c3..0036607005c 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -48,6 +48,19 @@ struct wined3d_rect_f
     float b;
 };
 
+static bool texture2d_is_full_rect(const struct wined3d_texture *texture, unsigned int level, const RECT *r)
+{
+    unsigned int t;
+
+    t = wined3d_texture_get_level_width(texture, level);
+    if ((r->left && r->right) || abs(r->right - r->left) != t)
+        return false;
+    t = wined3d_texture_get_level_height(texture, level);
+    if ((r->top && r->bottom) || abs(r->bottom - r->top) != t)
+        return false;
+    return true;
+}
+
 static BOOL wined3d_texture_use_pbo(const struct wined3d_texture *texture, const struct wined3d_gl_info *gl_info)
 {
     if (!gl_info->supported[ARB_PIXEL_BUFFER_OBJECT]
@@ -265,6 +278,265 @@ void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl,
     }
 }
 
+static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
+        const struct wined3d_resource *src_resource, DWORD src_location,
+        const struct wined3d_resource *dst_resource, DWORD dst_location)
+{
+    const struct wined3d_format *src_format = src_resource->format;
+    const struct wined3d_format *dst_format = dst_resource->format;
+
+    if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
+        return false;
+
+    /* Source and/or destination need to be on the GL side. */
+    if (!(src_resource->access & dst_resource->access & WINED3D_RESOURCE_ACCESS_GPU))
+        return false;
+
+    if (src_resource->type != WINED3D_RTYPE_TEXTURE_2D)
+        return false;
+
+    switch (blit_op)
+    {
+        case WINED3D_BLIT_OP_COLOR_BLIT:
+            if (!((src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
+                    || (src_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
+                return false;
+            if (!((dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & WINED3DFMT_FLAG_FBO_ATTACHABLE)
+                    || (dst_resource->bind_flags & WINED3D_BIND_RENDER_TARGET)))
+                return false;
+            if ((src_format->id != dst_format->id || dst_location == WINED3D_LOCATION_DRAWABLE)
+                    && (!is_identity_fixup(src_format->color_fixup) || !is_identity_fixup(dst_format->color_fixup)))
+                return false;
+            break;
+
+        case WINED3D_BLIT_OP_DEPTH_BLIT:
+            if (!(src_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
+                return false;
+            if (!(dst_format->flags[WINED3D_GL_RES_TYPE_TEX_2D] & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
+                return false;
+            /* Accept pure swizzle fixups for depth formats. In general we
+             * ignore the stencil component (if present) at the moment and the
+             * swizzle is not relevant with just the depth component. */
+            if (is_complex_fixup(src_format->color_fixup) || is_complex_fixup(dst_format->color_fixup)
+                    || is_scaling_fixup(src_format->color_fixup) || is_scaling_fixup(dst_format->color_fixup))
+                return false;
+            break;
+
+        default:
+            return false;
+    }
+
+    return true;
+}
+
+/* Blit between surface locations. Onscreen on different swapchains is not supported.
+ * Depth / stencil is not supported. Context activation is done by the caller. */
+static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
+        enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
+        unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
+        struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
+        const RECT *dst_rect)
+{
+    struct wined3d_texture *required_texture, *restore_texture;
+    const struct wined3d_gl_info *gl_info;
+    struct wined3d_context_gl *context_gl;
+    unsigned int restore_idx;
+    bool scaled_resolve;
+    GLenum gl_filter;
+    GLenum buffer;
+    RECT s, d;
+
+    TRACE("device %p, context %p, filter %s, src_texture %p, src_sub_resource_idx %u, src_location %s, "
+            "src_rect %s, dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n",
+            device, context, debug_d3dtexturefiltertype(filter), src_texture, src_sub_resource_idx,
+            wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect), dst_texture,
+            dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
+
+    scaled_resolve = wined3d_texture_gl_is_multisample_location(wined3d_texture_gl(src_texture), src_location)
+            && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
+            || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
+
+    if (filter == WINED3D_TEXF_LINEAR)
+        gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR;
+    else
+        gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_FASTEST_EXT : GL_NEAREST;
+
+    /* Make sure the locations are up-to-date. Loading the destination
+     * surface isn't required if the entire surface is overwritten. (And is
+     * in fact harmful if we're being called by surface_load_location() with
+     * the purpose of loading the destination surface.) */
+    wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
+    if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
+        wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
+    else
+        wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
+
+    /* Acquire a context for the front-buffer, even though we may be blitting
+     * to/from a back-buffer. Since context_acquire() doesn't take the
+     * resource location into account, it may consider the back-buffer to be
+     * offscreen. */
+    if (src_location == WINED3D_LOCATION_DRAWABLE)
+        required_texture = src_texture->swapchain->front_buffer;
+    else if (dst_location == WINED3D_LOCATION_DRAWABLE)
+        required_texture = dst_texture->swapchain->front_buffer;
+    else
+        required_texture = NULL;
+
+    restore_texture = context->current_rt.texture;
+    restore_idx = context->current_rt.sub_resource_idx;
+    if (restore_texture != required_texture)
+        context = context_acquire(device, required_texture, 0);
+    else
+        restore_texture = NULL;
+
+    context_gl = wined3d_context_gl(context);
+    if (!context_gl->valid)
+    {
+        context_release(context);
+        WARN("Invalid context, skipping blit.\n");
+        return;
+    }
+
+    gl_info = context_gl->gl_info;
+
+    if (src_location == WINED3D_LOCATION_DRAWABLE)
+    {
+        TRACE("Source texture %p is onscreen.\n", src_texture);
+        buffer = wined3d_texture_get_gl_buffer(src_texture);
+        s = *src_rect;
+        wined3d_texture_translate_drawable_coords(src_texture, context_gl->window, &s);
+        src_rect = &s;
+    }
+    else
+    {
+        TRACE("Source texture %p is offscreen.\n", src_texture);
+        buffer = GL_COLOR_ATTACHMENT0;
+    }
+
+    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER,
+            &src_texture->resource, src_sub_resource_idx, NULL, 0, src_location);
+    gl_info->gl_ops.gl.p_glReadBuffer(buffer);
+    checkGLcall("glReadBuffer()");
+    wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
+
+    if (dst_location == WINED3D_LOCATION_DRAWABLE)
+    {
+        TRACE("Destination texture %p is onscreen.\n", dst_texture);
+        buffer = wined3d_texture_get_gl_buffer(dst_texture);
+        d = *dst_rect;
+        wined3d_texture_translate_drawable_coords(dst_texture, context_gl->window, &d);
+        dst_rect = &d;
+    }
+    else
+    {
+        TRACE("Destination texture %p is offscreen.\n", dst_texture);
+        buffer = GL_COLOR_ATTACHMENT0;
+    }
+
+    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER,
+            &dst_texture->resource, dst_sub_resource_idx, NULL, 0, dst_location);
+    wined3d_context_gl_set_draw_buffer(context_gl, buffer);
+    wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
+    context_invalidate_state(context, STATE_FRAMEBUFFER);
+
+    gl_info->gl_ops.gl.p_glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+    context_invalidate_state(context, STATE_BLEND);
+
+    gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
+    context_invalidate_state(context, STATE_RASTERIZER);
+
+    gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
+            dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, GL_COLOR_BUFFER_BIT, gl_filter);
+    checkGLcall("glBlitFramebuffer()");
+
+    if (dst_location == WINED3D_LOCATION_DRAWABLE && dst_texture->swapchain->front_buffer == dst_texture)
+        gl_info->gl_ops.gl.p_glFlush();
+
+    if (restore_texture)
+        context_restore(context, restore_texture, restore_idx);
+}
+
+static void texture2d_depth_blt_fbo(const struct wined3d_device *device, struct wined3d_context *context,
+        struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx, DWORD src_location,
+        const RECT *src_rect, struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx,
+        DWORD dst_location, const RECT *dst_rect)
+{
+    struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
+    const struct wined3d_gl_info *gl_info = context_gl->gl_info;
+    DWORD src_mask, dst_mask;
+    GLbitfield gl_mask;
+
+    TRACE("device %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
+            "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s.\n", device,
+            src_texture, src_sub_resource_idx, wined3d_debug_location(src_location), wine_dbgstr_rect(src_rect),
+            dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location), wine_dbgstr_rect(dst_rect));
+
+    src_mask = src_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
+    dst_mask = dst_texture->resource.format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
+
+    if (src_mask != dst_mask)
+    {
+        ERR("Incompatible formats %s and %s.\n",
+                debug_d3dformat(src_texture->resource.format->id),
+                debug_d3dformat(dst_texture->resource.format->id));
+        return;
+    }
+
+    if (!src_mask)
+    {
+        ERR("Not a depth / stencil format: %s.\n",
+                debug_d3dformat(src_texture->resource.format->id));
+        return;
+    }
+
+    gl_mask = 0;
+    if (src_mask & WINED3DFMT_FLAG_DEPTH)
+        gl_mask |= GL_DEPTH_BUFFER_BIT;
+    if (src_mask & WINED3DFMT_FLAG_STENCIL)
+        gl_mask |= GL_STENCIL_BUFFER_BIT;
+
+    /* Make sure the locations are up-to-date. Loading the destination
+     * surface isn't required if the entire surface is overwritten. */
+    wined3d_texture_load_location(src_texture, src_sub_resource_idx, context, src_location);
+    if (!texture2d_is_full_rect(dst_texture, dst_sub_resource_idx % dst_texture->level_count, dst_rect))
+        wined3d_texture_load_location(dst_texture, dst_sub_resource_idx, context, dst_location);
+    else
+        wined3d_texture_prepare_location(dst_texture, dst_sub_resource_idx, context, dst_location);
+
+    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_READ_FRAMEBUFFER, NULL, 0,
+            &src_texture->resource, src_sub_resource_idx, src_location);
+    wined3d_context_gl_check_fbo_status(context_gl, GL_READ_FRAMEBUFFER);
+
+    wined3d_context_gl_apply_fbo_state_blit(context_gl, GL_DRAW_FRAMEBUFFER, NULL, 0,
+            &dst_texture->resource, dst_sub_resource_idx, dst_location);
+    wined3d_context_gl_set_draw_buffer(context_gl, GL_NONE);
+    wined3d_context_gl_check_fbo_status(context_gl, GL_DRAW_FRAMEBUFFER);
+    context_invalidate_state(context, STATE_FRAMEBUFFER);
+
+    if (gl_mask & GL_DEPTH_BUFFER_BIT)
+    {
+        gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
+        context_invalidate_state(context, STATE_RENDER(WINED3D_RS_ZWRITEENABLE));
+    }
+    if (gl_mask & GL_STENCIL_BUFFER_BIT)
+    {
+        if (gl_info->supported[EXT_STENCIL_TWO_SIDE])
+        {
+            gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
+            context_invalidate_state(context, STATE_RENDER(WINED3D_RS_TWOSIDEDSTENCILMODE));
+        }
+        gl_info->gl_ops.gl.p_glStencilMask(~0U);
+        context_invalidate_state(context, STATE_RENDER(WINED3D_RS_STENCILWRITEMASK));
+    }
+
+    gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
+    context_invalidate_state(context, STATE_RASTERIZER);
+
+    gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
+            dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
+    checkGLcall("glBlitFramebuffer()");
+}
+
 static void wined3d_texture_evict_sysmem(struct wined3d_texture *texture)
 {
     struct wined3d_texture_sub_resource *sub_resource;
@@ -5210,3 +5482,113 @@ void wined3d_ffp_blitter_create(struct wined3d_blitter **next, const struct wine
     blitter->next = *next;
     *next = blitter;
 }
+
+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);
+
+    heap_free(blitter);
+}
+
+static void fbo_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
+        unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
+        const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
+{
+    struct wined3d_blitter *next;
+
+    if ((next = blitter->next))
+        next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
+                clear_rects, draw_rect, flags, colour, depth, stencil);
+}
+
+static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
+        struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
+        DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
+        unsigned int dst_sub_resource_idx, DWORD dst_location, const RECT *dst_rect,
+        const struct wined3d_color_key *colour_key, enum wined3d_texture_filter_type filter)
+{
+    struct wined3d_context_gl *context_gl = wined3d_context_gl(context);
+    struct wined3d_resource *src_resource, *dst_resource;
+    enum wined3d_blit_op blit_op = op;
+    struct wined3d_device *device;
+    struct wined3d_blitter *next;
+
+    TRACE("blitter %p, op %#x, context %p, src_texture %p, src_sub_resource_idx %u, src_location %s, src_rect %s, "
+            "dst_texture %p, dst_sub_resource_idx %u, dst_location %s, dst_rect %s, colour_key %p, filter %s.\n",
+            blitter, op, context, src_texture, src_sub_resource_idx, wined3d_debug_location(src_location),
+            wine_dbgstr_rect(src_rect), dst_texture, dst_sub_resource_idx, wined3d_debug_location(dst_location),
+            wine_dbgstr_rect(dst_rect), colour_key, debug_d3dtexturefiltertype(filter));
+
+    src_resource = &src_texture->resource;
+    dst_resource = &dst_texture->resource;
+
+    device = dst_resource->device;
+
+    if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && dst_resource->format->id == src_resource->format->id)
+    {
+        if (dst_resource->format_flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
+            blit_op = WINED3D_BLIT_OP_DEPTH_BLIT;
+        else
+            blit_op = WINED3D_BLIT_OP_COLOR_BLIT;
+    }
+
+    if (!fbo_blitter_supported(blit_op, context_gl->gl_info,
+            src_resource, src_location, dst_resource, dst_location))
+    {
+        if (!(next = blitter->next))
+        {
+            ERR("No blitter to handle blit op %#x.\n", op);
+            return dst_location;
+        }
+
+        TRACE("Forwarding to blitter %p.\n", next);
+        return next->ops->blitter_blit(next, op, context, src_texture, src_sub_resource_idx, src_location,
+                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, colour_key, filter);
+    }
+
+    if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
+    {
+        TRACE("Colour blit.\n");
+        texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
+                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
+        return dst_location;
+    }
+
+    if (blit_op == WINED3D_BLIT_OP_DEPTH_BLIT)
+    {
+        TRACE("Depth/stencil blit.\n");
+        texture2d_depth_blt_fbo(device, context, src_texture, src_sub_resource_idx, src_location,
+                src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect);
+        return dst_location;
+    }
+
+    ERR("This blitter does not implement blit op %#x.\n", blit_op);
+    return dst_location;
+}
+
+static const struct wined3d_blitter_ops fbo_blitter_ops =
+{
+    fbo_blitter_destroy,
+    fbo_blitter_clear,
+    fbo_blitter_blit,
+};
+
+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 = heap_alloc(sizeof(*blitter))))
+        return;
+
+    TRACE("Created blitter %p.\n", blitter);
+
+    blitter->ops = &fbo_blitter_ops;
+    blitter->next = *next;
+    *next = blitter;
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b78fbde0f47..bd42e3f18b4 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2437,10 +2437,6 @@ struct wined3d_blitter *wined3d_glsl_blitter_create(struct wined3d_blitter **nex
 void wined3d_raw_blitter_create(struct wined3d_blitter **next,
         const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN;
 
-BOOL fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct wined3d_gl_info *gl_info,
-        const struct wined3d_resource *src_resource, DWORD src_location,
-        const struct wined3d_resource *dst_resource, DWORD dst_location) DECLSPEC_HIDDEN;
-
 BOOL wined3d_clip_blit(const RECT *clip_rect, RECT *clipped, RECT *other) DECLSPEC_HIDDEN;
 
 HGLRC context_create_wgl_attribs(const struct wined3d_gl_info *gl_info, HDC hdc, HGLRC share_ctx) DECLSPEC_HIDDEN;
@@ -3872,11 +3868,6 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_
         const struct wined3d_box *dst_box, struct wined3d_texture *src_texture,
         unsigned int src_sub_resource_idx, const struct wined3d_box *src_box, DWORD flags,
         const struct wined3d_blt_fx *blt_fx, enum wined3d_texture_filter_type filter) DECLSPEC_HIDDEN;
-void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
-        enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
-        unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
-        struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
-        const RECT *dst_rect) DECLSPEC_HIDDEN;
 void texture2d_get_blt_info(const struct wined3d_texture_gl *texture_gl, unsigned int sub_resource_idx,
         const RECT *rect, struct wined3d_blt_info *info) DECLSPEC_HIDDEN;
 void texture2d_load_fb_texture(struct wined3d_texture_gl *texture_gl, unsigned int sub_resource_idx,
-- 
2.20.1




More information about the wine-devel mailing list