When IWineD3DDevice_GetDepthStencilSurface returns WINED3DERR_NOTFOUND it was setting ppZStencilSurface to null. This was the cause of rendering issues with the 3d models in spore.
Can you write a test for this? I think we have some depth stencil tests in dlls/d3d9/tests/device.c which you could use to test this.
I think you are right with this patch - I vaguely remember writing a test for a different getter function, but it is better to be sure
I'm really stumped on why this even works because after writing a test (attached) and running on windows it shows that ppZStencilSurface IS getting set to null when D3DERR_NOTFOUND is returned.
Could it be that there is something else behind this problem which is unrelated to what I have been looking at?
Regards, Andrew
On Sat, Aug 30, 2008 at 1:05 AM, Stefan Dösinger stefan@codeweavers.com wrote:
When IWineD3DDevice_GetDepthStencilSurface returns WINED3DERR_NOTFOUND it was setting ppZStencilSurface to null. This was the cause of rendering issues with the 3d models in spore.
Can you write a test for this? I think we have some depth stencil tests in dlls/d3d9/tests/device.c which you could use to test this.
I think you are right with this patch - I vaguely remember writing a test for a different getter function, but it is better to be sure
Andrew Fenn schrieb:
I'm really stumped on why this even works because after writing a test (attached) and running on windows it shows that ppZStencilSurface IS getting set to null when D3DERR_NOTFOUND is returned.
Could it be that there is something else behind this problem which is unrelated to what I have been looking at?
Regards, Andrew
On Sat, Aug 30, 2008 at 1:05 AM, Stefan Dösinger stefan@codeweavers.com wrote:
When IWineD3DDevice_GetDepthStencilSurface returns WINED3DERR_NOTFOUND it was setting ppZStencilSurface to null. This was the cause of rendering issues with the 3d models in spore.
Can you write a test for this? I think we have some depth stencil tests in dlls/d3d9/tests/device.c which you could use to test this.
I think you are right with this patch - I vaguely remember writing a test for a different getter function, but it is better to be sure
I've tried some ugly things and found a way to produce this in a test. The test works on windows but not on wine. Removing the *ppZStencilSurface = NULL; works for a part of the test. But the return value is different.
Cheers Rico
diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index 41dcafb..6ead34d 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -1365,6 +1365,18 @@ static void test_depthstenciltest(void) ok(hr == D3DERR_NOTFOUND && pDepthStencil2 == NULL, "IDirect3DDevice9_GetDepthStencilSurface failed with %08x\n", hr); if(pDepthStencil2) IDirect3DSurface9_Release(pDepthStencil2);
+ /* the DepthStencilSurface is NULL and Reset should add a new one ?? + * At least this provocates a INVALIDCALL in GetDepthStencil afterwards */ +#define testnumber 10 + pDepthStencil2 = testnumber; /* set a value so that we could check if it is changed after an invalid call */ + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_Reset failed with %08x\n", hr); + hr = IDirect3DDevice9_GetDepthStencilSurface(pDevice, &pDepthStencil2); + ok(hr == D3DERR_INVALIDCALL && pDepthStencil2 == testnumber, "IDirect3DDevice9_GetDepthStencilSurface failed %08x (%08x) pDepthStencil %08x (%08x)\n", hr, D3DERR_INVALIDCALL, pDepthStencil2, testnumber); + if(pDepthStencil2 != testnumber && pDepthStencil2 != 0) IDirect3DSurface9_Release(pDepthStencil2); + pDepthStencil2 = 0; +exit(0); + /* This left the render states untouched! */ hr = IDirect3DDevice9_GetRenderState(pDevice, D3DRS_ZENABLE, &state); ok(hr == D3D_OK, "IDirect3DDevice9_GetRenderState failed with %08x\n", hr);
Andrew Fenn schrieb:
I'm really stumped on why this even works because after writing a test (attached) and running on windows it shows that ppZStencilSurface IS getting set to null when D3DERR_NOTFOUND is returned.
Could it be that there is something else behind this problem which is unrelated to what I have been looking at?
Regards, Andrew
On Sat, Aug 30, 2008 at 1:05 AM, Stefan Dösinger stefan@codeweavers.com wrote:
When IWineD3DDevice_GetDepthStencilSurface returns WINED3DERR_NOTFOUND it was setting ppZStencilSurface to null. This was the cause of rendering issues with the 3d models in spore.
Can you write a test for this? I think we have some depth stencil tests in dlls/d3d9/tests/device.c which you could use to test this.
I think you are right with this patch - I vaguely remember writing a test for a different getter function, but it is better to be sure
This is a better patch which shows the source of the problem and implements the correct behaviour of GetDepthStencilSurface. But there is a problem in function IWineD3DDeviceImpl_GetDepthStencilSurface. This couldn't return the value which we need (see test cases). So anyone a suggestion?
Cheers Rico
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index ddeaca3..9a2aeb9 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -745,8 +745,14 @@ static HRESULT WINAPI IDirect3DDevice9Impl_GetDepthStencilSurface(LPDIRECT3DDE *ppZStencilSurface = NULL; } } else { - WARN("Call to IWineD3DDevice_GetDepthStencilSurface failed\n"); - *ppZStencilSurface = NULL; + WARN("Call to IWineD3DDevice_GetDepthStencilSurface failed with %i\n", hr); + if( hr == D3DERR_INVALIDCALL ) { + FIXME("D3DERR_INVALIDCALL %i\n", hr); + } + else if(hr == D3DERR_NOTFOUND) { + FIXME("D3DERR_NOTFOUND %i\n", hr); + *ppZStencilSurface = NULL; + } } LeaveCriticalSection(&d3d9_cs); return hr; diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index 41dcafb..b67ed93 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -1365,6 +1365,27 @@ static void test_depthstenciltest(void) ok(hr == D3DERR_NOTFOUND && pDepthStencil2 == NULL, "IDirect3DDevice9_GetDepthStencilSurface failed with %08x\n", hr); if(pDepthStencil2) IDirect3DSurface9_Release(pDepthStencil2);
+ /* This shows that pDepthStencil2 is set to 0 when hr == D3DERR_NOTFOUND */ +#define testnumber 10 + pDepthStencil2 = testnumber; + hr = IDirect3DDevice9_GetDepthStencilSurface(pDevice, &pDepthStencil2); + ok(hr == D3DERR_NOTFOUND && pDepthStencil2 == NULL, "IDirect3DDevice9_GetDepthStencilSurface failed %08x (%08x) pDepthStencil %08x (%08x)\n", hr, D3DERR_NOTFOUND, pDepthStencil2, 0); + if(pDepthStencil2 != testnumber && pDepthStencil2 != 0) IDirect3DSurface9_Release(pDepthStencil2); + + /* This shows that pDepthStencil2 is NOT set to 0 when hr == D3DERR_INVALIDCALL. + * Current implementation couldn't set it (see IWineD3DDeviceImpl_GetDepthStencilSurface) */ + + /* the DepthStencilSurface is NULL and Reset should add a new one ?? + * At least this provocates an INVALIDCALL in GetDepthStencil afterwards on windows, on wine (D3DERR_NOTFOUND)! */ + pDepthStencil2 = testnumber; /* set a value so that we could check if it is changed after an invalid call */ + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_Reset failed with %08x\n", hr); + hr = IDirect3DDevice9_GetDepthStencilSurface(pDevice, &pDepthStencil2); + ok(hr == D3DERR_INVALIDCALL && pDepthStencil2 == testnumber, "IDirect3DDevice9_GetDepthStencilSurface failed %08x (%08x) pDepthStencil %08x (%08x)\n", hr, D3DERR_INVALIDCALL, pDepthStencil2, testnumber); + if(pDepthStencil2 != testnumber && pDepthStencil2 != 0) IDirect3DSurface9_Release(pDepthStencil2); + pDepthStencil2 = 0; +exit(0); + /* This left the render states untouched! */ hr = IDirect3DDevice9_GetRenderState(pDevice, D3DRS_ZENABLE, &state); ok(hr == D3D_OK, "IDirect3DDevice9_GetRenderState failed with %08x\n", hr);
This is a better patch which shows the source of the problem and implements the correct behaviour of GetDepthStencilSurface. But there is a problem in function IWineD3DDeviceImpl_GetDepthStencilSurface. This couldn't return the value which we need (see test cases). So anyone a suggestion?
Reset sets a flag when it fails. In this state, the device is essentially broken, and all you can do is release objects and attempt to call reset again(or destroy the device altogether). We currently implement a few Reset failure conditions and set a flag if Reset fails. I think this is done in d3d9 only right now, but a flag could be set in wined3d too, or d3d9's GetDepthStencilSurface could check the flag and return a different error value.