Refcounting fun

Stefan Dösinger stefandoesinger at
Sun Feb 12 09:50:51 CST 2006

> One way to solve this would be to have wined3d handle the reference
> counting for d3d7/8/9 as well, so that their AddRef/Release calls just
> call AddRef/Release on the wined3d object they wrap. That would also
> mean we need to pass a pointer to the d3d7/8/9 object's cleanup
> function. (Releasing a d3d9 surface to 0 should cause a d3d9 texture
> to be freed). Note that for creating a texture, currently a similair
> construction is used, in that IWineD3DDeviceImpl_CreateTexture gets
> passed a pointer to a d3d9 surface create function, in order to create
> the texture's surfaces.
I have had some reference counting problems with ddraw too, but they were more 
simple(Mainly, that needed WineD3D objects had no ddraw counterpart, or that 
WineD3D destroys the ddraw parents, although they were still needed).

DDraw doesn't use containers, instead it has surface attachments and complex 
surfaces, with some reference counting difficulties. My solution was to 
handle that things in ddraw.

Could it be that d3d9 surfaces and textures are the same objects on windows? 
What happens if you QueryInterface the surface for the texture GUID?

> Obviously doing all that would be quite a change in the way d3d is
> setup in wine, and would also have some implications for the d3d7 and
> d3d8 rewrites. I'm wondering if this solution would be acceptable, and
> whether perhaps there are other, better solutions. Anyone care to
> comment?
It might be interesting if there are more such refcount connections. For 
textures, my parent/child connections are:

DDraw surface 1 -> WineD3DTexture
IParent         -> WineD3DSurface 1
DDraw surface 2 -> WineD3DSurface 2

Directdraw textures are the same objects as directdraw surfaces, so they share 
the refcount.

First, I create a ddraw surface, and create a WineD3DTexture for it. The 
surface is the child for texture. WineD3D calls my surface creation callback, 
which creates a WineD3DSurface for the ddraw surface on the first call, and a 
Parent object for the WineD3Dsurface. The IParent objects only purpose is to 
release it's child when it's destroyed. For other levels, I create a new 
ddraw surface, which is the parent of the new WineD3D surface, and attach it 
to the first ddraw surface. The attachment list is managed in ddraw.

When the app releases the compound, it (hopefully) calls the release method of 
the first surface. This releases the WineD3D texture, which causes a release 
to the IParent object and the further ddraw surfaces. The parent and the 
ddraw surfaces release the Wined3d surfaces.
(That code works for 1 level textures, I haven't yet tried an app which uses 
multiple levels, or I silently broke that functionality)

My suggestion is to keep d3dX specific refcounting in ddraw / d3d8 / d3d9, and 
use the WineD3D refcounts for wined3d internal things.  A quick guessis to 
seperate the D3D9 release code from the cleanup code, instead of doing this 
in WineD3D.

What happens if a texture has 2 surface levels? A GetSurfaceLevel for the 
first level AddRefs both the texture and the surface. A GetSurfaceLevel for 
the secound addrefs the texture and the 2nd surface, but what happens to the 
first one? A Release() of the first surface Releases() the texture, what 
happens to the secound surface?


More information about the wine-devel mailing list