ddraw: Complex surfaces form a tree.
This commit is contained in:
parent
87544190a5
commit
9e3e799ca3
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue