Refcounting fun

Stefan Dösinger stefandoesinger at gmx.at
Sun Feb 12 15:35:37 CST 2006


Hi,
> Are you talking about IDirect3DSurface9 <=> IDirect3DTexture9 or do
> you mean IDirect3DSurface9 <=> IWineD3DSurface?
I meant IWineD3DSurface <=> IWineD3DTexture and Parent(IWineD3DSurface) <=> 
Parent(IWineD3DTexture). The first case has no consequences for ddraw, if the 
secound one is forced by WineD3D this would cause a connection between 
IDirect3DSurface9 <=> IDirect3DTexture9 and between {Direct Draw texture root 
surface} <=> {Other ddraw texture surfaces}

> Unfortunately my knowledge of ddraw and
> d3d7 is somewhat limited, so it's a bit hard for me to oversee all the
> implications those changes would have for ddraw / d3d7. The choice for
> Surface and Texture as an example is somewhat arbitrary I guess, but
> probably the one for which it matters the most. (As in, is most likely to
> break stuff if it isn't implemented correctly). In principle it would
> change for any object that has a container or uses similar construction.
> Perhaps it would even make sense to forward AddRef and Release calls for
> all d3d7/8/9 objects that directly wrap a wined3d object.
>
> For reference, the code for Release & CleanUp would look something
> like this for the different objects:
I could deal with such a Release / cleanup difference in ddraw, but I don't 
like the idea. I think it creates a too complex connection between WineD3D 
and the d3d libs. My d3d9 knowledge is limited too, but what if you do 
something like this: (sort of pseude-code only)

IDirect3DSurface9::AddRef
{
  if(This->container /* Or get the container from WineD3D */)
  {
     return IUnknown_AddRef(This->container);
  }
  else
  {
    ULONG ref = This->ref++;
    etc
  }
}

IDirect3DSurface9::Releae
{
  if(This->container /* Or get the container from WineD3D */)
  {
     return IUnknown_Release(This->container);
  }
  else
  {
    ULONG ref = This->ref--;
    
    if(ref == 0)
    {
       /*Destroy code*/
       IWineD3DSurface_Release(This->wineD3DSurface);
    }
    return ref;
  }
}

IDirect3DTexure9::AddRef
{
    /* normal addref, nothing special */
}

IDirect3DTexure9::Release
{
  ULONG ref = This->ref--;

  if(ref == 0)
  {
    for(all surfaces in this container)
    {
      surfaceImpl->container = NULL;
      /* Or place this call in WineD3DTexture::Releaase*/

      IWineD3DTexture_Release(This->wineD3DTexture);
      /* IWineD3DTexture_Release will call the release method
       * of the IDirect3D9Surface(because it releases the parent),
       * run the surface's release code(not the container, because
       * it's set to NULL and destroy the surface, because it's own
       * refcount is 1 from creation, and we never changed it.
       * The D3D9 surface release code releases the wineD3DSurface,
       * and everthing is cleaned.
       */

       HeapFree(GetProcessHeap, 0, This);
    }
  }
}

The important part is to set the surface's container when they are created, 
before the first AddRef() or Release() is called, and to set the container to 
NULL when the container is destroyed and before the surfaces are released. 
You can eighter track the containers in d3d9, or use wineD3D to get the 
container.

Could this work?

Stefan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-devel/attachments/20060212/2dfb00b1/attachment.pgp


More information about the wine-devel mailing list