Refcounting fun

Stefan Dösinger stefandoesinger at
Sun Feb 12 11:59:58 CST 2006

> With the solution mentioned in my previous post, d3d7/8/9 objects
> would essentially not be real COM objects on their own, they would
> just wrap the relevant wined3d AddRef/Release functions, and not have
> refcounts of their own. Wined3d would be responsible for it's own
> refcounting, and cleaning up the d3d7/8/9 "object" as part of it's own
> cleanup. Separating the d3d9 cleanup and release code would obviously
> be part of that. Note that if we separate the cleanup and release code
> we can't just call the cleanup code from wined3d, because we don't
> know the type of the parent, all we have is an IUnknown pointer. Which
> is why we would have to pass a pointer to that function to wined3d
> during object creation.
I don't think that this will work for ddraw. The ddraw object connections are 
a little different from D3D9 / WineD3D. For example, in ddraw, the app 
creates a DirectDraw interface. This interface doesn't have any surfaces on 
it's own, the primary surfaces are created by the app. When a Direct3DDevice 
is created, the surfaces already exist. In D3D9, creating the Direct3DDevice 
automatically creates the surfaces. There's no Texture object in ddraw too. I 
don't think that a direct DDraw <-> WineD3D refcount mapping can work.

> > 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?
> The reference count appears to be shared between the texture and all
> of its surfaces. This is the output of a small test program I wrote:
> texture_refs.c:67:Calling CreateTexture
> texture_refs.c:69:texture @ 001DB220
> texture_refs.c:71:texture refs: 1
> texture_refs.c:73:Calling GetSurfaceLevel (0)
> texture_refs.c:75:surface 0 @ 001DB420
> texture_refs.c:78:texture refs: 2
> texture_refs.c:79:surface 0 refs: 2
> texture_refs.c:82:QueryInterface for surface on texture returned
> 0x80004002, ptr 00000000
> texture_refs.c:84:QueryInterface for texture on surface 0 returned
> 0x80004002, ptr 00000000
> texture_refs.c:86:Calling GetSurfaceLevel (1)
> texture_refs.c:88:surface 1 @ 001DB540
> texture_refs.c:92:texture refs: 3
> texture_refs.c:93:surface 0 refs: 3
> texture_refs.c:94:surface 1 refs: 3
> texture_refs.c:96:Calling Release on texture
> texture_refs.c:101:texture refs: 2
> texture_refs.c:102:surface 0 refs: 2
> texture_refs.c:103:surface 1 refs: 2
> texture_refs.c:105:Calling Release on surface 1
> texture_refs.c:110:texture refs: 1
> texture_refs.c:111:surface 0 refs: 1
> texture_refs.c:112:surface 1 refs: 1
> texture_refs.c:114:Calling AddRef on surface 0
> texture_refs.c:119:texture refs: 2
> texture_refs.c:120:surface 0 refs: 2
> texture_refs.c:121:surface 1 refs: 2
Seems to be really one refcount. I'd suggest to create a addref_override and 
release_ovveride member for Direct3D9 Surfaces (and Direct3D8), and set them 
when a texture is created, and unset them when the texture is destroyed and 
before the surfaces are released the last time(so destroying the surface 
works normally with IDirect3DSurface9::Release).

As a sidenote, such overrides bring some problems. The current ddraw 
implementation is full of them. The callbacks and the existance of 3 
different IDirectDraw(Main, user, hal) implementations and 5 different 
IDirectDrawSurface(Main, user, hal, dib, zbuffer) implementations made it 
quite difficult to understand the code. I don't think that I've fully 
understood it by now.

I'll have a look about the consequences of a WineD3DTexture <-> WineD3DSurface 
refcount connection for ddraw. I think it's not hard to cope with that case, 
but I can't promise right now. Can you check if there are more refcount 

I think that I should line out the changes to WineD3D I am planning: I'm going 
to add some methods, like IWineD3DSurface::Blt, 
IWineD3DSurface::BltFast, ..., this doesn't make any difference for D3D9. I 
split up the WineD3DDevice initalisation code into the CreateDevice part, 
which doesn't initialize OpenGL, and a IWineD3DDevice::Init3D to create a 
swapchain and the render targets. As a counterpart, there's a 
IWineD3DDevice::Uninit3D, which destroys the swapchain, but not the 
rendertargets, and the IWineD3DDevice::Release method, which frees the rest.
The necessary changes to D3D9 are a call to IWineD3DDevice::Init3D during 
creation, and IWineD3DDevice::Uninit3D when the d3d9 device is destroyed. The 
d3d9 device has to release it's rendertarget surfaces on it's own too.

For 2D operation without OpenGL, I've created a secound surface 
implementation, IWineX11Surface(well, bad name). It replaces a few 
methods(Blt, Lock, Unlock, Flip, ...), but uses the same management code. 
CreateSurface takes another parameter which determines the surface type. To 
avoid a too complex code, there's no way to change a X11 surface into a 3D 
surface and vice versa. If for some reason a switch is necessary, ddraw 
releases all WineD3D surfaces and re-creates them. The advantage is that if 
are 2D app is run with GL surfaces, DDraw operation is hardware accellerated. 
This can be configured by a setting in winecfg in future.

The ugly part is the screen setup. Right now, this is done in the swapchain 
code with GL, and I've made a switch in IWineD3DDevice::GetDisplayMode and 
the new IWineD3DDevice::SetDisplayMode to have a different setup code without 
a swapchain. As a dublicate of IWineD3DDevice::Present, there's a 
IWineD3DSurface::Flip method, which calls Present for GL surfaces, or handles 
a flip by it's own(X11 surfaces).

DDraw-specific management in handled in ddraw directly. This concernes complex 
surfaces(~containers in d3d9), surface attachments and the (IMO horrible) 
DDraw structures. The code in WineD3D works with WineD3D or D3D9 types(except 
of the DDBLTFX function). I hope that I can avoid including the ddraw headers 
in WineD3D. My first patches will add some WineD3D types which don't exist in 
d3d7 to avoid using D3D9 types in ddraw.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url :

More information about the wine-devel mailing list