From 3e8694f1e63a08723e165c7abf8820fc6203d299 Mon Sep 17 00:00:00 2001
From: Ken Thomases <ken@codeweavers.com>
Date: Wed, 19 Mar 2014 18:34:47 -0500
Subject: wined3d: Make use of the WGL_WINE_surface extension to avoid
 changing window state.
To: wine-patches <wine-patches@winehq.org>

---
 dlls/wined3d/context.c         |   67 ++++++++++++++++++++++++++++++++-------
 dlls/wined3d/device.c          |   42 ++++++++++++++++--------
 dlls/wined3d/directx.c         |    1 +
 dlls/wined3d/surface.c         |    3 +-
 dlls/wined3d/swapchain.c       |   61 ++++++++++++++++++++++++++++++++---
 dlls/wined3d/wined3d_gl.h      |    1 +
 dlls/wined3d/wined3d_private.h |    3 ++
 7 files changed, 145 insertions(+), 33 deletions(-)

diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 00ab25f..2dcba71 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -887,24 +887,53 @@ static void context_restore_gl_context(const struct wined3d_gl_info *gl_info, HD
     }
 }
 
-static void context_update_window(struct wined3d_context *context)
+static void context_update_drawable(struct wined3d_context *context)
 {
-    if (context->win_handle == context->swapchain->win_handle)
+    const struct wined3d_gl_info *gl_info = context->gl_info;
+
+    if (context->win_handle == context->swapchain->win_handle
+            && context->surface == context->swapchain->surface)
         return;
 
-    TRACE("Updating context %p window from %p to %p.\n",
-            context, context->win_handle, context->swapchain->win_handle);
+    TRACE("Updating context %p window from %p to %p, surface from %p to %p.\n",
+            context, context->win_handle, context->swapchain->win_handle,
+            context->surface, context->swapchain->surface);
 
     if (context->hdc)
-        wined3d_release_dc(context->win_handle, context->hdc);
+    {
+        if (context->surface)
+        {
+            if (context->surface == context->swapchain->surface)
+            {
+                context->win_handle = context->swapchain->win_handle;
+                return;
+            }
+            else
+                GL_EXTCALL(wglReleaseSurfaceDCWINE(context->surface, context->hdc));
+        }
+        else
+            wined3d_release_dc(context->win_handle, context->hdc);
+    }
 
     context->win_handle = context->swapchain->win_handle;
+    context->surface = context->swapchain->surface;
+    context->hdc = NULL;
     context->hdc_is_private = FALSE;
     context->hdc_has_format = FALSE;
     context->needs_set = 1;
     context->valid = 1;
 
-    if (!(context->hdc = GetDC(context->win_handle)))
+    if (context->surface)
+    {
+        if ((context->hdc = GL_EXTCALL(wglGetSurfaceDCWINE(context->surface))))
+            context->hdc_is_private = TRUE;
+        else
+        {
+            WARN("Failed to get a device context for surface %p.\n", context->surface);
+            context->surface = NULL;
+        }
+    }
+    if (!context->hdc && !(context->hdc = GetDC(context->win_handle)))
     {
         ERR("Failed to get a device context for window %p.\n", context->win_handle);
         context->valid = 0;
@@ -1010,7 +1039,10 @@ static void context_destroy_gl_resources(struct wined3d_context *context)
         ERR("Failed to disable GL context.\n");
     }
 
-    wined3d_release_dc(context->win_handle, context->hdc);
+    if (context->surface)
+        GL_EXTCALL(wglReleaseSurfaceDCWINE(context->surface, context->hdc));
+    else
+        wined3d_release_dc(context->win_handle, context->hdc);
 
     if (!wglDeleteContext(context->glCtx))
     {
@@ -1339,10 +1371,10 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
     unsigned int s;
     int swap_interval;
     DWORD state;
-    HDC hdc;
+    HDC hdc = NULL;
     BOOL hdc_is_private = FALSE;
 
-    TRACE("swapchain %p, target %p, window %p.\n", swapchain, target, swapchain->win_handle);
+    TRACE("swapchain %p, target %p, window %p, surface %p.\n", swapchain, target, swapchain->win_handle, swapchain->surface);
 
     ret = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ret));
     if (!ret)
@@ -1397,7 +1429,17 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain,
         }
     }
 
-    if (!(hdc = GetDC(swapchain->win_handle)))
+    if (swapchain->surface)
+    {
+        if ((hdc = GL_EXTCALL(wglGetSurfaceDCWINE(swapchain->surface))))
+        {
+            ret->surface = swapchain->surface;
+            hdc_is_private = TRUE;
+        }
+        else
+            WARN("Failed to get device context for surface %p\n", swapchain->surface);
+    }
+    if (!hdc && !(hdc = GetDC(swapchain->win_handle)))
     {
         WARN("Failed to retireve device context, trying swapchain backup.\n");
 
@@ -1759,7 +1801,8 @@ static void context_get_rt_size(const struct wined3d_context *context, SIZE *siz
 {
     const struct wined3d_surface *rt = context->current_rt;
 
-    if (rt->swapchain && rt->swapchain->front_buffer == rt)
+    if (rt->swapchain && rt->swapchain->front_buffer == rt
+            && (!context->surface || context->swapchain->desc.windowed))
     {
         RECT window_size;
 
@@ -3053,7 +3096,7 @@ struct wined3d_context *context_acquire(const struct wined3d_device *device, str
     }
 
     context_enter(context);
-    context_update_window(context);
+    context_update_drawable(context);
     context_setup_target(context, target);
     if (!context->valid) return context;
 
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 4cd6342..b5d9b3d 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -745,30 +745,39 @@ void CDECL wined3d_device_setup_fullscreen_window(struct wined3d_device *device,
 {
     BOOL filter_messages;
     LONG style, exstyle;
+    UINT swp_flags;
 
     TRACE("Setting up window %p for fullscreen mode.\n", window);
 
-    if (device->style || device->exStyle)
+    if (!device->adapter->gl_info.supported[WGL_WINE_SURFACE])
     {
-        ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
-                window, device->style, device->exStyle);
-    }
+        if (device->style || device->exStyle)
+        {
+            ERR("Changing the window style for window %p, but another style (%08x, %08x) is already stored.\n",
+                    window, device->style, device->exStyle);
+        }
 
-    device->style = GetWindowLongW(window, GWL_STYLE);
-    device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
+        device->style = GetWindowLongW(window, GWL_STYLE);
+        device->exStyle = GetWindowLongW(window, GWL_EXSTYLE);
 
-    style = fullscreen_style(device->style);
-    exstyle = fullscreen_exstyle(device->exStyle);
+        style = fullscreen_style(device->style);
+        exstyle = fullscreen_exstyle(device->exStyle);
 
-    TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
-            device->style, device->exStyle, style, exstyle);
+        TRACE("Old style was %08x, %08x, setting to %08x, %08x.\n",
+                device->style, device->exStyle, style, exstyle);
+    }
 
     filter_messages = device->filter_messages;
     device->filter_messages = TRUE;
 
-    SetWindowLongW(window, GWL_STYLE, style);
-    SetWindowLongW(window, GWL_EXSTYLE, exstyle);
-    SetWindowPos(window, HWND_TOPMOST, 0, 0, w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
+    swp_flags = 0;
+    if (!device->adapter->gl_info.supported[WGL_WINE_SURFACE])
+    {
+        SetWindowLongW(window, GWL_STYLE, style);
+        SetWindowLongW(window, GWL_EXSTYLE, exstyle);
+        swp_flags = SWP_FRAMECHANGED;
+    }
+    SetWindowPos(window, HWND_TOPMOST, 0, 0, w, h, swp_flags | SWP_SHOWWINDOW | SWP_NOACTIVATE);
 
     device->filter_messages = filter_messages;
 }
@@ -4388,7 +4397,12 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
             wined3d_device_restore_fullscreen_window(device, swapchain->device_window);
             wined3d_device_release_focus_window(device);
         }
-        swapchain->desc.windowed = swapchain_desc->windowed;
+
+        if (!swapchain_desc->windowed != !swapchain->desc.windowed)
+        {
+            swapchain->desc.windowed = swapchain_desc->windowed;
+            swapchain_update_surface(swapchain);
+        }
     }
     else if (!swapchain_desc->windowed)
     {
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index ef81278..0b2e2e0 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -215,6 +215,7 @@ static const struct wined3d_extension_map wgl_extension_map[] =
     {"WGL_ARB_pixel_format",                WGL_ARB_PIXEL_FORMAT             },
     {"WGL_EXT_swap_control",                WGL_EXT_SWAP_CONTROL             },
     {"WGL_WINE_pixel_format_passthrough",   WGL_WINE_PIXEL_FORMAT_PASSTHROUGH},
+    {"WGL_WINE_surface",                    WGL_WINE_SURFACE                 },
 };
 
 /**********************************************************
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index cdc157e..b211796 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -4266,7 +4266,8 @@ void surface_translate_drawable_coords(const struct wined3d_surface *surface, co
 {
     UINT drawable_height;
 
-    if (surface->swapchain && surface == surface->swapchain->front_buffer)
+    if (surface->swapchain && surface == surface->swapchain->front_buffer
+            && (!context->surface || context->swapchain->desc.windowed))
     {
         POINT offset = {0, 0};
         RECT windowsize;
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 75e6628..e56d6de 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -29,6 +29,7 @@ WINE_DECLARE_DEBUG_CHANNEL(fps);
 
 static void swapchain_cleanup(struct wined3d_swapchain *swapchain)
 {
+    const struct wined3d_gl_info *gl_info = &swapchain->device->adapter->gl_info;
     HRESULT hr;
     UINT i;
 
@@ -66,6 +67,9 @@ static void swapchain_cleanup(struct wined3d_swapchain *swapchain)
     }
     HeapFree(GetProcessHeap(), 0, swapchain->context);
 
+    if (swapchain->surface && !GL_EXTCALL(wglDestroySurfaceWINE(swapchain->surface)))
+        ERR("wglDestroySurfaceWINE failed to destroy surface %p\n", swapchain->surface);
+
     /* Restore the screen resolution if we rendered in fullscreen.
      * This will restore the screen resolution to what it was before creating
      * the swapchain. In case of d3d8 and d3d9 this will be the original
@@ -130,6 +134,9 @@ void CDECL wined3d_swapchain_set_window(struct wined3d_swapchain *swapchain, HWN
     TRACE("Setting swapchain %p window from %p to %p.\n",
             swapchain, swapchain->win_handle, window);
     swapchain->win_handle = window;
+
+    if (swapchain->desc.windowed)
+        swapchain_update_surface(swapchain);
 }
 
 HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain,
@@ -281,7 +288,6 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
     UINT src_h = src_rect->bottom - src_rect->top;
     GLenum gl_filter;
     const struct wined3d_gl_info *gl_info = context->gl_info;
-    RECT win_rect;
     UINT win_h;
 
     TRACE("swapchain %p, context %p, src_rect %s, dst_rect %s.\n",
@@ -292,8 +298,14 @@ static void swapchain_blit(const struct wined3d_swapchain *swapchain,
     else
         gl_filter = GL_LINEAR;
 
-    GetClientRect(swapchain->win_handle, &win_rect);
-    win_h = win_rect.bottom - win_rect.top;
+    if (context->surface && !swapchain->desc.windowed)
+        win_h = swapchain->front_buffer->resource.height;
+    else
+    {
+        RECT win_rect;
+        GetClientRect(swapchain->win_handle, &win_rect);
+        win_h = win_rect.bottom - win_rect.top;
+    }
 
     if (gl_info->fbo_ops.glBlitFramebuffer && is_identity_fixup(backbuffer->resource.format->color_fixup))
     {
@@ -483,6 +495,13 @@ static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT
 
     if (dst_rect_in)
         dst_rect = *dst_rect_in;
+    else if (context->surface && !swapchain->desc.windowed)
+    {
+        dst_rect.left = 0;
+        dst_rect.top = 0;
+        dst_rect.right = swapchain->front_buffer->resource.width;
+        dst_rect.bottom = swapchain->front_buffer->resource.height;
+    }
     else
         GetClientRect(swapchain->win_handle, &dst_rect);
 
@@ -730,7 +749,15 @@ void swapchain_update_render_to_fbo(struct wined3d_swapchain *swapchain)
         return;
     }
 
-    GetClientRect(swapchain->win_handle, &client_rect);
+    if (swapchain->surface && !swapchain->desc.windowed)
+    {
+        client_rect.left = 0;
+        client_rect.top = 0;
+        client_rect.right = swapchain->front_buffer->resource.width;
+        client_rect.bottom = swapchain->front_buffer->resource.height;
+    }
+    else
+        GetClientRect(swapchain->win_handle, &client_rect);
 
     TRACE("Backbuffer %ux%u, window %ux%u.\n",
             swapchain->desc.backbuffer_width,
@@ -757,6 +784,7 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
         struct wined3d_swapchain_desc *desc, void *parent, const struct wined3d_parent_ops *parent_ops)
 {
     const struct wined3d_adapter *adapter = device->adapter;
+    const struct wined3d_gl_info *gl_info = &adapter->gl_info;
     struct wined3d_resource_desc surface_desc;
     BOOL displaymode_set = FALSE;
     RECT client_rect;
@@ -824,6 +852,7 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
     }
     swapchain->desc = *desc;
     swapchain_update_render_to_fbo(swapchain);
+    swapchain_update_surface(swapchain);
 
     TRACE("Creating front buffer.\n");
 
@@ -886,8 +915,6 @@ static HRESULT swapchain_init(struct wined3d_swapchain *swapchain, struct wined3
             WINED3DFMT_S1_UINT_D15_UNORM
         };
 
-        const struct wined3d_gl_info *gl_info = &adapter->gl_info;
-
         swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
         if (!swapchain->context)
         {
@@ -1020,6 +1047,9 @@ err:
         wined3d_surface_decref(swapchain->front_buffer);
     }
 
+    if (swapchain->surface && !GL_EXTCALL(wglDestroySurfaceWINE(swapchain->surface)))
+        ERR("wglDestroySurfaceWINE failed to destroy surface %p\n", swapchain->surface);
+
     return hr;
 }
 
@@ -1150,3 +1180,22 @@ void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain)
         surface_update_draw_binding(swapchain->back_buffers[i]);
     }
 }
+
+void swapchain_update_surface(struct wined3d_swapchain *swapchain)
+{
+    const struct wined3d_gl_info *gl_info = &swapchain->device->adapter->gl_info;
+    if (gl_info->supported[WGL_WINE_SURFACE])
+    {
+        HDC hdc;
+        HWND window = swapchain->desc.windowed ? swapchain->win_handle : NULL;
+
+        if (swapchain->surface && !GL_EXTCALL(wglDestroySurfaceWINE(swapchain->surface)))
+            ERR("wglDestroySurfaceWINE failed to destroy surface %p\n", swapchain->surface);
+
+        hdc = GetDC(window);
+        swapchain->surface = GL_EXTCALL(wglCreateSurfaceWINE(hdc));
+        if (!swapchain->surface)
+            WARN("wglCreateSurfaceWINE failed to create surface for window %p\n", window);
+        ReleaseDC(window, hdc);
+    }
+}
diff --git a/dlls/wined3d/wined3d_gl.h b/dlls/wined3d/wined3d_gl.h
index b357bb1..a946c1f 100644
--- a/dlls/wined3d/wined3d_gl.h
+++ b/dlls/wined3d/wined3d_gl.h
@@ -158,6 +158,7 @@ enum wined3d_gl_extension
     WGL_ARB_PIXEL_FORMAT,
     WGL_EXT_SWAP_CONTROL,
     WGL_WINE_PIXEL_FORMAT_PASSTHROUGH,
+    WGL_WINE_SURFACE,
     /* Internally used */
     WINED3D_GL_NORMALIZED_TEXRECT,
     WINED3D_GL_VERSION_2_0,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index dab0724..a07cd06 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1109,6 +1109,7 @@ struct wined3d_context
     HWND restore_pf_win;
     HGLRC                   glCtx;
     HWND                    win_handle;
+    HANDLE                  surface;
     HDC                     hdc;
     int pixel_format;
     GLint                   aux_buffers;
@@ -2612,6 +2613,7 @@ struct wined3d_swapchain
 
     HWND win_handle;
     HWND device_window;
+    HANDLE surface;
 
     HDC backup_dc;
     HWND backup_wnd;
@@ -2629,6 +2631,7 @@ void swapchain_destroy_contexts(struct wined3d_swapchain *swapchain) DECLSPEC_HI
 HDC swapchain_get_backup_dc(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 void swapchain_update_render_to_fbo(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
+void swapchain_update_surface(struct wined3d_swapchain *swapchain) DECLSPEC_HIDDEN;
 
 /*****************************************************************************
  * Utility function prototypes
-- 
1.7.7.4

