ddraw: Complex surfaces form a tree.

This commit is contained in:
Stefan Dösinger 2007-04-27 15:31:12 +02:00 committed by Alexandre Julliard
parent 87544190a5
commit 9e3e799ca3
5 changed files with 99 additions and 77 deletions

View File

@ -1797,9 +1797,6 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
(*ppSurf)->next_attached = NULL; (*ppSurf)->next_attached = NULL;
(*ppSurf)->first_attached = *ppSurf; (*ppSurf)->first_attached = *ppSurf;
(*ppSurf)->next_complex = NULL;
(*ppSurf)->first_complex = *ppSurf;
/* Needed to re-create the surface on an implementation change */ /* Needed to re-create the surface on an implementation change */
(*ppSurf)->ImplType = ImplType; (*ppSurf)->ImplType = ImplType;
@ -1958,10 +1955,10 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This,
{ {
UINT i, level = 0; UINT i, level = 0;
HRESULT hr; HRESULT hr;
IDirectDrawSurfaceImpl *last = root;
for(i = 0; i < count; i++) for(i = 0; i < count; i++)
{ {
IDirectDrawSurfaceImpl *object2 = NULL; IDirectDrawSurfaceImpl *object2 = NULL;
IDirectDrawSurfaceImpl *iterator;
/* increase the mipmap level, but only if a mipmap is created /* increase the mipmap level, but only if a mipmap is created
* In this case, also halve the size * In this case, also halve the size
@ -1982,12 +1979,9 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This,
return hr; return hr;
} }
/* Add the new surface to the complex attachment list */ /* Add the new surface to the complex attachment array */
object2->first_complex = root; last->complex_array[0] = object2;
object2->next_complex = NULL; last = object2;
iterator = root;
while(iterator->next_complex) iterator = iterator->next_complex;
iterator->next_complex = object2;
/* Remove the (possible) back buffer cap from the new surface description, /* Remove the (possible) back buffer cap from the new surface description,
* because only one surface in the flipping chain is a back buffer, one * because only one surface in the flipping chain is a back buffer, one
@ -2306,6 +2300,7 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
ERR("IDirectDrawImpl_CreateNewSurface failed with %08x\n", hr); ERR("IDirectDrawImpl_CreateNewSurface failed with %08x\n", hr);
return hr; return hr;
} }
object->is_complex_root = TRUE;
*Surf = ICOM_INTERFACE(object, IDirectDrawSurface7); *Surf = ICOM_INTERFACE(object, IDirectDrawSurface7);

View File

@ -232,8 +232,18 @@ struct IDirectDrawSurfaceImpl
/* This implementation handles attaching surfaces to other surfaces */ /* This implementation handles attaching surfaces to other surfaces */
IDirectDrawSurfaceImpl *next_attached; IDirectDrawSurfaceImpl *next_attached;
IDirectDrawSurfaceImpl *first_attached; IDirectDrawSurfaceImpl *first_attached;
IDirectDrawSurfaceImpl *next_complex;
IDirectDrawSurfaceImpl *first_complex; /* Complex surfaces are organized in a tree, although the tree is degenerated to a list in most cases.
* In mipmap and primary surfaces each level has only one attachment, which is the next surface level.
* Only the cube texture root has 6 surfaces attached, which then have a normal mipmap chain attached
* to them. So hardcode the array to 6, a dynamic array or a list would be an overkill.
*/
#define MAX_COMPLEX_ATTACHED 6
IDirectDrawSurfaceImpl *complex_array[MAX_COMPLEX_ATTACHED];
/* You can't traverse the tree upwards. Only a flag for Surface::Release because its needed there,
* but no pointer to prevent temptations to traverse it in the wrong direction.
*/
BOOL is_complex_root;
/* Surface description, for GetAttachedSurface */ /* Surface description, for GetAttachedSurface */
DDSURFACEDESC2 surface_desc; DDSURFACEDESC2 surface_desc;

View File

@ -379,11 +379,13 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
HeapFree(GetProcessHeap(), 0, This->Handles); HeapFree(GetProcessHeap(), 0, This->Handles);
TRACE("Releasing target %p %p\n", This->target, This->ddraw->d3d_target);
/* Release the render target and the WineD3D render target /* Release the render target and the WineD3D render target
* (See IDirect3D7::CreateDevice for more comments on this) * (See IDirect3D7::CreateDevice for more comments on this)
*/ */
IDirectDrawSurface7_Release(ICOM_INTERFACE(This->target, IDirectDrawSurface7)); IDirectDrawSurface7_Release(ICOM_INTERFACE(This->target, IDirectDrawSurface7));
IDirectDrawSurface7_Release(ICOM_INTERFACE(This->ddraw->d3d_target,IDirectDrawSurface7)); IDirectDrawSurface7_Release(ICOM_INTERFACE(This->ddraw->d3d_target,IDirectDrawSurface7));
TRACE("Target release done\n");
This->ddraw->d3ddevice = NULL; This->ddraw->d3ddevice = NULL;
@ -391,6 +393,7 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface)
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }
TRACE("Done\n");
return ref; return ref;
} }

View File

@ -785,7 +785,7 @@ DestroyCallback(IDirectDrawSurface7 *surf,
* part of a complex compound. They will get released when destroying * part of a complex compound. They will get released when destroying
* the root * the root
*/ */
if( (Impl->first_complex != Impl) || (Impl->first_attached != Impl) ) if( (!Impl->is_complex_root) || (Impl->first_attached != Impl) )
return DDENUMRET_OK; return DDENUMRET_OK;
/* Skip our depth stencil surface, it will be released with the render target */ /* Skip our depth stencil surface, it will be released with the render target */
if( Impl == ddraw->DepthStencilBuffer) if( Impl == ddraw->DepthStencilBuffer)

View File

@ -266,6 +266,8 @@ static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
* capabilities of the WineD3DDevice are uninitialized, which causes the * capabilities of the WineD3DDevice are uninitialized, which causes the
* swapchain to be released. * swapchain to be released.
* *
* When a complex sublevel falls to ref zero, then this is ignored.
*
* Returns: * Returns:
* The new refcount * The new refcount
* *
@ -284,11 +286,12 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
IDirectDrawSurfaceImpl *surf; IDirectDrawSurfaceImpl *surf;
IDirectDrawImpl *ddraw; IDirectDrawImpl *ddraw;
IUnknown *ifaceToRelease = This->ifaceToRelease; IUnknown *ifaceToRelease = This->ifaceToRelease;
int i;
/* Complex attached surfaces are destroyed implicitely when the root is released */ /* Complex attached surfaces are destroyed implicitely when the root is released */
if(This->first_complex != This) if(!This->is_complex_root)
{ {
WARN("(%p) Attempt to destroy a surface that is attached to a complex root %p\n", This, This->first_complex); WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
return ref; return ref;
} }
ddraw = This->ddraw; ddraw = This->ddraw;
@ -345,33 +348,60 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
* The same applies for textures without an * The same applies for textures without an
* IWineD3DTexture object attached * IWineD3DTexture object attached
*/ */
surf = This;
while(surf)
{
IParent *Parent; IParent *Parent;
for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
{
if(This->complex_array[i])
{
/* Only the topmost level can have more than 1 surfaces in the complex
* attachment array(Cube texture roots), for all others there is only
* one
*/
surf = This->complex_array[i];
while(surf)
{
IWineD3DSurface_GetParent(surf->WineD3DSurface, IWineD3DSurface_GetParent(surf->WineD3DSurface,
(IUnknown **) &Parent); (IUnknown **) &Parent);
IParent_Release(Parent); /* For the getParent */ IParent_Release(Parent); /* For the getParent */
IParent_Release(Parent); /* To release it */ IParent_Release(Parent); /* To release it */
surf = surf->next_complex; surf = surf->complex_array[0];
} }
} }
}
/* Now the top-level surface */
IWineD3DSurface_GetParent(This->WineD3DSurface,
(IUnknown **) &Parent);
IParent_Release(Parent); /* For the getParent */
IParent_Release(Parent); /* To release it */
}
/* The refcount test shows that the palette is detached when the surface is destroyed */ /* The refcount test shows that the palette is detached when the surface is destroyed */
IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7), IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
NULL); NULL);
/* Loop through all complex attached surfaces, /* Loop through all complex attached surfaces,
* and destroy them * and destroy them.
*
* Yet again, only the root can have more than one complexly attached surface, all the others
* have a total of one;
*/ */
while( (surf = This->next_complex) ) for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
{ {
This->next_complex = surf->next_complex; /* Unchain it from the complex listing */ if(!This->complex_array[i]) break;
IDirectDrawSurfaceImpl_Destroy(surf); /* Destroy it */
surf = This->complex_array[i];
This->complex_array[i] = NULL;
while(surf)
{
IDirectDrawSurfaceImpl *destroy = surf;
surf = surf->complex_array[0]; /* Iterate through the "tree" */
IDirectDrawSurfaceImpl_Destroy(destroy); /* Destroy it */
}
} }
/* Destroy the surface. /* Destroy the root surface.
*/ */
IDirectDrawSurfaceImpl_Destroy(This); IDirectDrawSurfaceImpl_Destroy(This);
@ -388,13 +418,14 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
* Returns an attached surface with the requested caps. Surface attachment * Returns an attached surface with the requested caps. Surface attachment
* and complex surfaces are not clearly described by the MSDN or sdk, * and complex surfaces are not clearly described by the MSDN or sdk,
* so this method is tricky and likely to contain problems. * so this method is tricky and likely to contain problems.
* This implementation searches the complex chain first, then the * This implementation searches the complex list first, then the
* attachment chain, and then it checks if the caps match to itself. * attachment chain.
* *
* The chains are searched from This down to the last surface in the chain, * The chains are searched from This down to the last surface in the chain,
* not from the first element in the chain. The first surface found is * not from the first element in the chain. The first surface found is
* returned. The MSDN says that this method fails if more than one surface * returned. The MSDN says that this method fails if more than one surface
* matches the caps, but apparently this is incorrect. * matches the caps, but it is not sure if that is right. The attachment
* structure may not even allow two matching surfaces.
* *
* The found surface is AddRef-ed before it is returned. * The found surface is AddRef-ed before it is returned.
* *
@ -416,6 +447,7 @@ IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface); ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
IDirectDrawSurfaceImpl *surf; IDirectDrawSurfaceImpl *surf;
DDSCAPS2 our_caps; DDSCAPS2 our_caps;
int i;
TRACE("(%p)->(%p,%p)\n", This, Caps, Surface); TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
@ -431,11 +463,11 @@ IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */ TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */
/* First, look at the complex chain */ for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
surf = This;
while( (surf = surf->next_complex) )
{ {
surf = This->complex_array[i];
if(!surf) break;
if (TRACE_ON(ddraw)) if (TRACE_ON(ddraw))
{ {
TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf, TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
@ -451,8 +483,7 @@ IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
/* MSDN: "This method fails if more than one surface is attached /* MSDN: "This method fails if more than one surface is attached
* that matches the capabilities requested." * that matches the capabilities requested."
* *
* The mipmap demo of the DirectX7 sdk shows what to do here: * Not sure how to test this.
* apparently apps expect the first found surface to be returned.
*/ */
TRACE("(%p): Returning surface %p\n", This, surf); TRACE("(%p): Returning surface %p\n", This, surf);
@ -480,13 +511,6 @@ IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) && if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) { ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
/* MSDN: "This method fails if more than one surface is attached
* that matches the capabilities requested."
*
* The mipmap demo of the DirectX7 sdk shows what to do here:
* apparently apps expect the first found surface to be returned.
*/
TRACE("(%p): Returning surface %p\n", This, surf); TRACE("(%p): Returning surface %p\n", This, surf);
*Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7); *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
IDirectDrawSurface7_AddRef(*Surface); IDirectDrawSurface7_AddRef(*Surface);
@ -494,22 +518,6 @@ IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
} }
} }
/* Is this valid? */
#if 0
if (((This->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
((This->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2) &&
This == This->first_complex)
{
TRACE("(%p): Returning surface %p\n", This, This);
*Surface = ICOM_INTERFACE(This, IDirectDrawSurface7);
IDirectDrawSurface7_AddRef(*Surface);
return DD_OK;
}
#endif
/* What to do here? Continue with the surface root?? */
TRACE("(%p) Didn't find a valid surface\n", This); TRACE("(%p) Didn't find a valid surface\n", This);
return DDERR_NOTFOUND; return DDERR_NOTFOUND;
} }
@ -737,9 +745,12 @@ IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
/***************************************************************************** /*****************************************************************************
* IDirectDrawSurface7::AddAttachedSurface * IDirectDrawSurface7::AddAttachedSurface
* *
* Attaches a surface to another surface. Surface attachments are * Attaches a surface to another surface. How the surface attachments work
* incorrectly described in the SDK and the MSDN, and this method * is not totally understood yet, and this method is prone to problems.
* is prone to bugs. The surface that is attached is AddRef-ed. * he surface that is attached is AddRef-ed.
*
* Tests with complex surfaces suggest that the surface attachments form a
* tree, but no method to test this has been found yet.
* *
* The attachment list consists of a first surface (first_attached) and * The attachment list consists of a first surface (first_attached) and
* for each surface a pointer to the next attached surface (next_attached). * for each surface a pointer to the next attached surface (next_attached).
@ -747,22 +758,20 @@ IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
* first_attached points to the surface itself. A surface that has * first_attached points to the surface itself. A surface that has
* no successors in the chain has next_attached set to NULL. * no successors in the chain has next_attached set to NULL.
* *
* Newly attached surfaces are attached right after the root surface. The * Newly attached surfaces are attached right after the root surface.
* complex chains are handled separately in a similar chain, with * If a surface is attached to a complex surface compound, it's attached to
* first_complex and next_complex. If a surface is attached to a complex * the surface that the app requested, not the complex root. See
* surface compound, it's attached to the surface that the app requested, * GetAttachedSurface for a description how surfaces are found.
* not the complex root. See GetAttachedSurface for a description
* how surfaces are found.
* *
* This is how the current implementation works, and it was coded by looking * This is how the current implementation works, and it was coded by looking
* at the needs of the applications. * at the needs of the applications.
* *
* So far only Z-Buffer attachments are tested, but there's no code yet * So far only Z-Buffer attachments are tested, and they are activated in
* to activate them. Mipmaps could be tricky to activate in WineD3D. * WineD3D. Mipmaps could be tricky to activate in WineD3D.
* Back buffers should work in 2D mode, but they are not tested. * Back buffers should work in 2D mode, but they are not tested(Not sure if
* Rendering to the primary surface and switching between that and * they can be attached at all). Rendering to the primary surface and
* double buffering is not yet implemented in WineD3D, so for 3D it might * switching between that and double buffering is not yet implemented in
* have unexpected results. * WineD3D, so for 3D it might have unexpected results.
* *
* Params: * Params:
* Attach: Surface to attach to iface * Attach: Surface to attach to iface
@ -1222,6 +1231,7 @@ IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface); ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
IDirectDrawSurfaceImpl *surf; IDirectDrawSurfaceImpl *surf;
DDSURFACEDESC2 desc; DDSURFACEDESC2 desc;
int i;
/* Attached surfaces aren't handled in WineD3D */ /* Attached surfaces aren't handled in WineD3D */
TRACE("(%p)->(%p,%p)\n",This,context,cb); TRACE("(%p)->(%p,%p)\n",This,context,cb);
@ -1229,8 +1239,11 @@ IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
if(!cb) if(!cb)
return DDERR_INVALIDPARAMS; return DDERR_INVALIDPARAMS;
for (surf = This->next_complex; surf != NULL; surf = surf->next_complex) for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
{ {
surf = This->complex_array[i];
if(!surf) break;
IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7)); IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
desc = surf->surface_desc; desc = surf->surface_desc;
/* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */ /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
@ -2258,6 +2271,7 @@ IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
break; break;
} }
TRACE("Setting palette on %p\n", attach);
IDirectDrawSurface7_SetPalette(attach, IDirectDrawSurface7_SetPalette(attach,
Pal); Pal);
surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach); surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach);