[PATCH 3/4] wined3d: Clip blits from / to the front buffer to the GL drawable.

Stefan Dösinger stefan at codeweavers.com
Tue Jul 7 09:26:32 CDT 2015


Currently this change doesn't matter all that much because the only blit
operation that accesses the front buffer is the shadow FB -> real FB
blit in ddraw, and this one is ideally already clipped (if not we go
through BitBlt). This will matter once swapchain_present blits go
through wined3d_surface_blt and the shadow frontbuffer is moved to
wined3d.

wined3d_clip_blit will also be useful for drawing the software mouse
cursor.
---
 dlls/wined3d/arb_program_shader.c | 10 ++++++--
 dlls/wined3d/surface.c            | 54 ++++++++++++++++++++++++++++++---------
 dlls/wined3d/utils.c              | 22 ++++++++++++++++
 dlls/wined3d/wined3d_private.h    |  4 ++-
 4 files changed, 75 insertions(+), 15 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 0bd7c22..4842dc3 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -7840,8 +7840,14 @@ static void arbfp_blit_surface(struct wined3d_device *device, DWORD filter,
 
     context_apply_blit_state(context, device);
 
-    if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
-        surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
+    if (!wined3d_resource_is_offscreen(&dst_surface->container->resource)
+            && !surface_clip_drawable_coords(dst_surface, context->win_handle,
+            &dst_rect, &src_rect))
+    {
+        TRACE("Empty front buffer write.\n");
+        context_release(context);
+        return;
+    }
 
     arbfp_blit_set(device->blit_priv, context, src_surface, color_key);
 
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index c6d5a5a..597ddca 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -924,7 +924,12 @@ static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_te
     {
         TRACE("Source surface %p is onscreen.\n", src_surface);
         buffer = surface_get_gl_buffer(src_surface);
-        surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
+        if (!surface_clip_drawable_coords(src_surface, context->win_handle, &src_rect, &dst_rect))
+        {
+            TRACE("Empty front buffer read.\n");
+            context_release(context);
+            return;
+        }
     }
     else
     {
@@ -941,7 +946,11 @@ static void surface_blt_fbo(const struct wined3d_device *device, enum wined3d_te
     {
         TRACE("Destination surface %p is onscreen.\n", dst_surface);
         buffer = surface_get_gl_buffer(dst_surface);
-        surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
+        if (!surface_clip_drawable_coords(dst_surface, context->win_handle, &dst_rect, &src_rect))
+        {
+            TRACE("Empty front buffer write.\n");
+            context_release(context);
+        }
     }
     else
     {
@@ -3332,28 +3341,44 @@ static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, st
  * drawable is limited to the window's client area. The sysmem and texture
  * copies do have the full screen size. Note that GL has a bottom-left
  * origin, while D3D has a top-left origin. */
-void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
+BOOL surface_clip_drawable_coords(const struct wined3d_surface *surface, HWND window,
+        RECT *screen_rect, RECT *other)
 {
     UINT drawable_height;
 
     if (surface->container->swapchain && surface->container == surface->container->swapchain->front_buffer)
     {
         POINT offset = {0, 0};
-        RECT windowsize;
+        RECT clip_rect;
+
+        /* Get the client rectangle in screen coordinates and clip the screen coordinate
+         * rectangle. Handling the rectangle of the other surface is easier when we see
+         * the clipping difference in surface (=screen) coordinates than translated client
+         * coordinates. */
+        ClientToScreen(window, &offset);
+        GetClientRect(window, &clip_rect);
+        OffsetRect(&clip_rect, offset.x, offset.y);
+
+        if (!wined3d_clip_blit(&clip_rect, screen_rect, other))
+            return FALSE;
 
-        ScreenToClient(window, &offset);
-        OffsetRect(rect, offset.x, offset.y);
+        /* Finally, translate the screen coordinate rectangle to client coordinates. */
+        OffsetRect(screen_rect, -offset.x, -offset.y);
 
-        GetClientRect(window, &windowsize);
-        drawable_height = windowsize.bottom - windowsize.top;
+        drawable_height = clip_rect.bottom - clip_rect.top;
     }
     else
     {
+        if (IsRectEmpty(screen_rect))
+            return FALSE;
+
         drawable_height = surface->resource.height;
     }
 
-    rect->top = drawable_height - rect->top;
-    rect->bottom = drawable_height - rect->bottom;
+    screen_rect->top = drawable_height - screen_rect->top;
+    screen_rect->bottom = drawable_height - screen_rect->bottom;
+
+    return TRUE;
 }
 
 static void surface_blt_to_drawable(const struct wined3d_device *device,
@@ -3379,8 +3404,13 @@ static void surface_blt_to_drawable(const struct wined3d_device *device,
     /* Activate the destination context, set it up for blitting */
     context_apply_blit_state(context, device);
 
-    if (!wined3d_resource_is_offscreen(&dst_surface->container->resource))
-        surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
+    if (!wined3d_resource_is_offscreen(&dst_surface->container->resource)
+            && !surface_clip_drawable_coords(dst_surface, context->win_handle, &dst_rect, &src_rect))
+    {
+        TRACE("Empty front buffer write.\n");
+        context_release(context);
+        return;
+    }
 
     device->blitter->set_shader(device->blit_priv, context, src_surface, NULL);
 
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 48f6671..6abb1e3 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -4722,3 +4722,25 @@ void wined3d_release_dc(HWND window, HDC dc)
     else if (!ReleaseDC(window, dc))
         ERR("Failed to release device context %p, last error %#x.\n", dc, GetLastError());
 }
+
+BOOL wined3d_clip_blit(const RECT *clip_rect, RECT *clipped, RECT *other)
+{
+    RECT orig = *clipped;
+    float scale_x = (float)(orig.right - orig.left) / (float)(other->right - other->left);
+    float scale_y = (float)(orig.bottom - orig.top) / (float)(other->bottom - other->top);
+
+    IntersectRect(clipped, clipped, clip_rect);
+
+    if (IsRectEmpty(clipped))
+    {
+        SetRectEmpty(other);
+        return FALSE;
+    }
+
+    other->left += (LONG)((clipped->left - orig.left) / scale_x);
+    other->top += (LONG)((clipped->top - orig.top) / scale_y);
+    other->right -= (LONG)((orig.right - clipped->right) / scale_x);
+    other->bottom -= (LONG)((orig.bottom - clipped->bottom) / scale_y);
+
+    return TRUE;
+}
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b7fa4c6..5287baf 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1383,6 +1383,7 @@ const struct blit_shader *wined3d_select_blitter(const struct wined3d_gl_info *g
         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;
+BOOL wined3d_clip_blit(const RECT *clip_rect, RECT *clipped, RECT *other) DECLSPEC_HIDDEN;
 
 struct wined3d_context *context_acquire(const struct wined3d_device *device,
         struct wined3d_surface *target) DECLSPEC_HIDDEN;
@@ -2402,6 +2403,8 @@ static inline GLuint surface_get_texture_name(const struct wined3d_surface *surf
 }
 
 void surface_set_dirty(struct wined3d_surface *surface) DECLSPEC_HIDDEN;
+BOOL surface_clip_drawable_coords(const struct wined3d_surface *surface, HWND window,
+        RECT *screen_rect, RECT *other) DECLSPEC_HIDDEN;
 HRESULT surface_color_fill(struct wined3d_surface *s,
         const RECT *rect, const struct wined3d_color *color) DECLSPEC_HIDDEN;
 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface) DECLSPEC_HIDDEN;
@@ -2419,7 +2422,6 @@ void surface_prepare_rb(struct wined3d_surface *surface,
 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface,
         const struct wined3d_surface *rt) DECLSPEC_HIDDEN;
 void surface_set_texture_target(struct wined3d_surface *surface, GLenum target, GLint level) DECLSPEC_HIDDEN;
-void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect) DECLSPEC_HIDDEN;
 HRESULT wined3d_surface_update_desc(struct wined3d_surface *surface,
         const struct wined3d_gl_info *gl_info, void *mem, unsigned int pitch) DECLSPEC_HIDDEN;
 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
-- 
2.3.6




More information about the wine-patches mailing list