Commit 80953d62 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

d3d9: Reject IDirect3DDevice9::Reset with active default pool resources.

parent 8bb5d13f
......@@ -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;
......
......@@ -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);
......
......@@ -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
};
......
......@@ -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
/*****************************************************************************
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment