From: Stefan Dösinger Subject: [PATCH 1/4] wined3d: Clip blits from / to the front buffer to the GL drawable (v2). Message-Id: <1437128000-16472-1-git-send-email-stefan@codeweavers.com> Date: Fri, 17 Jul 2015 12:13:17 +0200 Version 2: Rename parameters of surface_clip_drawable_blit and rename the function itself. I have left the parameters of wined3d_clip_blit untouched because the call doesn't care which one is the source or destination of the blit and what the blitted surfaces are. It is only used as helper for surface_clip_drawable_blit right now but will also be used for the software cursor later. 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 | 48 +++++++++++++++++++++++++++++++-------- dlls/wined3d/utils.c | 22 ++++++++++++++++++ dlls/wined3d/wined3d_private.h | 4 +++- 4 files changed, 72 insertions(+), 12 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 0bd7c22..b471ef7 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_blit(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..57610bd 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_blit(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_blit(dst_surface, context->win_handle, &dst_rect, &src_rect)) + { + TRACE("Empty front buffer write.\n"); + context_release(context); + } } else { @@ -3332,7 +3341,8 @@ 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_blit(const struct wined3d_surface *surface, HWND window, + RECT *drawable_rect, RECT *offscreen_rect) { UINT drawable_height; @@ -3341,19 +3351,34 @@ void surface_translate_drawable_coords(const struct wined3d_surface *surface, HW POINT offset = {0, 0}; RECT windowsize; + /* Get the client rectangle in screen coordinates and clip the screen coordinate + * rectangle. Handling the rectangle of the offscreen surface is easier when we see + * the clipping difference in drawable surface (=screen) coordinates rather than + * translated client coordinates. */ ScreenToClient(window, &offset); - OffsetRect(rect, offset.x, offset.y); - GetClientRect(window, &windowsize); + OffsetRect(&windowsize, -offset.x, -offset.y); + + if (!wined3d_clip_blit(&windowsize, drawable_rect, offscreen_rect)) + return FALSE; + + /* Finally, translate the screen coordinate rectangle to client coordinates. */ + OffsetRect(drawable_rect, offset.x, offset.y); + drawable_height = windowsize.bottom - windowsize.top; } else { + if (IsRectEmpty(drawable_rect)) + return FALSE; + drawable_height = surface->resource.height; } - rect->top = drawable_height - rect->top; - rect->bottom = drawable_height - rect->bottom; + drawable_rect->top = drawable_height - drawable_rect->top; + drawable_rect->bottom = drawable_height - drawable_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_blit(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 8dd9e80..07a55ab 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1381,6 +1381,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; @@ -2401,6 +2402,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_blit(const struct wined3d_surface *surface, HWND window, + RECT *drawable_rect, RECT *offscreen_rect) 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; @@ -2418,7 +2421,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