[1/9] WineD3D: BeginScene and EndScene tests and fixes

Stefan Dösinger stefan at codeweavers.com
Fri Feb 9 09:35:45 CST 2007


This is an updated patch which does not use fullscreen mode in the test for no 
reason. This avoids triggering the broken resolution restoring in d3d8, which 
is a different problem that needs fixing in a different patch.

The other patches are unaffected by that change
-------------- next part --------------
From f044e0a195dbfe36e2f75f05d0f3645f74bcc74c Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Fri, 9 Feb 2007 16:09:11 +0100
Subject: [PATCH] WineD3D: BeginScene and EndScene tests

Tests the behavior of BeginScene and EndScene regarding nested beginscenes, beginscene
without endscene and vice versa. Also tests the behavior of StretchRect on depth stencil
surfaces and render targets to verfiy the correctness of the msdn info
---
 dlls/d3d8/tests/device.c       |   64 +++++++++++++++++
 dlls/d3d9/tests/device.c       |  153 +++++++++++++++++++++++++++++++++++++++-
 dlls/ddraw/device.c            |   15 +++-
 dlls/ddraw/tests/d3d.c         |   36 +++++++++
 dlls/wined3d/device.c          |   21 +++++-
 dlls/wined3d/surface.c         |   17 +++++
 dlls/wined3d/wined3d_private.h |    4 +-
 7 files changed, 300 insertions(+), 10 deletions(-)

diff --git a/dlls/d3d8/tests/device.c b/dlls/d3d8/tests/device.c
index 8ec237e..553968b 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()
+{
+    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 34108d5..d01aadc 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()
+{
+    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 d0f81f3..12455fd 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 661efb3..e0de0fb 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()
+{
+    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 2f95fb1..623d525 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 ca9900a..bcb49f1 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 5fc8871..c1c36b0 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;
-- 
1.4.4.3



More information about the wine-patches mailing list