[PATCH 1/5] ddraw: Fix render target refcount handling.

Henri Verbeet hverbeet at codeweavers.com
Tue Sep 17 02:22:36 CDT 2013


Similar to AddAttachedSurface() / DeleteAttachedSurface(), we should Release
the interface version that we stored. (And actually store the interface that
we AddRef.)
---
 dlls/ddraw/ddraw.c         |   15 ++++---
 dlls/ddraw/ddraw_private.h |    4 +-
 dlls/ddraw/device.c        |  102 +++++++++++++++++---------------------------
 dlls/ddraw/surface.c       |    7 +--
 4 files changed, 55 insertions(+), 73 deletions(-)

diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index 608804f..bdb375b 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -4513,9 +4513,10 @@ static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid,
     TRACE("iface %p, riid %s, surface %p, device %p.\n", iface, debugstr_guid(riid), surface, device);
 
     wined3d_mutex_lock();
-    hr = d3d_device_create(ddraw, target, 7, &object, NULL);
-    if (SUCCEEDED(hr))
+    if (SUCCEEDED(hr = d3d_device_create(ddraw, target, (IUnknown *)surface, 7, &object, NULL)))
+    {
         *device = &object->IDirect3DDevice7_iface;
+    }
     else
     {
         WARN("Failed to create device, hr %#x.\n", hr);
@@ -4541,9 +4542,10 @@ static HRESULT WINAPI d3d3_CreateDevice(IDirect3D3 *iface, REFCLSID riid,
         return CLASS_E_NOAGGREGATION;
 
     wined3d_mutex_lock();
-    hr = d3d_device_create(ddraw, surface_impl, 3, &device_impl, NULL);
-    if (SUCCEEDED(hr))
+    if (SUCCEEDED(hr = d3d_device_create(ddraw, surface_impl, (IUnknown *)surface, 3, &device_impl, NULL)))
+    {
         *device = &device_impl->IDirect3DDevice3_iface;
+    }
     else
     {
         WARN("Failed to create device, hr %#x.\n", hr);
@@ -4566,9 +4568,10 @@ static HRESULT WINAPI d3d2_CreateDevice(IDirect3D2 *iface, REFCLSID riid,
             iface, debugstr_guid(riid), surface, device);
 
     wined3d_mutex_lock();
-    hr = d3d_device_create(ddraw, surface_impl, 2, &device_impl, NULL);
-    if (SUCCEEDED(hr))
+    if (SUCCEEDED(hr = d3d_device_create(ddraw, surface_impl, (IUnknown *)surface, 2, &device_impl, NULL)))
+    {
         *device = &device_impl->IDirect3DDevice2_iface;
+    }
     else
     {
         WARN("Failed to create device, hr %#x.\n", hr);
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index 44933d3..21e0ca8 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -277,7 +277,7 @@ struct d3d_device
     IUnknown *outer_unknown;
     struct wined3d_device *wined3d_device;
     struct ddraw *ddraw;
-    struct ddraw_surface *target;
+    IUnknown *rt_iface;
 
     struct wined3d_buffer *index_buffer;
     UINT index_buffer_size;
@@ -315,7 +315,7 @@ struct d3d_device
     D3DMATRIXHANDLE          world, proj, view;
 };
 
-HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
+HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target, IUnknown *rt_iface,
         UINT version, struct d3d_device **device, IUnknown *outer_unknown) DECLSPEC_HIDDEN;
 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device) DECLSPEC_HIDDEN;
 
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index c0332d9..66e0b7f 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -224,6 +224,7 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
 {
     struct d3d_device *This = impl_from_IUnknown(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
+    IUnknown *rt_iface;
 
     TRACE("%p decreasing refcount to %u.\n", This, ref);
 
@@ -308,11 +309,12 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
             IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
         }
 
-        TRACE("Releasing target %p.\n", This->target);
-        /* Release the render target. */
+        TRACE("Releasing render target %p.\n", This->rt_iface);
+        rt_iface = This->rt_iface;
+        This->rt_iface = NULL;
         if (This->version != 1)
-            IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface);
-        TRACE("Target release done\n");
+            IUnknown_Release(rt_iface);
+        TRACE("Render target release done.\n");
 
         This->ddraw->d3ddevice = NULL;
 
@@ -1794,31 +1796,14 @@ static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, ID
             (IDirect3DViewport3 **)viewport);
 }
 
-/*****************************************************************************
- * IDirect3DDevice7::SetRenderTarget
- *
- * Sets the render target for the Direct3DDevice.
- * For the thunks note that IDirectDrawSurface7 == IDirectDrawSurface4 and
- * IDirectDrawSurface3 == IDirectDrawSurface
- *
- * Version 2, 3 and 7
- *
- * Params:
- *  NewTarget: Pointer to an IDirectDrawSurface7 interface to set as the new
- *             render target
- *  Flags: Some flags
- *
- * Returns:
- *  D3D_OK on success, for details see IWineD3DDevice::SetRenderTarget
- *
- *****************************************************************************/
-static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct ddraw_surface *target)
+static HRESULT d3d_device_set_render_target(struct d3d_device *device,
+        struct ddraw_surface *target, IUnknown *rt_iface)
 {
     HRESULT hr;
 
     wined3d_mutex_lock();
 
-    if (device->target == target)
+    if (device->rt_iface == rt_iface)
     {
         TRACE("No-op SetRenderTarget operation, not doing anything\n");
         wined3d_mutex_unlock();
@@ -1830,7 +1815,10 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct dd
         wined3d_mutex_unlock();
         return DDERR_INVALIDPARAMS;
     }
-    device->target = target;
+
+    IUnknown_AddRef(rt_iface);
+    IUnknown_Release(device->rt_iface);
+    device->rt_iface = rt_iface;
     if (FAILED(hr = wined3d_device_set_render_target(device->wined3d_device,
             0, target->wined3d_surface, FALSE)))
     {
@@ -1845,16 +1833,14 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct dd
 }
 
 static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface,
-        IDirectDrawSurface7 *NewTarget, DWORD flags)
+        IDirectDrawSurface7 *target, DWORD flags)
 {
+    struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface7(target);
     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
-    struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface7(NewTarget);
 
-    TRACE("iface %p, target %p, flags %#x.\n", iface, NewTarget, flags);
+    TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
 
-    IDirectDrawSurface7_AddRef(NewTarget);
-    IDirectDrawSurface7_Release(&device->target->IDirectDrawSurface7_iface);
-    return d3d_device_set_render_target(device, target);
+    return d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
 }
 
 static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
@@ -1877,29 +1863,25 @@ static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *
 }
 
 static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface,
-        IDirectDrawSurface4 *NewRenderTarget, DWORD flags)
+        IDirectDrawSurface4 *target, DWORD flags)
 {
+    struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface4(target);
     struct d3d_device *device = impl_from_IDirect3DDevice3(iface);
-    struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface4(NewRenderTarget);
 
-    TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
+    TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
 
-    IDirectDrawSurface4_AddRef(NewRenderTarget);
-    IDirectDrawSurface4_Release(&device->target->IDirectDrawSurface4_iface);
-    return d3d_device_set_render_target(device, target);
+    return d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
 }
 
 static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
-        IDirectDrawSurface *NewRenderTarget, DWORD flags)
+        IDirectDrawSurface *target, DWORD flags)
 {
+    struct ddraw_surface *target_impl = unsafe_impl_from_IDirectDrawSurface(target);
     struct d3d_device *device = impl_from_IDirect3DDevice2(iface);
-    struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface(NewRenderTarget);
 
-    TRACE("iface %p, target %p, flags %#x.\n", iface, NewRenderTarget, flags);
+    TRACE("iface %p, target %p, flags %#x.\n", iface, target, flags);
 
-    IDirectDrawSurface_AddRef(NewRenderTarget);
-    IDirectDrawSurface_Release(&device->target->IDirectDrawSurface_iface);
-    return d3d_device_set_render_target(device, target);
+    return d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
 }
 
 /*****************************************************************************
@@ -1922,6 +1904,7 @@ static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
 static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
 {
     struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
+    HRESULT hr;
 
     TRACE("iface %p, target %p.\n", iface, RenderTarget);
 
@@ -1929,11 +1912,10 @@ static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDire
         return DDERR_INVALIDPARAMS;
 
     wined3d_mutex_lock();
-    *RenderTarget = &device->target->IDirectDrawSurface7_iface;
-    IDirectDrawSurface7_AddRef(*RenderTarget);
+    hr = IUnknown_QueryInterface(device->rt_iface, &IID_IDirectDrawSurface7, (void **)RenderTarget);
     wined3d_mutex_unlock();
 
-    return D3D_OK;
+    return hr;
 }
 
 static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
@@ -6658,10 +6640,16 @@ struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface)
 enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
 {
     IDirectDrawSurface7 *depthStencil = NULL;
+    IDirectDrawSurface7 *render_target;
     static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
     struct ddraw_surface *dsi;
 
-    IDirectDrawSurface7_GetAttachedSurface(&device->target->IDirectDrawSurface7_iface, &depthcaps, &depthStencil);
+    if (device->rt_iface && SUCCEEDED(IUnknown_QueryInterface(device->rt_iface,
+            &IID_IDirectDrawSurface7, (void **)&render_target)))
+    {
+        IDirectDrawSurface7_GetAttachedSurface(render_target, &depthcaps, &depthStencil);
+        IDirectDrawSurface7_Release(render_target);
+    }
     if (!depthStencil)
     {
         TRACE("Setting wined3d depth stencil to NULL\n");
@@ -6678,7 +6666,7 @@ enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device
 }
 
 static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
-        struct ddraw_surface *target, UINT version, IUnknown *outer_unknown)
+        struct ddraw_surface *target, IUnknown *rt_iface, UINT version, IUnknown *outer_unknown)
 {
     static const D3DMATRIX ident =
     {
@@ -6707,7 +6695,6 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
         device->outer_unknown = &device->IUnknown_inner;
 
     device->ddraw = ddraw;
-    device->target = target;
     list_init(&device->viewport_list);
 
     if (!ddraw_handle_table_init(&device->handle_table, 64))
@@ -6733,17 +6720,9 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
         return hr;
     }
 
-    /* FIXME: This is broken. The target AddRef() makes some sense, because
-     * we store a pointer during initialization, but then that's also where
-     * the AddRef() should be. We don't store ddraw->d3d_target anywhere. */
-    /* AddRef the render target. Also AddRef the render target from ddraw,
-     * because if it is released before the app releases the D3D device, the
-     * D3D capabilities of wined3d will be uninitialized, which has bad effects.
-     *
-     * In most cases, those surfaces are the same anyway, but this will simply
-     * add another ref which is released when the device is destroyed. */
+    device->rt_iface = rt_iface;
     if (version != 1)
-        IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface);
+        IUnknown_AddRef(device->rt_iface);
 
     ddraw->d3ddevice = device;
 
@@ -6757,7 +6736,7 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
     return D3D_OK;
 }
 
-HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
+HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target, IUnknown *rt_iface,
         UINT version, struct d3d_device **device, IUnknown *outer_unknown)
 {
     struct d3d_device *object;
@@ -6787,8 +6766,7 @@ HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
         return DDERR_OUTOFMEMORY;
     }
 
-    hr = d3d_device_init(object, ddraw, target, version, outer_unknown);
-    if (FAILED(hr))
+    if (FAILED(hr = d3d_device_init(object, ddraw, target, rt_iface, version, outer_unknown)))
     {
         WARN("Failed to initialize device, hr %#x.\n", hr);
         HeapFree(GetProcessHeap(), 0, object);
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index ad67da0..d23fc9c 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -207,9 +207,10 @@ static HRESULT WINAPI ddraw_surface7_QueryInterface(IDirectDrawSurface7 *iface,
             wined3d_mutex_lock();
             if (!This->device1)
             {
-                HRESULT hr = d3d_device_create(This->ddraw, This, 1, &This->device1,
-                        (IUnknown *)&This->IDirectDrawSurface_iface);
-                if (FAILED(hr))
+                HRESULT hr;
+
+                if (FAILED(hr = d3d_device_create(This->ddraw, This, (IUnknown *)&This->IDirectDrawSurface_iface,
+                        1, &This->device1, (IUnknown *)&This->IDirectDrawSurface_iface)))
                 {
                     This->device1 = NULL;
                     wined3d_mutex_unlock();
-- 
1.7.10.4




More information about the wine-patches mailing list