[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