d3d8: Fix implicit surface refcounting.

This commit is contained in:
Markus Amsler 2006-12-05 00:29:48 +01:00 committed by Alexandre Julliard
parent 0a3f417359
commit 4745618487
6 changed files with 69 additions and 42 deletions

View File

@ -179,6 +179,9 @@ struct IDirect3DDevice8Impl
/* FIXME: Move *baseVertexIndex somewhere sensible like wined3d */ /* FIXME: Move *baseVertexIndex somewhere sensible like wined3d */
UINT baseVertexIndex; UINT baseVertexIndex;
/* Avoids recursion with nested ReleaseRef to 0 */
BOOL inDestruction;
}; };
/* ---------------- */ /* ---------------- */
@ -252,6 +255,9 @@ struct IDirect3DSurface8Impl
/* If set forward refcounting to this object */ /* If set forward refcounting to this object */
IUnknown *forwardReference; IUnknown *forwardReference;
/* Flags an implicit surface */
BOOL isImplicit;
}; };
/* ------------------ */ /* ------------------ */
@ -599,6 +605,8 @@ extern HRESULT WINAPI D3D8CB_CreateRenderTarget(IUnknown *device, IUnknown *pSup
extern ULONG WINAPI D3D8CB_DestroyDepthStencilSurface (IWineD3DSurface *pSurface); extern ULONG WINAPI D3D8CB_DestroyDepthStencilSurface (IWineD3DSurface *pSurface);
extern ULONG WINAPI D3D8CB_DestroyRenderTarget (IWineD3DSurface *pSurface);
extern ULONG WINAPI D3D8CB_DestroySurface(IWineD3DSurface *pSurface); extern ULONG WINAPI D3D8CB_DestroySurface(IWineD3DSurface *pSurface);
extern ULONG WINAPI D3D8CB_DestroyVolume(IWineD3DVolume *pVolume); extern ULONG WINAPI D3D8CB_DestroyVolume(IWineD3DVolume *pVolume);

View File

@ -89,12 +89,16 @@ static ULONG WINAPI IDirect3DDevice8Impl_AddRef(LPDIRECT3DDEVICE8 iface) {
static ULONG WINAPI IDirect3DDevice8Impl_Release(LPDIRECT3DDEVICE8 iface) { static ULONG WINAPI IDirect3DDevice8Impl_Release(LPDIRECT3DDEVICE8 iface) {
IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface; IDirect3DDevice8Impl *This = (IDirect3DDevice8Impl *)iface;
ULONG ref = InterlockedDecrement(&This->ref); ULONG ref;
if (This->inDestruction) return 0;
ref = InterlockedDecrement(&This->ref);
TRACE("(%p) : ReleaseRef to %d\n", This, ref); TRACE("(%p) : ReleaseRef to %d\n", This, ref);
if (ref == 0) { if (ref == 0) {
TRACE("Releasing wined3d device %p\n", This->WineD3DDevice); TRACE("Releasing wined3d device %p\n", This->WineD3DDevice);
This->inDestruction = TRUE;
IWineD3DDevice_Uninit3D(This->WineD3DDevice, D3D8CB_DestroyDepthStencilSurface); IWineD3DDevice_Uninit3D(This->WineD3DDevice, D3D8CB_DestroyDepthStencilSurface);
IWineD3DDevice_Release(This->WineD3DDevice); IWineD3DDevice_Release(This->WineD3DDevice);
HeapFree(GetProcessHeap(), 0, This->shader_handles); HeapFree(GetProcessHeap(), 0, This->shader_handles);

View File

@ -200,14 +200,25 @@ HRESULT WINAPI D3D8CB_CreateRenderTarget(IUnknown *device, IUnknown *pSuperior,
if (SUCCEEDED(res)) { if (SUCCEEDED(res)) {
*ppSurface = d3dSurface->wineD3DSurface; *ppSurface = d3dSurface->wineD3DSurface;
IUnknown_Release(d3dSurface->parentDevice); d3dSurface->isImplicit = TRUE;
d3dSurface->parentDevice = NULL; /* Implicit surfaces are created with an refcount of 0 */
IUnknown_Release((IUnknown *)d3dSurface);
} else { } else {
*ppSurface = NULL; *ppSurface = NULL;
} }
return res; return res;
} }
ULONG WINAPI D3D8CB_DestroyRenderTarget(IWineD3DSurface *pSurface) {
IDirect3DSurface8Impl* surfaceParent;
TRACE("(%p) call back\n", pSurface);
IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent);
surfaceParent->isImplicit = FALSE;
/* Surface had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */
return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent);
}
/* Callback for creating the inplicite swapchain when the device is created */ /* Callback for creating the inplicite swapchain when the device is created */
static HRESULT WINAPI D3D8CB_CreateAdditionalSwapChain(IUnknown *device, static HRESULT WINAPI D3D8CB_CreateAdditionalSwapChain(IUnknown *device,
WINED3DPRESENT_PARAMETERS* pPresentationParameters, WINED3DPRESENT_PARAMETERS* pPresentationParameters,
@ -279,8 +290,9 @@ HRESULT WINAPI D3D8CB_CreateDepthStencilSurface(IUnknown *device, IUnknown *pSup
(D3DFORMAT)Format, MultiSample, (IDirect3DSurface8 **)&d3dSurface); (D3DFORMAT)Format, MultiSample, (IDirect3DSurface8 **)&d3dSurface);
if (SUCCEEDED(res)) { if (SUCCEEDED(res)) {
*ppSurface = d3dSurface->wineD3DSurface; *ppSurface = d3dSurface->wineD3DSurface;
IUnknown_Release(d3dSurface->parentDevice); d3dSurface->isImplicit = TRUE;
d3dSurface->parentDevice = NULL; /* Implicit surfaces are created with an refcount of 0 */
IUnknown_Release((IUnknown *)d3dSurface);
} }
return res; return res;
} }
@ -290,7 +302,8 @@ ULONG WINAPI D3D8CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) {
TRACE("(%p) call back\n", pSurface); TRACE("(%p) call back\n", pSurface);
IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent); IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent);
IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent); surfaceParent->isImplicit = FALSE;
/* Surface had refcount of 0 GetParent addrefed to 1, so 1 Release is enough */
return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent); return IDirect3DSurface8_Release((IDirect3DSurface8*) surfaceParent);
} }

View File

@ -52,6 +52,7 @@ static ULONG WINAPI IDirect3DSurface8Impl_AddRef(LPDIRECT3DSURFACE8 iface) {
} else { } else {
/* No container, handle our own refcounting */ /* No container, handle our own refcounting */
ULONG ref = InterlockedIncrement(&This->ref); ULONG ref = InterlockedIncrement(&This->ref);
if(ref == 1 && This->parentDevice) IUnknown_AddRef(This->parentDevice);
TRACE("(%p) : AddRef from %d\n", This, ref - 1); TRACE("(%p) : AddRef from %d\n", This, ref - 1);
return ref; return ref;
} }
@ -71,9 +72,10 @@ static ULONG WINAPI IDirect3DSurface8Impl_Release(LPDIRECT3DSURFACE8 iface) {
ULONG ref = InterlockedDecrement(&This->ref); ULONG ref = InterlockedDecrement(&This->ref);
TRACE("(%p) : ReleaseRef to %d\n", This, ref); TRACE("(%p) : ReleaseRef to %d\n", This, ref);
if (ref == 0) { if (ref == 0 && This->parentDevice) IUnknown_Release(This->parentDevice);
/* Implicit surfaces are destroyed with the device, not if refcount reaches 0. */
if (ref >= 0 && !This->isImplicit) {
IWineD3DSurface_Release(This->wineD3DSurface); IWineD3DSurface_Release(This->wineD3DSurface);
if (This->parentDevice) IUnknown_Release(This->parentDevice);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }

View File

@ -56,7 +56,7 @@ static ULONG WINAPI IDirect3DSwapChain8Impl_Release(LPDIRECT3DSWAPCHAIN8 iface)
TRACE("(%p) : ReleaseRef to %d\n", This, ref); TRACE("(%p) : ReleaseRef to %d\n", This, ref);
if (ref == 0) { if (ref == 0) {
IWineD3DSwapChain_Release(This->wineD3DSwapChain); IWineD3DSwapChain_Destroy(This->wineD3DSwapChain, D3D8CB_DestroyRenderTarget);
if (This->parentDevice) IUnknown_Release(This->parentDevice); if (This->parentDevice) IUnknown_Release(This->parentDevice);
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
} }

View File

@ -329,37 +329,37 @@ static void test_refcount(void)
* - the refcount is not forwarded to the container. * - the refcount is not forwarded to the container.
*/ */
hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget); hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget);
todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount); CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount);
if(pRenderTarget) if(pRenderTarget)
{ {
todo_wine CHECK_SURFACE_CONTAINER( pRenderTarget, IID_IDirect3DDevice8, pDevice); todo_wine CHECK_SURFACE_CONTAINER( pRenderTarget, IID_IDirect3DDevice8, pDevice);
todo_wine CHECK_REFCOUNT( pRenderTarget, 1); CHECK_REFCOUNT( pRenderTarget, 1);
todo_wine CHECK_ADDREF_REFCOUNT(pRenderTarget, 2); CHECK_ADDREF_REFCOUNT(pRenderTarget, 2);
todo_wine CHECK_REFCOUNT(pDevice, refcount); CHECK_REFCOUNT(pDevice, refcount);
todo_wine CHECK_RELEASE_REFCOUNT(pRenderTarget, 1); CHECK_RELEASE_REFCOUNT(pRenderTarget, 1);
todo_wine CHECK_REFCOUNT(pDevice, refcount); CHECK_REFCOUNT(pDevice, refcount);
hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget); hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget);
todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, refcount); CHECK_CALL( hr, "GetRenderTarget", pDevice, refcount);
todo_wine CHECK_REFCOUNT( pRenderTarget, 2); CHECK_REFCOUNT( pRenderTarget, 2);
todo_wine CHECK_RELEASE_REFCOUNT( pRenderTarget, 1); CHECK_RELEASE_REFCOUNT( pRenderTarget, 1);
todo_wine CHECK_RELEASE_REFCOUNT( pRenderTarget, 0); CHECK_RELEASE_REFCOUNT( pRenderTarget, 0);
CHECK_REFCOUNT( pDevice, --refcount); CHECK_REFCOUNT( pDevice, --refcount);
/* The render target is released with the device, so AddRef with refcount=0 is fine here. */ /* The render target is released with the device, so AddRef with refcount=0 is fine here. */
todo_wine CHECK_ADDREF_REFCOUNT(pRenderTarget, 1); CHECK_ADDREF_REFCOUNT(pRenderTarget, 1);
todo_wine CHECK_REFCOUNT(pDevice, ++refcount); CHECK_REFCOUNT(pDevice, ++refcount);
todo_wine CHECK_RELEASE_REFCOUNT(pRenderTarget, 0); CHECK_RELEASE_REFCOUNT(pRenderTarget, 0);
CHECK_REFCOUNT(pDevice, --refcount); CHECK_REFCOUNT(pDevice, --refcount);
} }
/* Render target and back buffer are identical. */ /* Render target and back buffer are identical. */
hr = IDirect3DDevice8_GetBackBuffer(pDevice, 0, 0, &pBackBuffer); hr = IDirect3DDevice8_GetBackBuffer(pDevice, 0, 0, &pBackBuffer);
todo_wine CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount); CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount);
if(pBackBuffer) if(pBackBuffer)
{ {
todo_wine CHECK_RELEASE_REFCOUNT(pBackBuffer, 0); CHECK_RELEASE_REFCOUNT(pBackBuffer, 0);
ok(pRenderTarget == pBackBuffer, "RenderTarget=%p and BackBuffer=%p should be the same.\n", ok(pRenderTarget == pBackBuffer, "RenderTarget=%p and BackBuffer=%p should be the same.\n",
pRenderTarget, pBackBuffer); pRenderTarget, pBackBuffer);
pBackBuffer = NULL; pBackBuffer = NULL;
@ -367,24 +367,24 @@ static void test_refcount(void)
CHECK_REFCOUNT( pDevice, --refcount); CHECK_REFCOUNT( pDevice, --refcount);
hr = IDirect3DDevice8_GetDepthStencilSurface(pDevice, &pStencilSurface); hr = IDirect3DDevice8_GetDepthStencilSurface(pDevice, &pStencilSurface);
todo_wine CHECK_CALL( hr, "GetDepthStencilSurface", pDevice, ++refcount); CHECK_CALL( hr, "GetDepthStencilSurface", pDevice, ++refcount);
if(pStencilSurface) if(pStencilSurface)
{ {
CHECK_SURFACE_CONTAINER( pStencilSurface, IID_IDirect3DDevice8, pDevice); CHECK_SURFACE_CONTAINER( pStencilSurface, IID_IDirect3DDevice8, pDevice);
todo_wine CHECK_REFCOUNT( pStencilSurface, 1); CHECK_REFCOUNT( pStencilSurface, 1);
todo_wine CHECK_ADDREF_REFCOUNT(pStencilSurface, 2); CHECK_ADDREF_REFCOUNT(pStencilSurface, 2);
todo_wine CHECK_REFCOUNT(pDevice, refcount); CHECK_REFCOUNT(pDevice, refcount);
todo_wine CHECK_RELEASE_REFCOUNT(pStencilSurface, 1); CHECK_RELEASE_REFCOUNT(pStencilSurface, 1);
todo_wine CHECK_REFCOUNT(pDevice, refcount); CHECK_REFCOUNT(pDevice, refcount);
todo_wine CHECK_RELEASE_REFCOUNT( pStencilSurface, 0); CHECK_RELEASE_REFCOUNT( pStencilSurface, 0);
CHECK_REFCOUNT( pDevice, --refcount); CHECK_REFCOUNT( pDevice, --refcount);
/* The stencil surface is released with the device, so AddRef with refcount=0 is fine here. */ /* The stencil surface is released with the device, so AddRef with refcount=0 is fine here. */
todo_wine CHECK_ADDREF_REFCOUNT(pStencilSurface, 1); CHECK_ADDREF_REFCOUNT(pStencilSurface, 1);
todo_wine CHECK_REFCOUNT(pDevice, ++refcount); CHECK_REFCOUNT(pDevice, ++refcount);
todo_wine CHECK_RELEASE_REFCOUNT(pStencilSurface, 0); CHECK_RELEASE_REFCOUNT(pStencilSurface, 0);
CHECK_REFCOUNT(pDevice, --refcount); CHECK_REFCOUNT(pDevice, --refcount);
pStencilSurface = NULL; pStencilSurface = NULL;
} }
@ -489,19 +489,19 @@ static void test_refcount(void)
{ {
/* check implicit back buffer */ /* check implicit back buffer */
hr = IDirect3DSwapChain8_GetBackBuffer(pSwapChain, 0, 0, &pBackBuffer); hr = IDirect3DSwapChain8_GetBackBuffer(pSwapChain, 0, 0, &pBackBuffer);
todo_wine CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount); CHECK_CALL( hr, "GetBackBuffer", pDevice, ++refcount);
CHECK_REFCOUNT( pSwapChain, 1); CHECK_REFCOUNT( pSwapChain, 1);
if(pBackBuffer) if(pBackBuffer)
{ {
todo_wine CHECK_SURFACE_CONTAINER( pBackBuffer, IID_IDirect3DDevice8, pDevice); todo_wine CHECK_SURFACE_CONTAINER( pBackBuffer, IID_IDirect3DDevice8, pDevice);
todo_wine CHECK_REFCOUNT( pBackBuffer, 1); CHECK_REFCOUNT( pBackBuffer, 1);
todo_wine CHECK_RELEASE_REFCOUNT( pBackBuffer, 0); CHECK_RELEASE_REFCOUNT( pBackBuffer, 0);
CHECK_REFCOUNT( pDevice, --refcount); CHECK_REFCOUNT( pDevice, --refcount);
/* The back buffer is released with the swapchain, so AddRef with refcount=0 is fine here. */ /* The back buffer is released with the swapchain, so AddRef with refcount=0 is fine here. */
todo_wine CHECK_ADDREF_REFCOUNT(pBackBuffer, 1); CHECK_ADDREF_REFCOUNT(pBackBuffer, 1);
todo_wine CHECK_REFCOUNT(pDevice, ++refcount); CHECK_REFCOUNT(pDevice, ++refcount);
todo_wine CHECK_RELEASE_REFCOUNT(pBackBuffer, 0); CHECK_RELEASE_REFCOUNT(pBackBuffer, 0);
CHECK_REFCOUNT(pDevice, --refcount); CHECK_REFCOUNT(pDevice, --refcount);
pBackBuffer = NULL; pBackBuffer = NULL;
} }
@ -525,10 +525,10 @@ static void test_refcount(void)
/* The implicit render target is not freed if refcount reaches 0. /* The implicit render target is not freed if refcount reaches 0.
* Otherwise GetRenderTarget would re-allocate it and the pointer would change.*/ * Otherwise GetRenderTarget would re-allocate it and the pointer would change.*/
hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget2); hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget2);
todo_wine CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount); CHECK_CALL( hr, "GetRenderTarget", pDevice, ++refcount);
if(pRenderTarget2) if(pRenderTarget2)
{ {
todo_wine CHECK_RELEASE_REFCOUNT(pRenderTarget2, 0); CHECK_RELEASE_REFCOUNT(pRenderTarget2, 0);
ok(pRenderTarget == pRenderTarget2, "RenderTarget=%p and RenderTarget2=%p should be the same.\n", ok(pRenderTarget == pRenderTarget2, "RenderTarget=%p and RenderTarget2=%p should be the same.\n",
pRenderTarget, pRenderTarget2); pRenderTarget, pRenderTarget2);
CHECK_REFCOUNT( pDevice, --refcount); CHECK_REFCOUNT( pDevice, --refcount);