Commit df01e8d6 authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

ddraw: Fix render target refcount handling.

Similar to AddAttachedSurface() / DeleteAttachedSurface(), we should Release the interface version that we stored. (And actually store the interface that we AddRef.)
parent 6594212d
...@@ -4513,9 +4513,10 @@ static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid, ...@@ -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); TRACE("iface %p, riid %s, surface %p, device %p.\n", iface, debugstr_guid(riid), surface, device);
wined3d_mutex_lock(); wined3d_mutex_lock();
hr = d3d_device_create(ddraw, target, 7, &object, NULL); if (SUCCEEDED(hr = d3d_device_create(ddraw, target, (IUnknown *)surface, 7, &object, NULL)))
if (SUCCEEDED(hr)) {
*device = &object->IDirect3DDevice7_iface; *device = &object->IDirect3DDevice7_iface;
}
else else
{ {
WARN("Failed to create device, hr %#x.\n", hr); WARN("Failed to create device, hr %#x.\n", hr);
...@@ -4541,9 +4542,10 @@ static HRESULT WINAPI d3d3_CreateDevice(IDirect3D3 *iface, REFCLSID riid, ...@@ -4541,9 +4542,10 @@ static HRESULT WINAPI d3d3_CreateDevice(IDirect3D3 *iface, REFCLSID riid,
return CLASS_E_NOAGGREGATION; return CLASS_E_NOAGGREGATION;
wined3d_mutex_lock(); wined3d_mutex_lock();
hr = d3d_device_create(ddraw, surface_impl, 3, &device_impl, NULL); if (SUCCEEDED(hr = d3d_device_create(ddraw, surface_impl, (IUnknown *)surface, 3, &device_impl, NULL)))
if (SUCCEEDED(hr)) {
*device = &device_impl->IDirect3DDevice3_iface; *device = &device_impl->IDirect3DDevice3_iface;
}
else else
{ {
WARN("Failed to create device, hr %#x.\n", hr); WARN("Failed to create device, hr %#x.\n", hr);
...@@ -4566,9 +4568,10 @@ static HRESULT WINAPI d3d2_CreateDevice(IDirect3D2 *iface, REFCLSID riid, ...@@ -4566,9 +4568,10 @@ static HRESULT WINAPI d3d2_CreateDevice(IDirect3D2 *iface, REFCLSID riid,
iface, debugstr_guid(riid), surface, device); iface, debugstr_guid(riid), surface, device);
wined3d_mutex_lock(); wined3d_mutex_lock();
hr = d3d_device_create(ddraw, surface_impl, 2, &device_impl, NULL); if (SUCCEEDED(hr = d3d_device_create(ddraw, surface_impl, (IUnknown *)surface, 2, &device_impl, NULL)))
if (SUCCEEDED(hr)) {
*device = &device_impl->IDirect3DDevice2_iface; *device = &device_impl->IDirect3DDevice2_iface;
}
else else
{ {
WARN("Failed to create device, hr %#x.\n", hr); WARN("Failed to create device, hr %#x.\n", hr);
......
...@@ -277,7 +277,7 @@ struct d3d_device ...@@ -277,7 +277,7 @@ struct d3d_device
IUnknown *outer_unknown; IUnknown *outer_unknown;
struct wined3d_device *wined3d_device; struct wined3d_device *wined3d_device;
struct ddraw *ddraw; struct ddraw *ddraw;
struct ddraw_surface *target; IUnknown *rt_iface;
struct wined3d_buffer *index_buffer; struct wined3d_buffer *index_buffer;
UINT index_buffer_size; UINT index_buffer_size;
...@@ -315,7 +315,7 @@ struct d3d_device ...@@ -315,7 +315,7 @@ struct d3d_device
D3DMATRIXHANDLE world, proj, view; 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; 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; enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device) DECLSPEC_HIDDEN;
......
...@@ -224,6 +224,7 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface) ...@@ -224,6 +224,7 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
{ {
struct d3d_device *This = impl_from_IUnknown(iface); struct d3d_device *This = impl_from_IUnknown(iface);
ULONG ref = InterlockedDecrement(&This->ref); ULONG ref = InterlockedDecrement(&This->ref);
IUnknown *rt_iface;
TRACE("%p decreasing refcount to %u.\n", This, ref); TRACE("%p decreasing refcount to %u.\n", This, ref);
...@@ -308,11 +309,12 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface) ...@@ -308,11 +309,12 @@ static ULONG WINAPI d3d_device_inner_Release(IUnknown *iface)
IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface); IDirect3DDevice3_DeleteViewport(&This->IDirect3DDevice3_iface, &vp->IDirect3DViewport3_iface);
} }
TRACE("Releasing target %p.\n", This->target); TRACE("Releasing render target %p.\n", This->rt_iface);
/* Release the render target. */ rt_iface = This->rt_iface;
This->rt_iface = NULL;
if (This->version != 1) if (This->version != 1)
IDirectDrawSurface7_Release(&This->target->IDirectDrawSurface7_iface); IUnknown_Release(rt_iface);
TRACE("Target release done\n"); TRACE("Render target release done.\n");
This->ddraw->d3ddevice = NULL; This->ddraw->d3ddevice = NULL;
...@@ -1794,31 +1796,14 @@ static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, ID ...@@ -1794,31 +1796,14 @@ static HRESULT WINAPI d3d_device2_GetCurrentViewport(IDirect3DDevice2 *iface, ID
(IDirect3DViewport3 **)viewport); (IDirect3DViewport3 **)viewport);
} }
/***************************************************************************** static HRESULT d3d_device_set_render_target(struct d3d_device *device,
* IDirect3DDevice7::SetRenderTarget struct ddraw_surface *target, IUnknown *rt_iface)
*
* 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)
{ {
HRESULT hr; HRESULT hr;
wined3d_mutex_lock(); wined3d_mutex_lock();
if (device->target == target) if (device->rt_iface == rt_iface)
{ {
TRACE("No-op SetRenderTarget operation, not doing anything\n"); TRACE("No-op SetRenderTarget operation, not doing anything\n");
wined3d_mutex_unlock(); wined3d_mutex_unlock();
...@@ -1830,7 +1815,10 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct dd ...@@ -1830,7 +1815,10 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct dd
wined3d_mutex_unlock(); wined3d_mutex_unlock();
return DDERR_INVALIDPARAMS; 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, if (FAILED(hr = wined3d_device_set_render_target(device->wined3d_device,
0, target->wined3d_surface, FALSE))) 0, target->wined3d_surface, FALSE)))
{ {
...@@ -1845,16 +1833,14 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct dd ...@@ -1845,16 +1833,14 @@ static HRESULT d3d_device_set_render_target(struct d3d_device *device, struct dd
} }
static HRESULT d3d_device7_SetRenderTarget(IDirect3DDevice7 *iface, 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 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); return d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
IDirectDrawSurface7_Release(&device->target->IDirectDrawSurface7_iface);
return d3d_device_set_render_target(device, target);
} }
static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface, static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUSetup(IDirect3DDevice7 *iface,
...@@ -1877,29 +1863,25 @@ static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 * ...@@ -1877,29 +1863,25 @@ static HRESULT WINAPI d3d_device7_SetRenderTarget_FPUPreserve(IDirect3DDevice7 *
} }
static HRESULT WINAPI d3d_device3_SetRenderTarget(IDirect3DDevice3 *iface, 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 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); return d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
IDirectDrawSurface4_Release(&device->target->IDirectDrawSurface4_iface);
return d3d_device_set_render_target(device, target);
} }
static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface, 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 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); return d3d_device_set_render_target(device, target_impl, (IUnknown *)target);
IDirectDrawSurface_Release(&device->target->IDirectDrawSurface_iface);
return d3d_device_set_render_target(device, target);
} }
/***************************************************************************** /*****************************************************************************
...@@ -1922,6 +1904,7 @@ static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface, ...@@ -1922,6 +1904,7 @@ static HRESULT WINAPI d3d_device2_SetRenderTarget(IDirect3DDevice2 *iface,
static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget) static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDirectDrawSurface7 **RenderTarget)
{ {
struct d3d_device *device = impl_from_IDirect3DDevice7(iface); struct d3d_device *device = impl_from_IDirect3DDevice7(iface);
HRESULT hr;
TRACE("iface %p, target %p.\n", iface, RenderTarget); TRACE("iface %p, target %p.\n", iface, RenderTarget);
...@@ -1929,11 +1912,10 @@ static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDire ...@@ -1929,11 +1912,10 @@ static HRESULT WINAPI d3d_device7_GetRenderTarget(IDirect3DDevice7 *iface, IDire
return DDERR_INVALIDPARAMS; return DDERR_INVALIDPARAMS;
wined3d_mutex_lock(); wined3d_mutex_lock();
*RenderTarget = &device->target->IDirectDrawSurface7_iface; hr = IUnknown_QueryInterface(device->rt_iface, &IID_IDirectDrawSurface7, (void **)RenderTarget);
IDirectDrawSurface7_AddRef(*RenderTarget);
wined3d_mutex_unlock(); wined3d_mutex_unlock();
return D3D_OK; return hr;
} }
static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget) static HRESULT WINAPI d3d_device3_GetRenderTarget(IDirect3DDevice3 *iface, IDirectDrawSurface4 **RenderTarget)
...@@ -6658,10 +6640,16 @@ struct d3d_device *unsafe_impl_from_IDirect3DDevice(IDirect3DDevice *iface) ...@@ -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) enum wined3d_depth_buffer_type d3d_device_update_depth_stencil(struct d3d_device *device)
{ {
IDirectDrawSurface7 *depthStencil = NULL; IDirectDrawSurface7 *depthStencil = NULL;
IDirectDrawSurface7 *render_target;
static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 }; static DDSCAPS2 depthcaps = { DDSCAPS_ZBUFFER, 0, 0, 0 };
struct ddraw_surface *dsi; 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) if (!depthStencil)
{ {
TRACE("Setting wined3d depth stencil to NULL\n"); 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 ...@@ -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, 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 = static const D3DMATRIX ident =
{ {
...@@ -6707,7 +6695,6 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, ...@@ -6707,7 +6695,6 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
device->outer_unknown = &device->IUnknown_inner; device->outer_unknown = &device->IUnknown_inner;
device->ddraw = ddraw; device->ddraw = ddraw;
device->target = target;
list_init(&device->viewport_list); list_init(&device->viewport_list);
if (!ddraw_handle_table_init(&device->handle_table, 64)) 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, ...@@ -6733,17 +6720,9 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
return hr; return hr;
} }
/* FIXME: This is broken. The target AddRef() makes some sense, because device->rt_iface = rt_iface;
* 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. */
if (version != 1) if (version != 1)
IDirectDrawSurface7_AddRef(&target->IDirectDrawSurface7_iface); IUnknown_AddRef(device->rt_iface);
ddraw->d3ddevice = device; ddraw->d3ddevice = device;
...@@ -6757,7 +6736,7 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw, ...@@ -6757,7 +6736,7 @@ static HRESULT d3d_device_init(struct d3d_device *device, struct ddraw *ddraw,
return D3D_OK; 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) UINT version, struct d3d_device **device, IUnknown *outer_unknown)
{ {
struct d3d_device *object; struct d3d_device *object;
...@@ -6787,8 +6766,7 @@ HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target, ...@@ -6787,8 +6766,7 @@ HRESULT d3d_device_create(struct ddraw *ddraw, struct ddraw_surface *target,
return DDERR_OUTOFMEMORY; return DDERR_OUTOFMEMORY;
} }
hr = d3d_device_init(object, ddraw, target, version, outer_unknown); if (FAILED(hr = d3d_device_init(object, ddraw, target, rt_iface, version, outer_unknown)))
if (FAILED(hr))
{ {
WARN("Failed to initialize device, hr %#x.\n", hr); WARN("Failed to initialize device, hr %#x.\n", hr);
HeapFree(GetProcessHeap(), 0, object); HeapFree(GetProcessHeap(), 0, object);
......
...@@ -207,9 +207,10 @@ static HRESULT WINAPI ddraw_surface7_QueryInterface(IDirectDrawSurface7 *iface, ...@@ -207,9 +207,10 @@ static HRESULT WINAPI ddraw_surface7_QueryInterface(IDirectDrawSurface7 *iface,
wined3d_mutex_lock(); wined3d_mutex_lock();
if (!This->device1) if (!This->device1)
{ {
HRESULT hr = d3d_device_create(This->ddraw, This, 1, &This->device1, HRESULT hr;
(IUnknown *)&This->IDirectDrawSurface_iface);
if (FAILED(hr)) if (FAILED(hr = d3d_device_create(This->ddraw, This, (IUnknown *)&This->IDirectDrawSurface_iface,
1, &This->device1, (IUnknown *)&This->IDirectDrawSurface_iface)))
{ {
This->device1 = NULL; This->device1 = NULL;
wined3d_mutex_unlock(); wined3d_mutex_unlock();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment