[PATCH 1/5] ddraw: Create the wined3d swapchain when setting the cooperative level.

Henri Verbeet hverbeet at codeweavers.com
Mon Nov 28 14:30:57 CST 2011


---
 dlls/ddraw/ddraw.c         |  280 +++++++++++++++++++++-----------------------
 dlls/ddraw/ddraw_private.h |    1 -
 dlls/ddraw/device.c        |    4 +-
 dlls/ddraw/surface.c       |   11 --
 dlls/ddraw/tests/d3d.c     |    4 +-
 5 files changed, 136 insertions(+), 164 deletions(-)

diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index d7aad8f..45496f6 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -445,7 +445,6 @@ void ddraw_destroy_swapchain(IDirectDrawImpl *ddraw)
         }
 
         ddraw->d3d_initialized = FALSE;
-        ddraw->d3d_target = NULL;
     }
     else
     {
@@ -484,16 +483,8 @@ static void ddraw_destroy(IDirectDrawImpl *This)
     list_remove(&This->ddraw_list_entry);
     wined3d_mutex_unlock();
 
-    /* This can happen more or less legitimately for ddraw 1 and 2, where
-     * surfaces don't keep a reference to the ddraw object. The surfaces
-     * will of course be broken after this, (and on native trying to do
-     * anything with them in that state results in an access violation), but
-     * the release of the ddraw object should succeed without crashing. */
     if (This->wined3d_swapchain)
-    {
-        WARN("DirectDraw object is being destroyed while the swapchain still exists.\n");
         ddraw_destroy_swapchain(This);
-    }
     wined3d_device_decref(This->wined3d_device);
     wined3d_decref(This->wineD3D);
 
@@ -625,6 +616,109 @@ static HRESULT ddraw_set_focus_window(IDirectDrawImpl *ddraw, HWND window)
     return DD_OK;
 }
 
+static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw,
+        WINED3DPRESENT_PARAMETERS *presentation_parameters)
+{
+    HWND window = presentation_parameters->hDeviceWindow;
+    HRESULT hr;
+
+    TRACE("ddraw %p.\n", ddraw);
+
+    if (!window || window == GetDesktopWindow())
+    {
+        window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window",
+                WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
+                NULL, NULL, NULL, NULL);
+        if (!window)
+        {
+            ERR("Failed to create window, last error %#x.\n", GetLastError());
+            return E_FAIL;
+        }
+
+        ShowWindow(window, SW_HIDE);   /* Just to be sure */
+        WARN("No window for the Direct3DDevice, created hidden window %p.\n", window);
+
+        presentation_parameters->hDeviceWindow = window;
+    }
+    else
+    {
+        TRACE("Using existing window %p for Direct3D rendering.\n", window);
+    }
+    ddraw->d3d_window = window;
+
+    /* Set this NOW, otherwise creating the depth stencil surface will cause a
+     * recursive loop until ram or emulated video memory is full. */
+    ddraw->d3d_initialized = TRUE;
+    hr = wined3d_device_init_3d(ddraw->wined3d_device, presentation_parameters);
+    if (FAILED(hr))
+    {
+        ddraw->d3d_initialized = FALSE;
+        return hr;
+    }
+
+    ddraw->declArraySize = 2;
+    ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize);
+    if (!ddraw->decls)
+    {
+        ERR("Error allocating an array for the converted vertex decls.\n");
+        ddraw->declArraySize = 0;
+        hr = wined3d_device_uninit_3d(ddraw->wined3d_device);
+        return E_OUTOFMEMORY;
+    }
+
+    TRACE("Successfully initialized 3D.\n");
+
+    return DD_OK;
+}
+
+static HRESULT ddraw_create_swapchain(IDirectDrawImpl *ddraw, HWND window, BOOL windowed)
+{
+    WINED3DPRESENT_PARAMETERS presentation_parameters;
+    struct wined3d_display_mode mode;
+    HRESULT hr = WINED3D_OK;
+
+    /* FIXME: wined3d_get_adapter_display_mode() would be more appropriate
+     * here, since we don't actually have a swapchain yet, but
+     * wined3d_device_get_display_mode() has some special handling for color
+     * depth changes. */
+    hr = wined3d_device_get_display_mode(ddraw->wined3d_device, 0, &mode);
+    if (FAILED(hr))
+    {
+        ERR("Failed to get display mode.\n");
+        return hr;
+    }
+
+    memset(&presentation_parameters, 0, sizeof(presentation_parameters));
+    presentation_parameters.BackBufferWidth = mode.width;
+    presentation_parameters.BackBufferHeight = mode.height;
+    presentation_parameters.BackBufferFormat = mode.format_id;
+    presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_COPY;
+    presentation_parameters.hDeviceWindow = window;
+    presentation_parameters.Windowed = windowed;
+
+    if (DefaultSurfaceType == SURFACE_OPENGL)
+        hr = ddraw_attach_d3d_device(ddraw, &presentation_parameters);
+    else
+        hr = wined3d_device_init_gdi(ddraw->wined3d_device, &presentation_parameters);
+
+    if (FAILED(hr))
+    {
+        ERR("Failed to create swapchain, hr %#x.\n", hr);
+        return hr;
+    }
+
+    if (FAILED(hr = wined3d_device_get_swapchain(ddraw->wined3d_device, 0, &ddraw->wined3d_swapchain)))
+    {
+        ERR("Failed to get swapchain, hr %#x.\n", hr);
+        ddraw->wined3d_swapchain = NULL;
+        return hr;
+    }
+
+    ddraw_set_swapchain_window(ddraw, window);
+
+    return DD_OK;
+}
+
 /*****************************************************************************
  * IDirectDraw7::SetCooperativeLevel
  *
@@ -789,6 +883,11 @@ static HRESULT WINAPI ddraw7_SetCooperativeLevel(IDirectDraw7 *iface, HWND hwnd,
     if (cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
         wined3d_device_set_multithreaded(This->wined3d_device);
 
+    if (This->wined3d_swapchain)
+        ddraw_destroy_swapchain(This);
+    if (FAILED(hr = ddraw_create_swapchain(This, This->dest_window, !(cooplevel & DDSCL_FULLSCREEN))))
+        ERR("Failed to create swapchain, hr %#x.\n", hr);
+
     /* Unhandled flags */
     if(cooplevel & DDSCL_ALLOWREBOOT)
         WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
@@ -2522,120 +2621,11 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This,
     return DD_OK;
 }
 
-static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw,
-        WINED3DPRESENT_PARAMETERS *presentation_parameters)
+HRESULT CDECL ddraw_reset_enum_callback(struct wined3d_resource *resource)
 {
-    HWND window = presentation_parameters->hDeviceWindow;
-    HRESULT hr;
-
-    TRACE("ddraw %p.\n", ddraw);
-
-    if (!window || window == GetDesktopWindow())
-    {
-        window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window",
-                WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
-                NULL, NULL, NULL, NULL);
-        if (!window)
-        {
-            ERR("Failed to create window, last error %#x.\n", GetLastError());
-            return E_FAIL;
-        }
-
-        ShowWindow(window, SW_HIDE);   /* Just to be sure */
-        WARN("No window for the Direct3DDevice, created hidden window %p.\n", window);
-
-        presentation_parameters->hDeviceWindow = window;
-    }
-    else
-    {
-        TRACE("Using existing window %p for Direct3D rendering.\n", window);
-    }
-    ddraw->d3d_window = window;
-
-    /* Set this NOW, otherwise creating the depth stencil surface will cause a
-     * recursive loop until ram or emulated video memory is full. */
-    ddraw->d3d_initialized = TRUE;
-    hr = wined3d_device_init_3d(ddraw->wined3d_device, presentation_parameters);
-    if (FAILED(hr))
-    {
-        ddraw->d3d_target = NULL;
-        ddraw->d3d_initialized = FALSE;
-        return hr;
-    }
-
-    ddraw->declArraySize = 2;
-    ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize);
-    if (!ddraw->decls)
-    {
-        ERR("Error allocating an array for the converted vertex decls.\n");
-        ddraw->declArraySize = 0;
-        hr = wined3d_device_uninit_3d(ddraw->wined3d_device);
-        return E_OUTOFMEMORY;
-    }
-
-    TRACE("Successfully initialized 3D.\n");
-
     return DD_OK;
 }
 
-static HRESULT ddraw_create_swapchain(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *surface)
-{
-    WINED3DPRESENT_PARAMETERS presentation_parameters;
-    struct wined3d_display_mode mode;
-    HRESULT hr = WINED3D_OK;
-
-    /* FIXME: wined3d_get_adapter_display_mode() would be more appropriate
-     * here, since we don't actually have a swapchain yet, but
-     * wined3d_device_get_display_mode() has some special handling for color
-     * depth changes. */
-    hr = wined3d_device_get_display_mode(ddraw->wined3d_device, 0, &mode);
-    if (FAILED(hr))
-    {
-        ERR("Failed to get display mode.\n");
-        return hr;
-    }
-
-    memset(&presentation_parameters, 0, sizeof(presentation_parameters));
-    presentation_parameters.BackBufferWidth = mode.width;
-    presentation_parameters.BackBufferHeight = mode.height;
-    presentation_parameters.BackBufferFormat = mode.format_id;
-    presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_COPY;
-    presentation_parameters.hDeviceWindow = ddraw->dest_window;
-    presentation_parameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN);
-
-    /* If the implementation is OpenGL and there's no d3ddevice, attach a
-     * d3ddevice. But attach the d3ddevice only if the currently created
-     * surface was a primary surface (2D app in 3D mode) or a 3DDEVICE surface
-     * (3D app). The only case I can think of where this doesn't apply is when
-     * a 2D app was configured by the user to run with OpenGL and it didn't
-     * create the render target as first surface. In this case the render
-     * target creation will cause the 3D init. */
-    if (DefaultSurfaceType == SURFACE_OPENGL)
-    {
-        hr = ddraw_attach_d3d_device(ddraw, &presentation_parameters);
-    }
-    else if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
-    {
-        hr = wined3d_device_init_gdi(ddraw->wined3d_device, &presentation_parameters);
-        if (FAILED(hr))
-            WARN("Failed to initialize GDI ddraw implementation, hr %#x.\n", hr);
-    }
-
-    if (SUCCEEDED(hr))
-    {
-        if (FAILED(hr = wined3d_device_get_swapchain(ddraw->wined3d_device, 0, &ddraw->wined3d_swapchain)))
-        {
-            ERR("Failed to get swapchain, hr %#x.\n", hr);
-            ddraw->wined3d_swapchain = NULL;
-        }
-    }
-
-    if (SUCCEEDED(hr))
-        ddraw_set_swapchain_window(ddraw, ddraw->dest_window);
-
-    return hr;
-}
-
 /*****************************************************************************
  * IDirectDraw7::CreateSurface
  *
@@ -2930,6 +2920,30 @@ static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD,
         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
     }
 
+    if ((desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) && (ddraw->cooperative_level & DDSCL_EXCLUSIVE))
+    {
+        WINED3DPRESENT_PARAMETERS presentation_parameters;
+
+        hr = wined3d_swapchain_get_present_parameters(ddraw->wined3d_swapchain, &presentation_parameters);
+        if (FAILED(hr))
+        {
+            ERR("Failed to get present parameters.\n");
+            return hr;
+        }
+
+        presentation_parameters.BackBufferWidth = mode.width;
+        presentation_parameters.BackBufferHeight = mode.height;
+        presentation_parameters.BackBufferFormat = mode.format_id;
+
+        hr = wined3d_device_reset(ddraw->wined3d_device,
+                &presentation_parameters, ddraw_reset_enum_callback);
+        if (FAILED(hr))
+        {
+            ERR("Failed to reset device.\n");
+            return hr;
+        }
+    }
+
     /* Create the first surface */
     hr = ddraw_create_surface(ddraw, &desc2, &object, 0, version);
     if (FAILED(hr))
@@ -2990,34 +3004,6 @@ static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD,
         return hr;
     }
 
-    if (!ddraw->d3d_initialized && desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE))
-    {
-        if (FAILED(hr = ddraw_create_swapchain(ddraw, object)))
-        {
-            IDirectDrawSurfaceImpl *release_surf;
-            ERR("Failed to create swapchain, hr %#x.\n", hr);
-            *Surf = NULL;
-
-            /* The earlier created surface structures are in an incomplete
-             * state here. Wined3d holds the reference on the parents, and it
-             * released them on the failure already. So the regular release
-             * method implementation would fail on the attempt to destroy
-             * either the parents or the swapchain. So free the surface here.
-             * The surface structure here is a list, not a tree, because
-             * onscreen targets cannot be cube textures. */
-            while (object)
-            {
-                release_surf = object;
-                object = object->complex_array[0];
-                ddraw_surface_destroy(release_surf);
-            }
-            return hr;
-        }
-
-        if (DefaultSurfaceType == SURFACE_OPENGL)
-            ddraw->d3d_target = ddraw->primary ? ddraw->primary : object;
-    }
-
     if (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
         ddraw->primary = object;
 
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index f53c93f..a4522b0 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -98,7 +98,6 @@ struct IDirectDrawImpl
     DWORD                   orig_bpp;
 
     /* D3D things */
-    IDirectDrawSurfaceImpl  *d3d_target;
     HWND                    d3d_window;
     IDirect3DDeviceImpl     *d3ddevice;
     int                     d3dversion;
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index ccbdb1a..462f39e 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -361,12 +361,11 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
 
         ddraw_handle_table_destroy(&This->handle_table);
 
-        TRACE("Releasing target %p %p\n", This->target, This->ddraw->d3d_target);
+        TRACE("Releasing target %p.\n", This->target);
         /* Release the render target and the WineD3D render target
          * (See IDirect3D7::CreateDevice for more comments on this)
          */
         IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
-        IDirectDrawSurface7_Release(&This->ddraw->d3d_target->IDirectDrawSurface7_iface);
         TRACE("Target release done\n");
 
         This->ddraw->d3ddevice = NULL;
@@ -6914,7 +6913,6 @@ HRESULT d3d_device_init(IDirect3DDeviceImpl *device, IDirectDrawImpl *ddraw, IDi
      * In most cases, those surfaces are the same anyway, but this will simply
      * add another ref which is released when the device is destroyed. */
     IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
-    IDirectDrawSurface7_AddRef(&ddraw->d3d_target->IDirectDrawSurface7_iface);
 
     ddraw->d3ddevice = device;
 
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index c7f92fd..851920c 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -453,20 +453,12 @@ void ddraw_surface_destroy(IDirectDrawSurfaceImpl *This)
 
 static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface)
 {
-    IDirectDrawImpl *ddraw = surface->ddraw;
-    BOOL destroy_swapchain = FALSE;
     IDirectDrawSurfaceImpl *surf;
     IUnknown *ifaceToRelease;
     UINT i;
 
     TRACE("surface %p.\n", surface);
 
-    if ((ddraw->d3d_initialized && surface == ddraw->d3d_target
-            && DefaultSurfaceType == SURFACE_OPENGL)
-            || ((surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
-            && DefaultSurfaceType != SURFACE_OPENGL))
-        destroy_swapchain = TRUE;
-
     /* The refcount test shows that the palette is detached when the surface
      * is destroyed. */
     IDirectDrawSurface7_SetPalette(&surface->IDirectDrawSurface7_iface, NULL);
@@ -495,9 +487,6 @@ static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface)
     /* Destroy the root surface. */
     ddraw_surface_destroy(surface);
 
-    if (ddraw->wined3d_swapchain && destroy_swapchain)
-        ddraw_destroy_swapchain(ddraw);
-
     /* Reduce the ddraw refcount */
     if (ifaceToRelease)
         IUnknown_Release(ifaceToRelease);
diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c
index 7ed7575..0a42083 100644
--- a/dlls/ddraw/tests/d3d.c
+++ b/dlls/ddraw/tests/d3d.c
@@ -3309,7 +3309,7 @@ static void SetRenderTargetTest(void)
     ok(hr == DD_OK, "IDirect3DDevice7_GetRenderTarget failed, hr=0x%08x\n", hr);
 
     refcount = getRefcount((IUnknown*) oldrt);
-    todo_wine ok(refcount == 3, "Refcount should be 3, returned is %d\n", refcount);
+    ok(refcount == 3, "Refcount should be 3, returned is %d\n", refcount);
 
     refcount = getRefcount((IUnknown*) failrt);
     ok(refcount == 1, "Refcount should be 1, returned is %d\n", refcount);
@@ -3318,7 +3318,7 @@ static void SetRenderTargetTest(void)
     ok(hr != D3D_OK, "IDirect3DDevice7_SetRenderTarget succeeded\n");
 
     refcount = getRefcount((IUnknown*) oldrt);
-    todo_wine ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);
+    ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);
 
     refcount = getRefcount((IUnknown*) failrt);
     ok(refcount == 2, "Refcount should be 2, returned is %d\n", refcount);
-- 
1.7.3.4




More information about the wine-patches mailing list