From c13940de055c863da6491501c4ce0af8099f181f Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Tue, 19 Jan 2021 14:34:55 +0100 Subject: [PATCH] ddraw: Use BitBlt() for exclusive mode frontbuffer updates if the swapchain window is not in the foreground. Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard (cherry picked from commit 4ce1d7f93a35322d149cbde29d619e2580159a80) Signed-off-by: Michael Stefaniuc --- dlls/ddraw/surface.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index fd788a96ac0..0ca19d4f8a5 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -39,6 +39,16 @@ static BOOL ddraw_surface_is_lost(const struct ddraw_surface *surface) && (surface->ddraw->device_state != DDRAW_DEVICE_STATE_OK || surface->is_lost); } +static BOOL ddraw_gdi_is_front(struct ddraw *ddraw) +{ + struct ddraw_surface *surface; + + if (!ddraw->gdi_surface || !(surface = wined3d_texture_get_sub_resource_parent(ddraw->gdi_surface, 0))) + return FALSE; + + return surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER; +} + /* This is slow, of course. Also, in case of locks, we can't prevent other * applications from drawing to the screen while we've locked the frontbuffer. * We'd like to do this in wined3d instead, but for that to work wined3d needs @@ -46,6 +56,7 @@ static BOOL ddraw_surface_is_lost(const struct ddraw_surface *surface) HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, const RECT *rect, BOOL read, unsigned int swap_interval) { + struct ddraw *ddraw = surface->ddraw; struct wined3d_texture *dst_texture; HDC surface_dc, screen_dc; int x, y, w, h; @@ -53,9 +64,9 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, BOOL ret; RECT r; - if (surface->ddraw->flags & DDRAW_SWAPPED && !read) + if (ddraw->flags & DDRAW_SWAPPED && !read) { - surface->ddraw->flags &= ~DDRAW_SWAPPED; + ddraw->flags &= ~DDRAW_SWAPPED; rect = NULL; } @@ -73,7 +84,23 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, if (w <= 0 || h <= 0) return DD_OK; - if (surface->ddraw->swapchain_window) + /* The interaction between ddraw and GDI drawing is not all that well + * documented, and somewhat arcane. In ddraw exclusive mode, GDI draws + * seemingly go to the *original* frontbuffer/primary surface, while ddraw + * draws/flips go to the *current* frontbuffer surface. The bottom line is + * that if the current frontbuffer is not the GDI frontbuffer, and there's + * e.g. a popup window in front of the ddraw swapchain window, we can't + * use wined3d_swapchain_present() to get the ddraw contents to the screen + * while in exclusive mode, since it would get obscured by the popup + * window. On the other hand, if the current frontbuffer *is* the GDI + * frontbuffer, that's what's supposed to happen; the popup should obscure + * (oart of) the ddraw swapchain window. + * + * This affects the "Deer Hunter" demo, which uses a popup window and GDI + * draws to draw part of the user interface. See also the "fswindow" + * sample is the DirectX 7 SDK. */ + if (ddraw->swapchain_window && (!(ddraw->cooperative_level & DDSCL_EXCLUSIVE) + || ddraw->swapchain_window == GetForegroundWindow() || ddraw_gdi_is_front(ddraw))) { /* Nothing to do, we control the frontbuffer, or at least the parts we * care about. */ @@ -81,15 +108,15 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, return DD_OK; if (swap_interval) - dst_texture = wined3d_swapchain_get_back_buffer(surface->ddraw->wined3d_swapchain, 0); + dst_texture = wined3d_swapchain_get_back_buffer(ddraw->wined3d_swapchain, 0); else - dst_texture = surface->ddraw->wined3d_frontbuffer; + dst_texture = ddraw->wined3d_frontbuffer; if (SUCCEEDED(hr = wined3d_texture_blt(dst_texture, 0, rect, surface->wined3d_texture, surface->sub_resource_idx, rect, 0, NULL, WINED3D_TEXF_POINT)) && swap_interval) { - hr = wined3d_swapchain_present(surface->ddraw->wined3d_swapchain, rect, rect, NULL, swap_interval, 0); - surface->ddraw->flags |= DDRAW_SWAPPED; + hr = wined3d_swapchain_present(ddraw->wined3d_swapchain, rect, rect, NULL, swap_interval, 0); + ddraw->flags |= DDRAW_SWAPPED; } return hr; }