Commit 25c0941e authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

ddraw: Add a separate function for surface cleanup.

parent f6e4f4a1
......@@ -293,73 +293,24 @@ void ddraw_surface_destroy(IDirectDrawSurfaceImpl *This)
HeapFree(GetProcessHeap(), 0, This);
}
/*****************************************************************************
* IDirectDrawSurface7::Release
*
* Reduces the surface's refcount by 1. If the refcount falls to 0, the
* surface is destroyed.
*
* Destroying the surface is a bit tricky. For the connection between
* WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
* It has a nice graph explaining the connection.
*
* What happens here is basically this:
* When a surface is destroyed, its WineD3DSurface is released,
* and the refcount of the DirectDraw interface is reduced by 1. If it has
* complex surfaces attached to it, then these surfaces are destroyed too,
* regardless of their refcount. If any surface being destroyed has another
* surface attached to it (with a "soft" attachment, not complex), then
* this surface is detached with DeleteAttachedSurface.
*
* When the surface is a texture, the WineD3DTexture is released.
* If the surface is the Direct3D render target, then the D3D
* capabilities of the WineD3DDevice are uninitialized, which causes the
* swapchain to be released.
*
* When a complex sublevel falls to ref zero, then this is ignored.
*
* Returns:
* The new refcount
*
*****************************************************************************/
static ULONG WINAPI ddraw_surface7_Release(IDirectDrawSurface7 *iface)
static void ddraw_surface_cleanup(IDirectDrawSurfaceImpl *surface)
{
IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("%p decreasing refcount to %u.\n", This, ref);
if (ref == 0)
{
IDirectDrawSurfaceImpl *surf;
IDirectDrawImpl *ddraw;
IUnknown *ifaceToRelease = This->ifaceToRelease;
IUnknown *ifaceToRelease;
UINT i;
/* Complex attached surfaces are destroyed implicitly when the root is released */
EnterCriticalSection(&ddraw_cs);
if(!This->is_complex_root)
{
WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
LeaveCriticalSection(&ddraw_cs);
return ref;
}
ddraw = This->ddraw;
TRACE("surface %p.\n", surface);
/* If it's a texture, destroy the WineD3DTexture.
* WineD3D will destroy the IParent interfaces
* of the sublevels, which destroys the WineD3DSurfaces.
* Set the surfaces to NULL to avoid destroying them again later
*/
if (This->wined3d_texture)
wined3d_texture_decref(This->wined3d_texture);
if (surface->wined3d_texture) /* If it's a texture, destroy the wined3d texture. */
wined3d_texture_decref(surface->wined3d_texture);
else if (surface->wined3d_swapchain)
{
IDirectDrawImpl *ddraw = surface->ddraw;
/* If it's the RenderTarget, destroy the d3ddevice */
else if (This->wined3d_swapchain)
/* If it's the render target, destroy the D3D device. */
if (ddraw->d3d_initialized && surface == ddraw->d3d_target)
{
if((ddraw->d3d_initialized) && (This == ddraw->d3d_target)) {
TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
TRACE("Destroying the render target, uninitializing D3D.\n");
for (i = 0; i < ddraw->numConvertedDecls; ++i)
{
......@@ -370,61 +321,55 @@ static ULONG WINAPI ddraw_surface7_Release(IDirectDrawSurface7 *iface)
if (FAILED(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice)))
{
/* Not good */
ERR("(%p) Failed to uninit 3D\n", This);
ERR("Failed to uninit 3D.\n");
}
else
{
/* Free the d3d window if one was created */
if(ddraw->d3d_window != 0 && ddraw->d3d_window != ddraw->dest_window)
/* Free the d3d window if one was created. */
if (ddraw->d3d_window && ddraw->d3d_window != ddraw->dest_window)
{
TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
TRACE("Destroying the hidden render window %p.\n", ddraw->d3d_window);
DestroyWindow(ddraw->d3d_window);
ddraw->d3d_window = 0;
}
/* Unset the pointers */
}
This->wined3d_swapchain = NULL; /* Uninit3D releases the swapchain */
ddraw->d3d_initialized = FALSE;
ddraw->d3d_target = NULL;
}
else
{
IWineD3DDevice_UninitGDI(ddraw->wineD3DDevice);
This->wined3d_swapchain = NULL;
}
/* Reset to the default surface implementation type. This is needed if apps use
* non render target surfaces and expect blits to work after destroying the render
* target.
surface->wined3d_swapchain = NULL;
/* Reset to the default surface implementation type. This is needed
* if applications use non render target surfaces and expect blits to
* work after destroying the render target.
*
* TODO: Recreate existing offscreen surfaces
*/
* TODO: Recreate existing offscreen surfaces. */
ddraw->ImplType = DefaultSurfaceType;
/* Write a trace because D3D unloading was the reason for many
* crashes during development.
*/
TRACE("(%p) D3D unloaded\n", This);
TRACE("D3D unloaded.\n");
}
/* The refcount test shows that the palette is detached when the surface is destroyed */
IDirectDrawSurface7_SetPalette((IDirectDrawSurface7 *)This, NULL);
/* The refcount test shows that the palette is detached when the surface
* is destroyed. */
IDirectDrawSurface7_SetPalette((IDirectDrawSurface7 *)surface, NULL);
/* Loop through all complex attached surfaces,
* and destroy them.
/* Loop through all complex attached surfaces and destroy them.
*
* Yet again, only the root can have more than one complexly attached surface, all the others
* have a total of one;
*/
for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
* Yet again, only the root can have more than one complexly attached
* surface, all the others have a total of one. */
for (i = 0; i < MAX_COMPLEX_ATTACHED; ++i)
{
if(!This->complex_array[i]) break;
if (!surface->complex_array[i])
break;
surf = This->complex_array[i];
This->complex_array[i] = NULL;
while(surf)
surf = surface->complex_array[i];
surface->complex_array[i] = NULL;
while (surf)
{
IDirectDrawSurfaceImpl *destroy = surf;
surf = surf->complex_array[0]; /* Iterate through the "tree" */
......@@ -432,11 +377,63 @@ static ULONG WINAPI ddraw_surface7_Release(IDirectDrawSurface7 *iface)
}
}
ifaceToRelease = surface->ifaceToRelease;
/* Destroy the root surface. */
ddraw_surface_destroy(This);
ddraw_surface_destroy(surface);
/* Reduce the ddraw refcount */
if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
if (ifaceToRelease)
IUnknown_Release(ifaceToRelease);
}
/*****************************************************************************
* IDirectDrawSurface7::Release
*
* Reduces the surface's refcount by 1. If the refcount falls to 0, the
* surface is destroyed.
*
* Destroying the surface is a bit tricky. For the connection between
* WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
* It has a nice graph explaining the connection.
*
* What happens here is basically this:
* When a surface is destroyed, its WineD3DSurface is released,
* and the refcount of the DirectDraw interface is reduced by 1. If it has
* complex surfaces attached to it, then these surfaces are destroyed too,
* regardless of their refcount. If any surface being destroyed has another
* surface attached to it (with a "soft" attachment, not complex), then
* this surface is detached with DeleteAttachedSurface.
*
* When the surface is a texture, the WineD3DTexture is released.
* If the surface is the Direct3D render target, then the D3D
* capabilities of the WineD3DDevice are uninitialized, which causes the
* swapchain to be released.
*
* When a complex sublevel falls to ref zero, then this is ignored.
*
* Returns:
* The new refcount
*
*****************************************************************************/
static ULONG WINAPI ddraw_surface7_Release(IDirectDrawSurface7 *iface)
{
IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
ULONG ref = InterlockedDecrement(&This->ref);
TRACE("%p decreasing refcount to %u.\n", This, ref);
if (ref == 0)
{
/* Complex attached surfaces are destroyed implicitly when the root is released */
EnterCriticalSection(&ddraw_cs);
if(!This->is_complex_root)
{
WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
LeaveCriticalSection(&ddraw_cs);
return ref;
}
ddraw_surface_cleanup(This);
LeaveCriticalSection(&ddraw_cs);
}
......
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