I'm trying to solve bug 5872 http://bugs.winehq.org/show_bug.cgi?id=5872 BF1942 calls GetDepthStencilSurface/IUnknown_Release and checks the refcount to be 0, but wine returns 1. (test hack attached)
I have done some testing: The first call to GetDepthStencilSurface increases the refcount of the device, any subsequent call increases the refcount of the surface. On release calls the refcount of the surface gets decreased. If the refcount is 1 the release call decreases the surface refcount AND the device refcount.
The exact same behaviour shows GetRenderTarget. d3d9 does also the same.
Any ideas how we should implement this behaviour?
Markus
diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index e735502..3ad8ca0 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -20,6 +20,7 @@ #define COBJMACROS #include <d3d8.h> #include <dxerr8.h> #include "wine/test.h" +#include <stdio.h>
static IDirect3D8 *(WINAPI *pDirect3DCreate8)(UINT);
@@ -183,6 +184,8 @@ static void test_refcount(void) D3DPRESENT_PARAMETERS d3dpp; D3DDISPLAYMODE d3ddm; int refcount = 0, tmp; + IDirect3DSurface8 *pRenderTarget2 = NULL; + IDirect3DSurface8 *pStencilSurface2 = NULL;
DWORD decl[] = { @@ -217,6 +220,8 @@ static void test_refcount(void) d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice ); @@ -226,6 +231,41 @@ static void test_refcount(void) refcount = get_refcount( (IUnknown *)pDevice ); ok(refcount == 1, "Invalid device RefCount %d\n", refcount);
+ printf("hr=%x refDevice=%d\n\n", hr, refcount); + + hr = IDirect3DDevice8_GetDepthStencilSurface(pDevice, &pStencilSurface2); + printf("hr=%x refSurface=%d\n", hr, get_refcount( (IUnknown *)pStencilSurface2) ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + hr = IDirect3DDevice8_GetDepthStencilSurface(pDevice, &pStencilSurface2); + printf("hr=%x refSurface=%d\n", hr, get_refcount( (IUnknown *)pStencilSurface2) ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget2); + printf("hr=%x refTarget=%d\n", hr, get_refcount( (IUnknown *)pRenderTarget2) ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + hr = IDirect3DDevice8_GetRenderTarget(pDevice, &pRenderTarget2); + printf("hr=%x refTarget=%d\n", hr, get_refcount( (IUnknown *)pRenderTarget2) ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + refcount = IUnknown_Release(pRenderTarget2); + printf("hr=%x refTarget=%d\n", hr, refcount ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + refcount = IUnknown_Release(pRenderTarget2); + printf("hr=%x refTarget=%d\n", hr, refcount ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + refcount = IUnknown_Release(pStencilSurface2); + printf("hr=%x refSurface=%d\n", hr, refcount ); + printf("hr=%x refDevice=%d\n\n", hr, get_refcount( (IUnknown *)pDevice) ); + + refcount = IUnknown_Release(pStencilSurface2); + printf("hr=%x refSurface=%d\n", hr, refcount ); + printf("hr=%x refDevice=%d\n", hr, get_refcount( (IUnknown *)pDevice) ); + return; + /* Buffers */ hr = IDirect3DDevice8_CreateIndexBuffer( pDevice, 16, 0, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &pIndexBuffer ); CHECK_CALL( hr, "CreateIndexBuffer", pDevice, ++refcount ); @@ -316,6 +356,6 @@ START_TEST(device) if (pDirect3DCreate8) { test_refcount(); - test_swapchain(); +// test_swapchain(); } }
Am Mittwoch 18 Oktober 2006 10:18 schrieb Markus Amsler:
I'm trying to solve bug 5872 http://bugs.winehq.org/show_bug.cgi?id=5872 BF1942 calls GetDepthStencilSurface/IUnknown_Release and checks the refcount to be 0, but wine returns 1. (test hack attached)
I have done some testing: The first call to GetDepthStencilSurface increases the refcount of the device, any subsequent call increases the refcount of the surface. On release calls the refcount of the surface gets decreased. If the refcount is 1 the release call decreases the surface refcount AND the device refcount.
The exact same behaviour shows GetRenderTarget. d3d9 does also the same.
Any ideas how we should implement this behaviour?
Doh - refcounting fun :-/
We know that surfaces, textures, ..., hold a reference to the device, which is what you see with the increased device refcount. We have an IDirect3DDevice?_AddRef call in CreateSurface / CreateTexture... Native seems to have this AddRef call in IDirect3DResource_AddRef:
if(oldref == 0) IDirect3DDevice8_AddRef(This->myDevice);
I guess this is the first thing we have to change.
The next is that the auto depth stencil surface and the implicit render targets seem to be created with a reference count of 0, that is why they have a ref of 1 on the first GetRenderTarget, and why the AddRef from above increases the device refcount. And the implicit surfaces aren't destroyed until the device is destroyed. This will be fun to implement with our release code :-/
It could be that the implicit render target and auto depth stencil COM objects are not COM objects in d3d's internal management and that they are constructed in the first call to GetRenderTarget. But we won't be able to do that. Or well, we can do it in d3d8.dll and d3d9.dll, but not in wined3d.dll. But applications don't see what we are doing in wined3d anyway.
What you need for sure is a really good test case to convince AJ that all this is correct ;-)
On 18/10/06, Stefan Dösinger stefandoesinger@gmx.at wrote:
We have an IDirect3DDevice?_AddRef call in CreateSurface / CreateTexture... Native seems to have this AddRef call in IDirect3DResource_AddRef:
if(oldref == 0) IDirect3DDevice8_AddRef(This->myDevice);
I guess this is the first thing we have to change.
Not sure how you read that from the test.
The next is that the auto depth stencil surface and the implicit render targets seem to be created with a reference count of 0, that is why they have a ref of 1 on the first GetRenderTarget, and why the AddRef from above increases the device refcount.
It could just be that the surface object is only created on the first call to GetRenderTarget. Note that in this test we don't do any actual rendering, so it's not impossible that in a typical application the depth stencil would already be created the moment GetRenderTarget is called.
It could be that the implicit render target and auto depth stencil COM objects are not COM objects in d3d's internal management and that they are constructed in the first call to GetRenderTarget. But we won't be able to do that. Or well, we can do it in d3d8.dll and d3d9.dll, but not in wined3d.dll.
Sure we can. Regular surfaces are currently created with a callback to d3d8 / d3d9 as well.
I wonder what happens if you release the surface you get from GetDepthStencilTarget, and then try to do some rendering with the device.
We have an IDirect3DDevice?_AddRef call in CreateSurface / CreateTexture... Native seems to have this AddRef call in IDirect3DResource_AddRef:
if(oldref == 0) IDirect3DDevice8_AddRef(This->myDevice);
I guess this is the first thing we have to change.
Not sure how you read that from the test.
Not from this test, but I had a test which did this:
CreateVertexBuffer(&vb) // ref++ Release(vb) // ref-- AddRef(vb) // ref++
CreateVertexBuffer(&vb) //ref++ SetStreamSource(device, 0, vb); //ref unchanged Release(vb) //ref-- GetStreamSource(device, 0, &vb);//ref++
and check the device refcount after each call, with the results from above.
I didn't send the test because it did an incorrect thing(release to 0, then addref).
It could just be that the surface object is only created on the first call to GetRenderTarget. Note that in this test we don't do any actual rendering, so it's not impossible that in a typical application the depth stencil would already be created the moment GetRenderTarget is called.
Yeah, I mentioned that. But I suspect that the surface resources are created with the device, just that the COM object is constructed on the first GetRenderTarget call.
It could be that the implicit render target and auto depth stencil COM objects are not COM objects in d3d's internal management and that they are constructed in the first call to GetRenderTarget. But we won't be able to do that. Or well, we can do it in d3d8.dll and d3d9.dll, but not in wined3d.dll.
Sure we can. Regular surfaces are currently created with a callback to d3d8 / d3d9 as well.
Yes, but some methods in WineD3D need the back buffer and the front buffer implementation pointer, like Present or LockRect/UnlockRect
I wonder what happens if you release the surface you get from GetDepthStencilTarget, and then try to do some rendering with the device.
I suspect that it won't have any effect(except that the refcount falls to 0)
On 18/10/06, Stefan Dösinger stefandoesinger@gmx.at wrote:
Yes, but some methods in WineD3D need the back buffer and the front buffer implementation pointer, like Present or LockRect/UnlockRect
Well yes, but you don't know if those access the field directly or call GetRenderTarget / GetDepthStencil internally.
Btw, this construction looks very similar to what happens when you call GetVertexDeclaration after having set an FVF with SetFVF.