diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index c20d98eec84..ca4200f0ef7 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -230,13 +230,110 @@ static BOOL WINAPI IDirect3DDevice9Impl_ShowCursor(LPDIRECT3DDEVICE9 iface, return ret; } +static HRESULT WINAPI reset_enum_callback(IWineD3DResource *resource, void *data) { + BOOL *resources_ok = (BOOL *) data; + WINED3DRESOURCETYPE type; + HRESULT ret = S_OK; + WINED3DSURFACE_DESC surface_desc; + WINED3DVOLUME_DESC volume_desc; + WINED3DINDEXBUFFER_DESC index_desc; + WINED3DVERTEXBUFFER_DESC vertex_desc; + WINED3DFORMAT dummy_format; + DWORD dummy_dword; + WINED3DPOOL pool = WINED3DPOOL_SCRATCH; /* a harmless pool */ + IUnknown *parent; + + type = IWineD3DResource_GetType(resource); + switch(type) { + case WINED3DRTYPE_SURFACE: + surface_desc.Format = &dummy_format; + surface_desc.Type = &type; + surface_desc.Usage = &dummy_dword; + surface_desc.Pool = &pool; + surface_desc.Size = &dummy_dword; + surface_desc.MultiSampleType = &dummy_dword; + surface_desc.MultiSampleQuality = &dummy_dword; + surface_desc.Width = &dummy_dword; + surface_desc.Height = &dummy_dword; + + IWineD3DSurface_GetDesc((IWineD3DSurface *) resource, &surface_desc); + break; + + case WINED3DRTYPE_VOLUME: + volume_desc.Format = &dummy_format; + volume_desc.Type = &type; + volume_desc.Usage = &dummy_dword; + volume_desc.Pool = &pool; + volume_desc.Size = &dummy_dword; + volume_desc.Width = &dummy_dword; + volume_desc.Height = &dummy_dword; + volume_desc.Depth = &dummy_dword; + IWineD3DVolume_GetDesc((IWineD3DVolume *) resource, &volume_desc); + break; + + case WINED3DRTYPE_INDEXBUFFER: + IWineD3DIndexBuffer_GetDesc((IWineD3DIndexBuffer *) resource, &index_desc); + pool = index_desc.Pool; + break; + + case WINED3DRTYPE_VERTEXBUFFER: + IWineD3DVertexBuffer_GetDesc((IWineD3DVertexBuffer *) resource, &vertex_desc); + pool = index_desc.Pool; + break; + + /* No need to check for textures. If there is a D3DPOOL_DEFAULT texture, there + * is a D3DPOOL_DEFAULT surface or volume as well + */ + default: + break; + } + + if(pool == WINED3DPOOL_DEFAULT) { + IWineD3DResource_GetParent(resource, &parent); + if(IUnknown_Release(parent) == 0) { + TRACE("Parent %p is an implicit resource with ref 0\n", parent); + } else { + WARN("Resource %p(wineD3D %p) with pool D3DPOOL_DEFAULT blocks the Reset call\n", parent, resource); + ret = S_FALSE; + *resources_ok = FALSE; + } + } + IWineD3DResource_Release(resource); + + return ret; +} + static HRESULT WINAPI IDirect3DDevice9Impl_Reset(LPDIRECT3DDEVICE9 iface, D3DPRESENT_PARAMETERS* pPresentationParameters) { IDirect3DDevice9Impl *This = (IDirect3DDevice9Impl *)iface; WINED3DPRESENT_PARAMETERS localParameters; HRESULT hr; + BOOL resources_ok = TRUE; + UINT i; TRACE("(%p) Relay pPresentationParameters(%p)\n", This, pPresentationParameters); + /* Reset states that hold a COM object. WineD3D holds an internal reference to set objects, because + * such objects can still be used for rendering after their external d3d9 object has been destroyed. + * These objects must not be enumerated. Unsetting them tells WineD3D that the application will not + * make use of the hidden reference and destroys the objects. + * + * Unsetting them is no problem, because the states are supposed to be reset anyway. If the validation + * below fails, the device is considered "lost", and _Reset and _Release are the only allowed calls + */ + IWineD3DDevice_SetIndices(This->WineD3DDevice, NULL); + for(i = 0; i < 16; i++) { + IWineD3DDevice_SetStreamSource(This->WineD3DDevice, i, NULL, 0, 0); + } + for(i = 0; i < 16; i++) { + IWineD3DDevice_SetTexture(This->WineD3DDevice, i, NULL); + } + + IWineD3DDevice_EnumResources(This->WineD3DDevice, reset_enum_callback, &resources_ok); + if(!resources_ok) { + WARN("The application is holding D3DPOOL_DEFAULT resources, rejecting reset\n"); + return WINED3DERR_INVALIDCALL; + } + localParameters.BackBufferWidth = pPresentationParameters->BackBufferWidth; localParameters.BackBufferHeight = pPresentationParameters->BackBufferHeight; localParameters.BackBufferFormat = pPresentationParameters->BackBufferFormat; diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index 94056736c89..ef62f83834f 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -279,6 +279,15 @@ static void test_swapchain(void) DestroyWindow( hwnd ); } +/* Shared between two functions */ +static const DWORD simple_vs[] = {0xFFFE0101, /* vs_1_1 */ + 0x0000001F, 0x80000000, 0x900F0000, /* dcl_position0 v0 */ + 0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0 */ + 0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1 */ + 0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2 */ + 0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3 */ + 0x0000FFFF}; /* END */ + static void test_refcount(void) { HRESULT hr; @@ -313,13 +322,6 @@ static void test_refcount(void) { D3DDECL_END() }; - static DWORD simple_vs[] = {0xFFFE0101, /* vs_1_1 */ - 0x0000001F, 0x80000000, 0x900F0000, /* dcl_position0 v0 */ - 0x00000009, 0xC0010000, 0x90E40000, 0xA0E40000, /* dp4 oPos.x, v0, c0 */ - 0x00000009, 0xC0020000, 0x90E40000, 0xA0E40001, /* dp4 oPos.y, v0, c1 */ - 0x00000009, 0xC0040000, 0x90E40000, 0xA0E40002, /* dp4 oPos.z, v0, c2 */ - 0x00000009, 0xC0080000, 0x90E40000, 0xA0E40003, /* dp4 oPos.w, v0, c3 */ - 0x0000FFFF}; /* END */ static DWORD simple_ps[] = {0xFFFF0101, /* ps_1_1 */ 0x00000051, 0xA00F0001, 0x3F800000, 0x00000000, 0x00000000, 0x00000000, /* def c1 = 1.0, 0.0, 0.0, 0.0 */ 0x00000042, 0xB00F0000, /* tex t0 */ @@ -719,6 +721,9 @@ static void test_reset(void) DWORD width, orig_width = GetSystemMetrics(SM_CXSCREEN); DWORD height, orig_height = GetSystemMetrics(SM_CYSCREEN); IDirect3DSwapChain9 *pSwapchain; + IDirect3DSurface9 *surface; + IDirect3DTexture9 *texture; + IDirect3DVertexShader9 *shader; pD3d = pDirect3DCreate9( D3D_SDK_VERSION ); ok(pD3d != NULL, "Failed to create IDirect3D9 object\n"); @@ -849,6 +854,55 @@ static void test_reset(void) IDirect3DSwapChain9_Release(pSwapchain); } + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.Windowed = TRUE; + d3dpp.BackBufferWidth = 400; + d3dpp.BackBufferHeight = 300; + + /* _Reset fails if there is a resource in the default pool */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(pDevice, 16, 16, D3DFMT_R5G6B5, D3DPOOL_DEFAULT, &surface, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + IDirect3DSurface9_Release(surface); + /* Reset again to get the device out of the lost state */ + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + + /* Scratch, sysmem and managed pools are fine */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(pDevice, 16, 16, D3DFMT_R5G6B5, D3DPOOL_SCRATCH, &surface, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + IDirect3DSurface9_Release(surface); + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(pDevice, 16, 16, D3DFMT_R5G6B5, D3DPOOL_SYSTEMMEM, &surface, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + IDirect3DSurface9_Release(surface); + hr = IDirect3DDevice9_CreateTexture(pDevice, 16, 16, 0, 0, D3DFMT_R5G6B5, D3DPOOL_MANAGED, &texture, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateTexture returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + IDirect3DTexture9_Release(texture); + + /* A reference held to an implicit surface causes failures as well */ + hr = IDirect3DDevice9_GetBackBuffer(pDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &surface); + ok(hr == D3D_OK, "IDirect3DDevice9_GetBackBuffer returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + IDirect3DSurface9_Release(surface); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + + /* Shaders are fine as well */ + hr = IDirect3DDevice9_CreateVertexShader(pDevice, simple_vs, &shader); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateVertexShader returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_Reset(pDevice, &d3dpp); + ok(hr == D3D_OK, "IDirect3DDevice9_Reset failed with %s\n", DXGetErrorString9(hr)); + IDirect3DVertexShader9_Release(shader); + cleanup: if(pD3d) IDirect3D9_Release(pD3d); if(pDevice) IDirect3D9_Release(pDevice); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index b30333def72..3ec2c42b847 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -6824,6 +6824,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRE if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) { ERR("What do do about a changed auto depth stencil parameter?\n"); } + TRACE("Checks done\n"); if(pPresentationParameters->Windowed) { mode.Width = swapchain->orig_width; @@ -7095,6 +7096,24 @@ static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IW } +static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) { + IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface; + IWineD3DResourceImpl *resource, *cursor; + HRESULT ret; + TRACE("(%p)->(%p,%p)\n", This, pCallback, pData); + + LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) { + TRACE("enumerating resource %p\n", resource); + IWineD3DResource_AddRef((IWineD3DResource *) resource); + ret = pCallback((IWineD3DResource *) resource, pData); + if(ret == S_FALSE) { + TRACE("Canceling enumeration\n"); + break; + } + } + return WINED3D_OK; +} + /********************************************************** * IWineD3DDevice VTbl follows **********************************************************/ @@ -7241,7 +7260,8 @@ const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl = IWineD3DDeviceImpl_UpdateSurface, IWineD3DDeviceImpl_GetFrontBufferData, /*** object tracking ***/ - IWineD3DDeviceImpl_ResourceReleased + IWineD3DDeviceImpl_ResourceReleased, + IWineD3DDeviceImpl_EnumResources }; diff --git a/include/wine/wined3d_interface.h b/include/wine/wined3d_interface.h index 3b3e68d25dc..7b00c7ae861 100644 --- a/include/wine/wined3d_interface.h +++ b/include/wine/wined3d_interface.h @@ -247,6 +247,10 @@ typedef HRESULT (WINAPI *D3DCB_CREATEADDITIONALSWAPCHAIN) (IUnknown *pDevice, struct IWineD3DSwapChain **pSwapChain ); +typedef HRESULT (WINAPI *D3DCB_ENUMRESOURCES) (struct IWineD3DResource *resource, + void *pData + ); + /***************************************************************************** * Callback functions for custom implicit object destruction. */ @@ -482,6 +486,7 @@ DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) STDMETHOD(GetFrontBufferData)(THIS_ UINT iSwapChain,struct IWineD3DSurface* pSurface) PURE; /*** object tracking ***/ STDMETHOD_(void, ResourceReleased)(THIS_ struct IWineD3DResource *resource); + STDMETHOD(EnumResources)(THIS_ D3DCB_ENUMRESOURCES pCallback, void *pData); }; #undef INTERFACE @@ -621,6 +626,7 @@ DECLARE_INTERFACE_(IWineD3DDevice,IWineD3DBase) #define IWineD3DDevice_UpdateSurface(p,a,b,c,d) (p)->lpVtbl->UpdateSurface(p,a,b,c,d) #define IWineD3DDevice_GetFrontBufferData(p,a,b) (p)->lpVtbl->GetFrontBufferData(p,a,b) #define IWineD3DDevice_ResourceReleased(p,a) (p)->lpVtbl->ResourceReleased(p,a) +#define IWineD3DDevice_EnumResources(p,a,b) (p)->lpVtbl->EnumResources(p,a,b) #endif /*****************************************************************************