[PATCH 5/5] wined3d: Don't free D3D swapchains until the wined3d swapchain is destroyed.

Henri Verbeet hverbeet at codeweavers.com
Thu Apr 7 11:46:01 CDT 2011


This will allow us the get rid of the swapchain refcounting hacks in d3d9 in
particular. This is similar to the way we handle resources that are still in
use by a stateblock, but aren't referenced anywhere by the application.
---
 dlls/d3d8/swapchain.c          |   31 +++++++++++++++++++++++++++----
 dlls/d3d9/swapchain.c          |   28 ++++++++++++++++++++++++----
 dlls/ddraw/ddraw.c             |    2 +-
 dlls/dxgi/swapchain.c          |   18 +++++++++++++++---
 dlls/wined3d/device.c          |    4 ++--
 dlls/wined3d/swapchain.c       |    5 ++++-
 dlls/wined3d/wined3d_private.h |    4 +++-
 include/wine/wined3d.idl       |    1 +
 8 files changed, 77 insertions(+), 16 deletions(-)

diff --git a/dlls/d3d8/swapchain.c b/dlls/d3d8/swapchain.c
index d6b7a28..654e153 100644
--- a/dlls/d3d8/swapchain.c
+++ b/dlls/d3d8/swapchain.c
@@ -54,6 +54,15 @@ static ULONG WINAPI IDirect3DSwapChain8Impl_AddRef(IDirect3DSwapChain8 *iface)
 
     TRACE("%p increasing refcount to %u.\n", iface, ref);
 
+    if (ref == 1)
+    {
+        if (This->parentDevice)
+            IDirect3DDevice8_AddRef(This->parentDevice);
+        wined3d_mutex_lock();
+        IWineD3DSwapChain_AddRef(This->wineD3DSwapChain);
+        wined3d_mutex_unlock();
+    }
+
     return ref;
 }
 
@@ -64,13 +73,16 @@ static ULONG WINAPI IDirect3DSwapChain8Impl_Release(IDirect3DSwapChain8 *iface)
 
     TRACE("%p decreasing refcount to %u.\n", iface, ref);
 
-    if (ref == 0) {
+    if (!ref)
+    {
+        IDirect3DDevice8 *parentDevice = This->parentDevice;
+
         wined3d_mutex_lock();
         IWineD3DSwapChain_Destroy(This->wineD3DSwapChain);
         wined3d_mutex_unlock();
 
-        if (This->parentDevice) IUnknown_Release(This->parentDevice);
-        HeapFree(GetProcessHeap(), 0, This);
+        if (parentDevice)
+            IDirect3DDevice8_Release(parentDevice);
     }
     return ref;
 }
@@ -125,6 +137,16 @@ static const IDirect3DSwapChain8Vtbl Direct3DSwapChain8_Vtbl =
     IDirect3DSwapChain8Impl_GetBackBuffer
 };
 
+static void STDMETHODCALLTYPE d3d8_swapchain_wined3d_object_released(void *parent)
+{
+    HeapFree(GetProcessHeap(), 0, parent);
+}
+
+static const struct wined3d_parent_ops d3d8_swapchain_wined3d_parent_ops =
+{
+    d3d8_swapchain_wined3d_object_released,
+};
+
 HRESULT swapchain_init(IDirect3DSwapChain8Impl *swapchain, IDirect3DDevice8Impl *device,
         D3DPRESENT_PARAMETERS *present_parameters)
 {
@@ -152,7 +174,8 @@ HRESULT swapchain_init(IDirect3DSwapChain8Impl *swapchain, IDirect3DDevice8Impl
 
     wined3d_mutex_lock();
     hr = IWineD3DDevice_CreateSwapChain(device->WineD3DDevice, &wined3d_parameters,
-            SURFACE_OPENGL, swapchain, &swapchain->wineD3DSwapChain);
+            SURFACE_OPENGL, swapchain, &d3d8_swapchain_wined3d_parent_ops,
+            &swapchain->wineD3DSwapChain);
     wined3d_mutex_unlock();
 
     present_parameters->BackBufferWidth = wined3d_parameters.BackBufferWidth;
diff --git a/dlls/d3d9/swapchain.c b/dlls/d3d9/swapchain.c
index 0d52391..df1cc77 100644
--- a/dlls/d3d9/swapchain.c
+++ b/dlls/d3d9/swapchain.c
@@ -50,7 +50,18 @@ static ULONG WINAPI IDirect3DSwapChain9Impl_AddRef(LPDIRECT3DSWAPCHAIN9 iface) {
 
     TRACE("%p increasing refcount to %u.\n", iface, ref);
 
-    if(ref == 1 && This->parentDevice) IDirect3DDevice9Ex_AddRef(This->parentDevice);
+    if (ref == 1)
+    {
+        if (This->parentDevice)
+            IDirect3DDevice9Ex_AddRef(This->parentDevice);
+
+        if (!This->isImplicit)
+        {
+            wined3d_mutex_lock();
+            IWineD3DSwapChain_AddRef(This->wineD3DSwapChain);
+            wined3d_mutex_unlock();
+        }
+    }
 
     return ref;
 }
@@ -68,8 +79,6 @@ static ULONG WINAPI IDirect3DSwapChain9Impl_Release(LPDIRECT3DSWAPCHAIN9 iface)
             wined3d_mutex_lock();
             IWineD3DSwapChain_Destroy(This->wineD3DSwapChain);
             wined3d_mutex_unlock();
-
-            HeapFree(GetProcessHeap(), 0, This);
         }
 
         /* Release the device last, as it may cause the device to be destroyed. */
@@ -217,6 +226,16 @@ static const IDirect3DSwapChain9Vtbl Direct3DSwapChain9_Vtbl =
     IDirect3DSwapChain9Impl_GetPresentParameters
 };
 
+static void STDMETHODCALLTYPE d3d9_swapchain_wined3d_object_released(void *parent)
+{
+    HeapFree(GetProcessHeap(), 0, parent);
+}
+
+static const struct wined3d_parent_ops d3d9_swapchain_wined3d_parent_ops =
+{
+    d3d9_swapchain_wined3d_object_released,
+};
+
 HRESULT swapchain_init(IDirect3DSwapChain9Impl *swapchain, IDirect3DDevice9Impl *device,
         D3DPRESENT_PARAMETERS *present_parameters)
 {
@@ -244,7 +263,8 @@ HRESULT swapchain_init(IDirect3DSwapChain9Impl *swapchain, IDirect3DDevice9Impl
 
     wined3d_mutex_lock();
     hr = IWineD3DDevice_CreateSwapChain(device->WineD3DDevice, &wined3d_parameters,
-            SURFACE_OPENGL, swapchain, &swapchain->wineD3DSwapChain);
+            SURFACE_OPENGL, swapchain, &d3d9_swapchain_wined3d_parent_ops,
+            &swapchain->wineD3DSwapChain);
     wined3d_mutex_unlock();
 
     present_parameters->BackBufferWidth = wined3d_parameters.BackBufferWidth;
diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index 5cc5743..d056dcf 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -5905,7 +5905,7 @@ static HRESULT STDMETHODCALLTYPE device_parent_CreateSwapChain(IWineD3DDevicePar
     TRACE("iface %p, present_parameters %p, swapchain %p\n", iface, present_parameters, swapchain);
 
     hr = IWineD3DDevice_CreateSwapChain(This->wineD3DDevice, present_parameters,
-            This->ImplType, NULL, swapchain);
+            This->ImplType, NULL, &ddraw_null_wined3d_parent_ops, swapchain);
     if (FAILED(hr))
     {
         FIXME("(%p) CreateSwapChain failed, returning %#x\n", iface, hr);
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index de9412b..4a58ed2 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -53,6 +53,9 @@ static ULONG STDMETHODCALLTYPE dxgi_swapchain_AddRef(IDXGISwapChain *iface)
 
     TRACE("%p increasing refcount to %u\n", This, refcount);
 
+    if (refcount == 1)
+        IWineD3DSwapChain_AddRef(This->wined3d_swapchain);
+
     return refcount;
 }
 
@@ -91,8 +94,6 @@ static ULONG STDMETHODCALLTYPE dxgi_swapchain_Release(IDXGISwapChain *iface)
                 ERR("Uninit3D failed, hr %#x\n", hr);
             }
         }
-
-        HeapFree(GetProcessHeap(), 0, This);
     }
 
     return refcount;
@@ -269,6 +270,16 @@ static const struct IDXGISwapChainVtbl dxgi_swapchain_vtbl =
     dxgi_swapchain_GetLastPresentCount,
 };
 
+static void STDMETHODCALLTYPE dxgi_swapchain_wined3d_object_released(void *parent)
+{
+    HeapFree(GetProcessHeap(), 0, parent);
+}
+
+static const struct wined3d_parent_ops dxgi_swapchain_wined3d_parent_ops =
+{
+    dxgi_swapchain_wined3d_object_released,
+};
+
 HRESULT dxgi_swapchain_init(struct dxgi_swapchain *swapchain, struct dxgi_device *device,
         WINED3DPRESENT_PARAMETERS *present_parameters)
 {
@@ -278,7 +289,8 @@ HRESULT dxgi_swapchain_init(struct dxgi_swapchain *swapchain, struct dxgi_device
     swapchain->refcount = 1;
 
     hr = IWineD3DDevice_CreateSwapChain(device->wined3d_device, present_parameters,
-            SURFACE_OPENGL, swapchain, &swapchain->wined3d_swapchain);
+            SURFACE_OPENGL, swapchain, &dxgi_swapchain_wined3d_parent_ops,
+            &swapchain->wined3d_swapchain);
     if (FAILED(hr))
     {
         WARN("Failed to create wined3d swapchain, hr %#x.\n", hr);
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 4623494..e05c732 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -1278,7 +1278,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface,
 /* Do not call while under the GL lock. */
 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
         WINED3DPRESENT_PARAMETERS *present_parameters, WINED3DSURFTYPE surface_type,
-        void *parent, IWineD3DSwapChain **swapchain)
+        void *parent, const struct wined3d_parent_ops *parent_ops, IWineD3DSwapChain **swapchain)
 {
     IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
     IWineD3DSwapChainImpl *object;
@@ -1294,7 +1294,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice *iface,
         return E_OUTOFMEMORY;
     }
 
-    hr = swapchain_init(object, surface_type, This, present_parameters, parent);
+    hr = swapchain_init(object, surface_type, This, present_parameters, parent, parent_ops);
     if (FAILED(hr))
     {
         WARN("Failed to initialize swapchain, hr %#x.\n", hr);
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index e785494..e1add64 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -80,6 +80,7 @@ static void WINAPI IWineD3DBaseSwapChainImpl_Destroy(IWineD3DSwapChain *iface)
         IWineD3DDevice_SetDisplayMode((IWineD3DDevice *)swapchain->device, 0, &mode);
     }
 
+    swapchain->parent_ops->wined3d_object_destroyed(swapchain->parent);
     HeapFree(GetProcessHeap(), 0, swapchain->context);
     HeapFree(GetProcessHeap(), 0, swapchain);
 }
@@ -860,7 +861,8 @@ static const IWineD3DSwapChainVtbl IWineGDISwapChain_Vtbl =
 
 /* Do not call while under the GL lock. */
 HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface_type,
-        IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters, void *parent)
+        IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters,
+        void *parent, const struct wined3d_parent_ops *parent_ops)
 {
     const struct wined3d_adapter *adapter = device->adapter;
     const struct wined3d_format *format;
@@ -903,6 +905,7 @@ HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface
 
     swapchain->device = device;
     swapchain->parent = parent;
+    swapchain->parent_ops = parent_ops;
     swapchain->ref = 1;
     swapchain->win_handle = window;
     swapchain->device_window = window;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 37344b8..d78d504 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2530,6 +2530,7 @@ struct IWineD3DSwapChainImpl
     LONG                      ref;     /* Note: Ref counting not required */
 
     void *parent;
+    const struct wined3d_parent_ops *parent_ops;
     IWineD3DDeviceImpl *device;
 
     /* IWineD3DSwapChain fields */
@@ -2556,7 +2557,8 @@ void x11_copy_to_screen(IWineD3DSwapChainImpl *This, const RECT *rc) DECLSPEC_HI
 
 struct wined3d_context *swapchain_get_context(struct IWineD3DSwapChainImpl *swapchain) DECLSPEC_HIDDEN;
 HRESULT swapchain_init(IWineD3DSwapChainImpl *swapchain, WINED3DSURFTYPE surface_type,
-        IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters, void *parent) DECLSPEC_HIDDEN;
+        IWineD3DDeviceImpl *device, WINED3DPRESENT_PARAMETERS *present_parameters,
+        void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
 
 #define DEFAULT_REFRESH_RATE 0
 
diff --git a/include/wine/wined3d.idl b/include/wine/wined3d.idl
index 00e6d0e..de83f47 100644
--- a/include/wine/wined3d.idl
+++ b/include/wine/wined3d.idl
@@ -2481,6 +2481,7 @@ interface IWineD3DDevice : IUnknown
         [in] WINED3DPRESENT_PARAMETERS *present_parameters,
         [in] WINED3DSURFTYPE surface_type,
         [in] void *parent,
+        [in] const struct wined3d_parent_ops *parent_ops,
         [out] IWineD3DSwapChain **swapchain
     );
     HRESULT CreateVertexDeclaration(
-- 
1.7.3.4




More information about the wine-patches mailing list