diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c index 8ec237e1d68..31cff063cf3 100644 --- a/dlls/d3d8/tests/device.c +++ b/dlls/d3d8/tests/device.c @@ -759,6 +759,69 @@ static void test_display_modes(void) IDirect3D8_Release(pD3d); } +static void test_scene(void) +{ + HRESULT hr; + HWND hwnd = NULL; + IDirect3D8 *pD3d = NULL; + IDirect3DDevice8 *pDevice = NULL; + D3DPRESENT_PARAMETERS d3dpp; + D3DDISPLAYMODE d3ddm; + + pD3d = pDirect3DCreate8( D3D_SDK_VERSION ); + ok(pD3d != NULL, "Failed to create IDirect3D8 object\n"); + hwnd = CreateWindow( "static", "d3d8_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL ); + ok(hwnd != NULL, "Failed to create window\n"); + if (!pD3d || !hwnd) goto cleanup; + + IDirect3D8_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm ); + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferWidth = 800; + d3dpp.BackBufferHeight = 600; + d3dpp.BackBufferFormat = d3ddm.Format; + + + hr = IDirect3D8_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice ); + ok(hr == D3D_OK, "IDirect3D8_CreateDevice failed with %s\n", DXGetErrorString8(hr)); + if(!pDevice) goto cleanup; + + /* Test an EndScene without beginscene. Should return an error */ + hr = IDirect3DDevice8_EndScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice8_EndScene returned %s\n", DXGetErrorString8(hr)); + + /* Test a normal BeginScene / EndScene pair, this should work */ + hr = IDirect3DDevice8_BeginScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice8_BeginScene failed with %s\n", DXGetErrorString8(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice8_EndScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice8_EndScene failed with %s\n", DXGetErrorString8(hr)); + } + + /* Test another EndScene without having begun a new scene. Should return an error */ + hr = IDirect3DDevice8_EndScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice8_EndScene returned %s\n", DXGetErrorString8(hr)); + + /* Two nested BeginScene and EndScene calls */ + hr = IDirect3DDevice8_BeginScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice8_BeginScene failed with %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_BeginScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice8_BeginScene returned %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_EndScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice8_EndScene failed with %s\n", DXGetErrorString8(hr)); + hr = IDirect3DDevice8_EndScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice8_EndScene returned %s\n", DXGetErrorString8(hr)); + + /* StretchRect does not exit in Direct3D8, so no equivalent to the d3d9 stretchrect tests */ + +cleanup: + if(pD3d) IDirect3D8_Release(pD3d); + if(pDevice) IDirect3D8_Release(pDevice); + if(hwnd) DestroyWindow(hwnd); +} START_TEST(device) { @@ -780,5 +843,6 @@ START_TEST(device) test_mipmap_levels(); test_cursor(); test_states(); + test_scene(); } } diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index 34108d52b9f..2e923b8b447 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2006 Vitaliy Margolen - * Copyright (C) 2006 Stefan Dösinger(For CodeWeavers) * Copyright (C) 2006 Chris Robinson + * Copyright (C) 2006-2007 Stefan Dösinger(For CodeWeavers) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -943,6 +943,156 @@ static void test_display_modes(void) IDirect3D9_Release(pD3d); } +static void test_scene(void) +{ + HRESULT hr; + HWND hwnd = NULL; + IDirect3D9 *pD3d = NULL; + IDirect3DDevice9 *pDevice = NULL; + D3DPRESENT_PARAMETERS d3dpp; + D3DDISPLAYMODE d3ddm; + IDirect3DSurface9 *pSurface1 = NULL, *pSurface2 = NULL, *pSurface3 = NULL, *pRenderTarget = NULL; + IDirect3DSurface9 *pBackBuffer = NULL, *pDepthStencil = NULL; + RECT rect = {0, 0, 128, 128}; + D3DCAPS9 caps; + + pD3d = pDirect3DCreate9( D3D_SDK_VERSION ); + ok(pD3d != NULL, "Failed to create IDirect3D9 object\n"); + hwnd = CreateWindow( "static", "d3d9_test", WS_OVERLAPPEDWINDOW, 100, 100, 160, 160, NULL, NULL, NULL, NULL ); + ok(hwnd != NULL, "Failed to create window\n"); + if (!pD3d || !hwnd) goto cleanup; + + IDirect3D9_GetAdapterDisplayMode( pD3d, D3DADAPTER_DEFAULT, &d3ddm ); + ZeroMemory( &d3dpp, sizeof(d3dpp) ); + d3dpp.Windowed = TRUE; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.BackBufferWidth = 800; + d3dpp.BackBufferHeight = 600; + d3dpp.BackBufferFormat = d3ddm.Format; + d3dpp.EnableAutoDepthStencil = TRUE; + d3dpp.AutoDepthStencilFormat = D3DFMT_D16; + + hr = IDirect3D9_CreateDevice( pD3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL /* no NULLREF here */, hwnd, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice ); + ok(hr == D3D_OK, "IDirect3D9_CreateDevice failed with %s\n", DXGetErrorString9(hr)); + if(!pDevice) goto cleanup; + + /* Get the caps, they will be needed to tell if an operation is supposed to be valid */ + memset(&caps, 0, sizeof(caps)); + hr = IDirect3DDevice9_GetDeviceCaps(pDevice, &caps); + ok(hr == D3D_OK, "IDirect3DDevice9_GetCaps failed with %s\n", DXGetErrorString9(hr)); + if(FAILED(hr)) goto cleanup; + + /* Test an EndScene without beginscene. Should return an error */ + hr = IDirect3DDevice9_EndScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + + /* Test a normal BeginScene / EndScene pair, this should work */ + hr = IDirect3DDevice9_BeginScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene failed with %s\n", DXGetErrorString9(hr)); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice9_EndScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene failed with %s\n", DXGetErrorString9(hr)); + } + + /* Test another EndScene without having begun a new scene. Should return an error */ + hr = IDirect3DDevice9_EndScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + + /* Two nested BeginScene and EndScene calls */ + hr = IDirect3DDevice9_BeginScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice9_BeginScene failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_BeginScene returned %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_EndScene(pDevice); + ok(hr == D3D_OK, "IDirect3DDevice9_EndScene failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_EndScene(pDevice); + ok(hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_EndScene returned %s\n", DXGetErrorString9(hr)); + + /* Create some surfaces to test stretchrect between the scenes */ + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(pDevice, 128, 128, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface1, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreateOffscreenPlainSurface(pDevice, 128, 128, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &pSurface2, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateOffscreenPlainSurface failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreateDepthStencilSurface(pDevice, 800, 600, D3DFMT_D16, D3DMULTISAMPLE_NONE, 0, FALSE, &pSurface3, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateDepthStencilSurface failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_CreateRenderTarget(pDevice, 128, 128, d3ddm.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &pRenderTarget, NULL); + ok(hr == D3D_OK, "IDirect3DDevice9_CreateRenderTarget failed with %s\n", DXGetErrorString9(hr)); + + hr = IDirect3DDevice9_GetBackBuffer(pDevice, 0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); + ok(hr == D3D_OK, "IDirect3DDevice9_GetBackBuffer failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_GetDepthStencilSurface(pDevice, &pDepthStencil); + ok(hr == D3D_OK, "IDirect3DDevice9_GetBackBuffer failed with %s\n", DXGetErrorString9(hr)); + + /* First make sure a simple StretchRect call works */ + if(pSurface1 && pSurface2) { + hr = IDirect3DDevice9_StretchRect(pDevice, pSurface1, NULL, pSurface2, NULL, 0); + ok( hr == D3D_OK, "IDirect3DDevice9_StretchRect failed with %s\n", DXGetErrorString9(hr)); + } + if(pBackBuffer && pRenderTarget) { + hr = IDirect3DDevice9_StretchRect(pDevice, pBackBuffer, &rect, pRenderTarget, NULL, 0); + ok( hr == D3D_OK, "IDirect3DDevice9_StretchRect failed with %s\n", DXGetErrorString9(hr)); + } + if(pDepthStencil && pSurface3) { + HRESULT expected; + if(0) /* Disabled for now because it crashes in wine */ { + expected = caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES ? D3D_OK : D3DERR_INVALIDCALL; + hr = IDirect3DDevice9_StretchRect(pDevice, pDepthStencil, NULL, pSurface3, NULL, 0); + ok( hr == expected, "IDirect3DDevice9_StretchRect returned %s, expected %s\n", DXGetErrorString9(hr), DXGetErrorString9(expected)); + } + } + + /* Now try it in a BeginScene - EndScene pair. Seems to be allowed in a beginScene - Endscene pair + * width normal surfaces, render targets and depth stencil surfaces. + */ + hr = IDirect3DDevice9_BeginScene(pDevice); + ok( hr == D3D_OK, "IDirect3DDevice9_BeginScene failed with %s\n", DXGetErrorString9(hr)); + + if(pSurface1 && pSurface2) + { + hr = IDirect3DDevice9_StretchRect(pDevice, pSurface1, NULL, pSurface2, NULL, 0); + ok( hr == D3D_OK, "IDirect3DDevice9_StretchRect failed with %s\n", DXGetErrorString9(hr)); + } + if(pBackBuffer && pRenderTarget) + { + hr = IDirect3DDevice9_StretchRect(pDevice, pBackBuffer, &rect, pRenderTarget, NULL, 0); + ok( hr == D3D_OK, "IDirect3DDevice9_StretchRect failed with %s\n", DXGetErrorString9(hr)); + } + if(pDepthStencil && pSurface3) + { + /* This is supposed to fail inside a BeginScene - EndScene pair. */ + hr = IDirect3DDevice9_StretchRect(pDevice, pDepthStencil, NULL, pSurface3, NULL, 0); + ok( hr == D3DERR_INVALIDCALL, "IDirect3DDevice9_StretchRect returned %s, expected D3DERR_INVALIDCALL\n", DXGetErrorString9(hr)); + } + + hr = IDirect3DDevice9_EndScene(pDevice); + ok( hr == D3D_OK, "IDirect3DDevice9_EndScene failed with %s\n", DXGetErrorString9(hr)); + + /* Does a SetRenderTarget influence BeginScene / EndScene ? + * Set a new render target, then see if it started a new scene. Flip the rt back and see if that maybe + * ended the scene. Expected result is that the scene is not affected by SetRenderTarget + */ + hr = IDirect3DDevice9_SetRenderTarget(pDevice, 0, pRenderTarget); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderTarget failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_BeginScene(pDevice); + ok( hr == D3D_OK, "IDirect3DDevice9_BeginScene failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_SetRenderTarget(pDevice, 0, pBackBuffer); + ok(hr == D3D_OK, "IDirect3DDevice9_SetRenderTarget failed with %s\n", DXGetErrorString9(hr)); + hr = IDirect3DDevice9_EndScene(pDevice); + ok( hr == D3D_OK, "IDirect3DDevice9_EndScene failed with %s\n", DXGetErrorString9(hr)); + +cleanup: + if(pRenderTarget) IDirect3DSurface9_Release(pRenderTarget); + if(pDepthStencil) IDirect3DSurface9_Release(pDepthStencil); + if(pBackBuffer) IDirect3DSurface9_Release(pBackBuffer); + if(pSurface1) IDirect3DSurface9_Release(pSurface1); + if(pSurface2) IDirect3DSurface9_Release(pSurface2); + if(pSurface3) IDirect3DSurface9_Release(pSurface3); + if(pD3d) IDirect3D9_Release(pD3d); + if(pDevice) IDirect3D9_Release(pDevice); + if(hwnd) DestroyWindow(hwnd); +} START_TEST(device) { @@ -963,5 +1113,6 @@ START_TEST(device) test_mipmap_levels(); test_cursor(); test_reset(); + test_scene(); } } diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c index d0f81f3b3e2..12455fd79c7 100644 --- a/dlls/ddraw/device.c +++ b/dlls/ddraw/device.c @@ -1428,15 +1428,20 @@ IDirect3DDeviceImpl_1_DeleteMatrix(IDirect3DDevice *iface, * * Returns: * D3D_OK on success, for details see IWineD3DDevice::BeginScene + * D3DERR_SCENE_IN_SCENE if WineD3D returns an error(Only in case of an already + * started scene). * *****************************************************************************/ static HRESULT WINAPI IDirect3DDeviceImpl_7_BeginScene(IDirect3DDevice7 *iface) { ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface); + HRESULT hr; TRACE("(%p): Relay\n", This); - return IWineD3DDevice_BeginScene(This->wineD3DDevice); + hr = IWineD3DDevice_BeginScene(This->wineD3DDevice); + if(hr == WINED3D_OK) return D3D_OK; + else return D3DERR_SCENE_IN_SCENE; /* TODO: Other possible causes of failure */ } static HRESULT WINAPI @@ -1473,16 +1478,20 @@ Thunk_IDirect3DDeviceImpl_1_BeginScene(IDirect3DDevice *iface) * * Returns: * D3D_OK on success, for details see IWineD3DDevice::EndScene + * D3DERR_SCENE_NOT_IN_SCENE is returned if WineD3D returns an error. It does + * that only if the scene was already ended. * *****************************************************************************/ static HRESULT WINAPI IDirect3DDeviceImpl_7_EndScene(IDirect3DDevice7 *iface) { ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface); + HRESULT hr; TRACE("(%p): Relay\n", This); - IWineD3DDevice_EndScene(This->wineD3DDevice); - return D3D_OK; + hr = IWineD3DDevice_EndScene(This->wineD3DDevice); + if(hr == WINED3D_OK) return D3D_OK; + else return D3DERR_SCENE_NOT_IN_SCENE; } static HRESULT WINAPI diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c index 661efb364e5..29d0b0cd555 100644 --- a/dlls/ddraw/tests/d3d.c +++ b/dlls/ddraw/tests/d3d.c @@ -486,6 +486,41 @@ static void StateTest( void ) ok(rc == D3D_OK, "IDirect3DDevice7_SetRenderState(D3DRENDERSTATE_ZVISIBLE, FALSE) returned %08x\n", rc); } + +static void SceneTest(void) +{ + HRESULT hr; + + /* Test an EndScene without beginscene. Should return an error */ + hr = IDirect3DDevice7_EndScene(lpD3DDevice); + ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr); + + /* Test a normal BeginScene / EndScene pair, this should work */ + hr = IDirect3DDevice7_BeginScene(lpD3DDevice); + ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr); + if(SUCCEEDED(hr)) + { + hr = IDirect3DDevice7_EndScene(lpD3DDevice); + ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr); + } + + /* Test another EndScene without having begun a new scene. Should return an error */ + hr = IDirect3DDevice7_EndScene(lpD3DDevice); + ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr); + + /* Two nested BeginScene and EndScene calls */ + hr = IDirect3DDevice7_BeginScene(lpD3DDevice); + ok(hr == D3D_OK, "IDirect3DDevice7_BeginScene failed with %08x\n", hr); + hr = IDirect3DDevice7_BeginScene(lpD3DDevice); + ok(hr == D3DERR_SCENE_IN_SCENE, "IDirect3DDevice7_BeginScene returned %08x\n", hr); + hr = IDirect3DDevice7_EndScene(lpD3DDevice); + ok(hr == D3D_OK, "IDirect3DDevice7_EndScene failed with %08x\n", hr); + hr = IDirect3DDevice7_EndScene(lpD3DDevice); + ok(hr == D3DERR_SCENE_NOT_IN_SCENE, "IDirect3DDevice7_EndScene returned %08x\n", hr); + + /* TODO: Verify that blitting works in the same way as in d3d9 */ +} + START_TEST(d3d) { init_function_pointers(); @@ -501,5 +536,6 @@ START_TEST(d3d) LightTest(); ProcessVerticesTest(); StateTest(); + SceneTest(); ReleaseDirect3D(); } diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 2f95fb1450f..623d52566c1 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -4547,13 +4547,25 @@ static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) { /* At the moment we have no need for any functionality at the beginning of a scene */ IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; - TRACE("(%p) : stub\n", This); + TRACE("(%p)\n", This); + + if(This->inScene) { + TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + This->inScene = TRUE; return WINED3D_OK; } static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) { IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; TRACE("(%p)\n", This); + + if(!This->inScene) { + TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + ENTER_GL(); /* We only have to do this if we need to read the, swapbuffers performs a flush for us */ glFlush(); @@ -4579,8 +4591,8 @@ static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) { IUnknown_Release(targetContainer); } } - This->sceneEnded = TRUE; LEAVE_GL(); + This->inScene = FALSE; return WINED3D_OK; } @@ -5713,8 +5725,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, } else { /* Otherwise, set the render target up */ - if (!This->sceneEnded) { + if (This->inScene) { + /* EndScene takes care for loading the pbuffer into the texture. Call EndScene and BeginScene until we have better offscreen handling */ IWineD3DDevice_EndScene(iface); + IWineD3DDevice_BeginScene(iface); } TRACE("clearing renderer\n"); /* IWineD3DDeviceImpl_CleanRender(iface); */ @@ -5752,7 +5766,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, } else { FIXME("Unknown error setting the render target\n"); } - This->sceneEnded = FALSE; return hr; } diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index ca9900a9f5c..bcb49f18ecf 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -2759,9 +2759,18 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT * static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface; IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx); TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage)); + /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */ + if(myDevice->inScene && + (iface == myDevice->stencilBufferTarget || + (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) { + TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + /* Special cases for RenderTargets */ if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) || ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) { @@ -2823,8 +2832,16 @@ HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) { HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) { IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface; IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source; + IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice; TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans); + if(myDevice->inScene && + (iface == myDevice->stencilBufferTarget || + (Source && Source == myDevice->stencilBufferTarget))) { + TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n"); + return WINED3DERR_INVALIDCALL; + } + /* Special cases for RenderTargets */ if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) || ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) { diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 5fc88715827..c1c36b033db 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -642,8 +642,8 @@ typedef struct IWineD3DDeviceImpl /* Screen buffer resources */ glContext contextCache[CONTEXT_CACHE]; - /* A flag to check if endscene has been called before changing the render tartet */ - BOOL sceneEnded; + /* A flag to check for proper BeginScene / EndScene call pairs */ + BOOL inScene; /* process vertex shaders using software or hardware */ BOOL softwareVertexProcessing;