From 9e3e799ca3e5e74e20f9c3da1aefd74dfb15e9f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Fri, 27 Apr 2007 15:31:12 +0200 Subject: [PATCH] ddraw: Complex surfaces form a tree. --- dlls/ddraw/ddraw.c | 15 ++-- dlls/ddraw/ddraw_private.h | 14 +++- dlls/ddraw/device.c | 3 + dlls/ddraw/main.c | 2 +- dlls/ddraw/surface.c | 142 ++++++++++++++++++++----------------- 5 files changed, 99 insertions(+), 77 deletions(-) diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c index f6e153bf36e..0f6b6db5bf3 100644 --- a/dlls/ddraw/ddraw.c +++ b/dlls/ddraw/ddraw.c @@ -1797,9 +1797,6 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This, (*ppSurf)->next_attached = NULL; (*ppSurf)->first_attached = *ppSurf; - (*ppSurf)->next_complex = NULL; - (*ppSurf)->first_complex = *ppSurf; - /* Needed to re-create the surface on an implementation change */ (*ppSurf)->ImplType = ImplType; @@ -1958,10 +1955,10 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This, { UINT i, level = 0; HRESULT hr; + IDirectDrawSurfaceImpl *last = root; for(i = 0; i < count; i++) { IDirectDrawSurfaceImpl *object2 = NULL; - IDirectDrawSurfaceImpl *iterator; /* increase the mipmap level, but only if a mipmap is created * In this case, also halve the size @@ -1982,12 +1979,9 @@ CreateAdditionalSurfaces(IDirectDrawImpl *This, return hr; } - /* Add the new surface to the complex attachment list */ - object2->first_complex = root; - object2->next_complex = NULL; - iterator = root; - while(iterator->next_complex) iterator = iterator->next_complex; - iterator->next_complex = object2; + /* Add the new surface to the complex attachment array */ + last->complex_array[0] = object2; + last = object2; /* Remove the (possible) back buffer cap from the new surface description, * 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); return hr; } + object->is_complex_root = TRUE; *Surf = ICOM_INTERFACE(object, IDirectDrawSurface7); diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 14db3c39aac..85e15bc8e3e 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -232,8 +232,18 @@ struct IDirectDrawSurfaceImpl /* This implementation handles attaching surfaces to other surfaces */ IDirectDrawSurfaceImpl *next_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 */ DDSURFACEDESC2 surface_desc; diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index 14866f3614a..e7e975d49ae 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -379,11 +379,13 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface) 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 * (See IDirect3D7::CreateDevice for more comments on this) */ IDirectDrawSurface7_Release(ICOM_INTERFACE(This->target, IDirectDrawSurface7)); IDirectDrawSurface7_Release(ICOM_INTERFACE(This->ddraw->d3d_target,IDirectDrawSurface7)); + TRACE("Target release done\n"); This->ddraw->d3ddevice = NULL; @@ -391,6 +393,7 @@ IDirect3DDeviceImpl_7_Release(IDirect3DDevice7 *iface) HeapFree(GetProcessHeap(), 0, This); } + TRACE("Done\n"); return ref; } diff --git a/dlls/ddraw/main.c b/dlls/ddraw/main.c index cfe069ca65f..239460cfd4d 100644 --- a/dlls/ddraw/main.c +++ b/dlls/ddraw/main.c @@ -785,7 +785,7 @@ DestroyCallback(IDirectDrawSurface7 *surf, * part of a complex compound. They will get released when destroying * the root */ - if( (Impl->first_complex != Impl) || (Impl->first_attached != Impl) ) + if( (!Impl->is_complex_root) || (Impl->first_attached != Impl) ) return DDENUMRET_OK; /* Skip our depth stencil surface, it will be released with the render target */ if( Impl == ddraw->DepthStencilBuffer) diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index e6e316ed222..3c64deb48ed 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -266,6 +266,8 @@ static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This) * 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 * @@ -284,11 +286,12 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface) IDirectDrawSurfaceImpl *surf; IDirectDrawImpl *ddraw; IUnknown *ifaceToRelease = This->ifaceToRelease; + int i; /* 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; } ddraw = This->ddraw; @@ -345,17 +348,33 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface) * The same applies for textures without an * IWineD3DTexture object attached */ - surf = This; - while(surf) - { - IParent *Parent; + IParent *Parent; - IWineD3DSurface_GetParent(surf->WineD3DSurface, - (IUnknown **) &Parent); - IParent_Release(Parent); /* For the getParent */ - IParent_Release(Parent); /* To release it */ - surf = surf->next_complex; + 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, + (IUnknown **) &Parent); + IParent_Release(Parent); /* For the getParent */ + IParent_Release(Parent); /* To release it */ + 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 */ @@ -363,15 +382,26 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface) NULL); /* 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 */ - IDirectDrawSurfaceImpl_Destroy(surf); /* Destroy it */ + if(!This->complex_array[i]) break; + + 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); @@ -388,13 +418,14 @@ IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface) * Returns an attached surface with the requested caps. Surface attachment * and complex surfaces are not clearly described by the MSDN or sdk, * so this method is tricky and likely to contain problems. - * This implementation searches the complex chain first, then the - * attachment chain, and then it checks if the caps match to itself. + * This implementation searches the complex list first, then the + * attachment 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 * 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. * @@ -416,6 +447,7 @@ IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface, ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface); IDirectDrawSurfaceImpl *surf; DDSCAPS2 our_caps; + int i; 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 */ - /* First, look at the complex chain */ - surf = This; - - while( (surf = surf->next_complex) ) + for(i = 0; i < MAX_COMPLEX_ATTACHED; i++) { + surf = This->complex_array[i]; + if(!surf) break; + if (TRACE_ON(ddraw)) { 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 * 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. + * Not sure how to test this. */ 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) && ((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); *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7); 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); return DDERR_NOTFOUND; } @@ -737,9 +745,12 @@ IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface, /***************************************************************************** * IDirectDrawSurface7::AddAttachedSurface * - * Attaches a surface to another surface. Surface attachments are - * incorrectly described in the SDK and the MSDN, and this method - * is prone to bugs. The surface that is attached is AddRef-ed. + * Attaches a surface to another surface. How the surface attachments work + * is not totally understood yet, and this method is prone to problems. + * 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 * 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 * no successors in the chain has next_attached set to NULL. * - * Newly attached surfaces are attached right after the root surface. The - * complex chains are handled separately in a similar chain, with - * first_complex and next_complex. If a surface is attached to a complex - * surface compound, it's attached to the surface that the app requested, - * not the complex root. See GetAttachedSurface for a description - * how surfaces are found. + * Newly attached surfaces are attached right after the root surface. + * If a surface is attached to a complex surface compound, it's attached to + * the surface that the app requested, 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 * at the needs of the applications. * - * So far only Z-Buffer attachments are tested, but there's no code yet - * to activate them. Mipmaps could be tricky to activate in WineD3D. - * Back buffers should work in 2D mode, but they are not tested. - * Rendering to the primary surface and switching between that and - * double buffering is not yet implemented in WineD3D, so for 3D it might - * have unexpected results. + * So far only Z-Buffer attachments are tested, and they are activated in + * WineD3D. Mipmaps could be tricky to activate in WineD3D. + * Back buffers should work in 2D mode, but they are not tested(Not sure if + * they can be attached at all). Rendering to the primary surface and + * switching between that and double buffering is not yet implemented in + * WineD3D, so for 3D it might have unexpected results. * * Params: * Attach: Surface to attach to iface @@ -1222,6 +1231,7 @@ IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface, ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface); IDirectDrawSurfaceImpl *surf; DDSURFACEDESC2 desc; + int i; /* Attached surfaces aren't handled in WineD3D */ TRACE("(%p)->(%p,%p)\n",This,context,cb); @@ -1229,8 +1239,11 @@ IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface, if(!cb) 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)); desc = surf->surface_desc; /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */ @@ -2258,6 +2271,7 @@ IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface, break; } + TRACE("Setting palette on %p\n", attach); IDirectDrawSurface7_SetPalette(attach, Pal); surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attach);