[2/10] WineD3D: Visual test framework

Stefan Dösinger stefan at codeweavers.com
Fri Feb 16 12:08:28 CST 2007


-------------- next part --------------
From 385d972bd1542dd8c963eb2b9fe04f1dc6d120b7 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Mon, 12 Feb 2007 16:06:23 +0100
Subject: [PATCH] WineD3D: Visual test framework

This test framework allows limited testing of how states affect the
resulting rendering. It is limited because opengl and d3d are not pixel
exact, but everything that causes visible differences in games should
not depend on pixel exactness for these tests.
---
 dlls/d3d8/tests/Makefile.in  |    1 +
 dlls/d3d8/tests/visual.c     |  175 +++++++++++++++++++++++++++++++++
 dlls/d3d9/tests/Makefile.in  |    1 +
 dlls/d3d9/tests/visual.c     |  175 +++++++++++++++++++++++++++++++++
 dlls/ddraw/tests/Makefile.in |    3 +-
 dlls/ddraw/tests/visual.c    |  219 ++++++++++++++++++++++++++++++++++++++++++
 dlls/wined3d/device.c        |    4 +
 7 files changed, 577 insertions(+), 1 deletions(-)

diff --git a/dlls/d3d8/tests/Makefile.in b/dlls/d3d8/tests/Makefile.in
index 00ac6ad..58f963c 100644
--- a/dlls/d3d8/tests/Makefile.in
+++ b/dlls/d3d8/tests/Makefile.in
@@ -11,6 +11,7 @@ CTESTS = \
 	device.c \
 	surface.c \
 	texture.c \
+	visual.c \
 	volume.c
 
 @MAKE_TEST_RULES@
diff --git a/dlls/d3d8/tests/visual.c b/dlls/d3d8/tests/visual.c
new file mode 100644
index 0000000..87d17f2
--- /dev/null
+++ b/dlls/d3d8/tests/visual.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005 Henri Verbeet
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* See comment in dlls/d3d9/tests/visual.c for general guidelines */
+
+#define COBJMACROS
+#include <d3d8.h>
+#include <dxerr8.h>
+#include "wine/test.h"
+
+static HMODULE d3d8_handle = 0;
+
+static HWND create_window(void)
+{
+    WNDCLASS wc = {0};
+    HWND ret;
+    wc.lpfnWndProc = &DefWindowProc;
+    wc.lpszClassName = "d3d8_test_wc";
+    RegisterClass(&wc);
+
+    ret = CreateWindow("d3d8_test_wc", "d3d8_test",
+                        WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
+    return ret;
+}
+
+static DWORD getPixelColor(IDirect3DDevice8 *device, UINT x, UINT y)
+{
+    DWORD ret;
+    IDirect3DSurface8 *surf;
+    IDirect3DTexture8 *tex;
+    HRESULT hr;
+    D3DLOCKED_RECT lockedRect;
+    RECT rectToLock = {x, y, x+1, y+1};
+
+    hr = IDirect3DDevice8_CreateTexture(device, 640, 480, 1 /* Levels */, 0 /* usage */, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &tex);
+    if(FAILED(hr) || !tex )  /* This is not a test */
+    {
+        trace("Can't create an offscreen plain surface to read the render target data, hr=%s\n", DXGetErrorString8(hr));
+        return 0xdeadbeef;
+    }
+    hr = IDirect3DTexture8_GetSurfaceLevel(tex, 0, &surf);
+    if(FAILED(hr) || !tex )  /* This is not a test */
+    {
+        trace("Can't get surface from texture, hr=%s\n", DXGetErrorString8(hr));
+        ret = 0xdeadbeee;
+        goto out;
+    }
+
+    hr = IDirect3DDevice8_GetFrontBuffer(device, surf);
+    if(FAILED(hr))
+    {
+        trace("Can't read the front buffer data, hr=%s\n", DXGetErrorString8(hr));
+        ret = 0xdeadbeed;
+        goto out;
+    }
+
+    hr = IDirect3DSurface8_LockRect(surf, &lockedRect, &rectToLock, D3DLOCK_READONLY);
+    if(FAILED(hr))
+    {
+        trace("Can't lock the offscreen surface, hr=%s\n", DXGetErrorString8(hr));
+        ret = 0xdeadbeec;
+        goto out;
+    }
+    /* Remove the X channel for now. DirectX and OpenGL have different ideas how to treat it apparently, and it isn't
+     * really important for these tests
+     */
+    ret = ((DWORD *) lockedRect.pBits)[0] & 0x00ffffff;
+    hr = IDirect3DSurface8_UnlockRect(surf);
+    if(FAILED(hr))
+    {
+        trace("Can't unlock the offscreen surface, hr=%s\n", DXGetErrorString8(hr));
+    }
+
+out:
+    if(surf) IDirect3DSurface8_Release(surf);
+    if(tex) IDirect3DTexture8_Release(tex);
+    return ret;
+}
+
+static IDirect3DDevice8 *init_d3d8(void)
+{
+    IDirect3D8 * (__stdcall * d3d8_create)(UINT SDKVersion) = 0;
+    IDirect3D8 *d3d8_ptr = 0;
+    IDirect3DDevice8 *device_ptr = 0;
+    D3DPRESENT_PARAMETERS present_parameters;
+    HRESULT hr;
+
+    d3d8_create = (void *)GetProcAddress(d3d8_handle, "Direct3DCreate8");
+    ok(d3d8_create != NULL, "Failed to get address of Direct3DCreate8\n");
+    if (!d3d8_create) return NULL;
+
+    d3d8_ptr = d3d8_create(D3D_SDK_VERSION);
+    ok(d3d8_ptr != NULL, "Failed to create IDirect3D8 object\n");
+    if (!d3d8_ptr) return NULL;
+
+    ZeroMemory(&present_parameters, sizeof(present_parameters));
+    present_parameters.Windowed = FALSE;
+    present_parameters.hDeviceWindow = create_window();
+    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    present_parameters.BackBufferWidth = 640;
+    present_parameters.BackBufferHeight = 480;
+    present_parameters.BackBufferFormat = D3DFMT_X8R8G8B8;
+
+    hr = IDirect3D8_CreateDevice(d3d8_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, present_parameters.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
+    ok(hr == D3D_OK, "IDirect3D_CreateDevice returned: %s\n", DXGetErrorString8(hr));
+
+    return device_ptr;
+}
+
+START_TEST(visual)
+{
+    IDirect3DDevice8 *device_ptr;
+    HRESULT hr;
+    DWORD color;
+
+    d3d8_handle = LoadLibraryA("d3d8.dll");
+    if (!d3d8_handle)
+    {
+        trace("Could not load d3d8.dll, skipping tests\n");
+        return;
+    }
+
+    device_ptr = init_d3d8();
+    if (!device_ptr) return;
+
+    /* Check for the reliability of the returned data */
+    hr = IDirect3DDevice8_Clear(device_ptr, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0);
+    if(FAILED(hr))
+    {
+        trace("Clear failed, can't assure correctness of the test results, skipping\n");
+        goto cleanup;
+    }
+    IDirect3DDevice8_Present(device_ptr, NULL, NULL, NULL, NULL);
+
+    color = getPixelColor(device_ptr, 1, 1);
+    if(color !=0x00ff0000)
+    {
+        trace("Sanity check returned an incorrect color(%08x), can't assure the correctness of the tests, skipping\n", color);
+        goto cleanup;
+    }
+
+    hr = IDirect3DDevice8_Clear(device_ptr, 0, NULL, D3DCLEAR_TARGET, 0xff00ddee, 0.0, 0);
+    if(FAILED(hr))
+    {
+        trace("Clear failed, can't assure correctness of the test results, skipping\n");
+        goto cleanup;
+    }
+    IDirect3DDevice8_Present(device_ptr, NULL, NULL, NULL, NULL);
+
+    color = getPixelColor(device_ptr, 639, 479);
+    if(color != 0x0000ddee)
+    {
+        trace("Sanity check returned an incorrect color(%08x), can't assure the correctness of the tests, skipping\n", color);
+        goto cleanup;
+    }
+
+cleanup:
+    if(device_ptr) IDirect3DDevice8_Release(device_ptr);
+}
diff --git a/dlls/d3d9/tests/Makefile.in b/dlls/d3d9/tests/Makefile.in
index 0151ee3..37befbe 100644
--- a/dlls/d3d9/tests/Makefile.in
+++ b/dlls/d3d9/tests/Makefile.in
@@ -14,6 +14,7 @@ CTESTS = \
 	surface.c \
 	texture.c \
 	vertexdeclaration.c \
+	visual.c \
 	volume.c
 
 @MAKE_TEST_RULES@
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
new file mode 100644
index 0000000..88f0927
--- /dev/null
+++ b/dlls/d3d9/tests/visual.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2005 Henri Verbeet
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* This test framework allows limited testing of rendering results. Things are rendered, shown on
+ * the framebuffer, read back from there and compared to expected colors.
+ *
+ * However, neither d3d nor opengl is guaranted to be pixel exact, and thus the capability of this test
+ * is rather limited. As a general guideline for adding tests, do not rely on corner pixels. Draw a big enought
+ * area which shows specific behavior(like a quad on the whole screen), and try to get resulting colos with
+ * all bits set or unset in all channels(like pure red, green, blue, white, black). Hopefully everything that
+ * causes visible results in games can be tested in a way that does not depend on pixel exactness
+ */
+
+#define COBJMACROS
+#include <d3d9.h>
+#include <dxerr9.h>
+#include "wine/test.h"
+
+static HMODULE d3d9_handle = 0;
+
+static HWND create_window(void)
+{
+    WNDCLASS wc = {0};
+    HWND ret;
+    wc.lpfnWndProc = &DefWindowProc;
+    wc.lpszClassName = "d3d9_test_wc";
+    RegisterClass(&wc);
+
+    ret = CreateWindow("d3d9_test_wc", "d3d9_test",
+                        WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
+    return ret;
+}
+
+static DWORD getPixelColor(IDirect3DDevice9 *device, UINT x, UINT y)
+{
+    DWORD ret;
+    IDirect3DSurface9 *surf;
+    HRESULT hr;
+    D3DLOCKED_RECT lockedRect;
+    RECT rectToLock = {x, y, x+1, y+1};
+
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 640, 480, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surf, NULL);
+    if(FAILED(hr) || !surf )  /* This is not a test */
+    {
+        trace("Can't create an offscreen plain surface to read the render target data, hr=%s\n", DXGetErrorString9(hr));
+        return 0xdeadbeef;
+    }
+
+    hr = IDirect3DDevice9_GetFrontBufferData(device, 0, surf);
+    if(FAILED(hr))
+    {
+        trace("Can't read the front buffer data, hr=%s\n", DXGetErrorString9(hr));
+        ret = 0xdeadbeed;
+        goto out;
+    }
+
+    hr = IDirect3DSurface9_LockRect(surf, &lockedRect, &rectToLock, D3DLOCK_READONLY);
+    if(FAILED(hr))
+    {
+        trace("Can't lock the offscreen surface, hr=%s\n", DXGetErrorString9(hr));
+        ret = 0xdeadbeec;
+        goto out;
+    }
+
+    /* Remove the X channel for now. DirectX and OpenGL have different ideas how to treat it apparently, and it isn't
+     * really important for these tests
+     */
+    ret = ((DWORD *) lockedRect.pBits)[0] & 0x00ffffff;
+    hr = IDirect3DSurface9_UnlockRect(surf);
+    if(FAILED(hr))
+    {
+        trace("Can't unlock the offscreen surface, hr=%s\n", DXGetErrorString9(hr));
+    }
+
+out:
+    if(surf) IDirect3DSurface9_Release(surf);
+    return ret;
+}
+
+static IDirect3DDevice9 *init_d3d9(void)
+{
+    IDirect3D9 * (__stdcall * d3d9_create)(UINT SDKVersion) = 0;
+    IDirect3D9 *d3d9_ptr = 0;
+    IDirect3DDevice9 *device_ptr = 0;
+    D3DPRESENT_PARAMETERS present_parameters;
+    HRESULT hr;
+
+    d3d9_create = (void *)GetProcAddress(d3d9_handle, "Direct3DCreate9");
+    ok(d3d9_create != NULL, "Failed to get address of Direct3DCreate9\n");
+    if (!d3d9_create) return NULL;
+
+    d3d9_ptr = d3d9_create(D3D_SDK_VERSION);
+    ok(d3d9_ptr != NULL, "Failed to create IDirect3D9 object\n");
+    if (!d3d9_ptr) return NULL;
+
+    ZeroMemory(&present_parameters, sizeof(present_parameters));
+    present_parameters.Windowed = FALSE;
+    present_parameters.hDeviceWindow = create_window();
+    present_parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
+    present_parameters.BackBufferWidth = 640;
+    present_parameters.BackBufferHeight = 480;
+    present_parameters.BackBufferFormat = D3DFMT_X8R8G8B8;
+
+    hr = IDirect3D9_CreateDevice(d3d9_ptr, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, present_parameters.hDeviceWindow, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &present_parameters, &device_ptr);
+    ok(hr == D3D_OK, "IDirect3D_CreateDevice returned: %s\n", DXGetErrorString9(hr));
+
+    return device_ptr;
+}
+
+START_TEST(visual)
+{
+    IDirect3DDevice9 *device_ptr;
+    HRESULT hr;
+    DWORD color;
+
+    d3d9_handle = LoadLibraryA("d3d9.dll");
+    if (!d3d9_handle)
+    {
+        trace("Could not load d3d9.dll, skipping tests\n");
+        return;
+    }
+
+    device_ptr = init_d3d9();
+    if (!device_ptr) return;
+
+    /* Check for the reliability of the returned data */
+    hr = IDirect3DDevice9_Clear(device_ptr, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0);
+    if(FAILED(hr))
+    {
+        trace("Clear failed, can't assure correctness of the test results, skipping\n");
+        goto cleanup;
+    }
+    IDirect3DDevice9_Present(device_ptr, NULL, NULL, NULL, NULL);
+
+    color = getPixelColor(device_ptr, 1, 1);
+    if(color !=0x00ff0000)
+    {
+        trace("Sanity check returned an incorrect color(%08x), can't assure the correctness of the tests, skipping\n", color);
+        goto cleanup;
+    }
+
+    hr = IDirect3DDevice9_Clear(device_ptr, 0, NULL, D3DCLEAR_TARGET, 0xff00ddee, 0.0, 0);
+    if(FAILED(hr))
+    {
+        trace("Clear failed, can't assure correctness of the test results, skipping\n");
+        goto cleanup;
+    }
+    IDirect3DDevice9_Present(device_ptr, NULL, NULL, NULL, NULL);
+
+    color = getPixelColor(device_ptr, 639, 479);
+    if(color != 0x0000ddee)
+    {
+        trace("Sanity check returned an incorrect color(%08x), can't assure the correctness of the tests, skipping\n", color);
+        goto cleanup;
+    }
+
+cleanup:
+    if(device_ptr) IDirect3DDevice9_Release(device_ptr);
+}
diff --git a/dlls/ddraw/tests/Makefile.in b/dlls/ddraw/tests/Makefile.in
index 80e1f3b..d41f695 100644
--- a/dlls/ddraw/tests/Makefile.in
+++ b/dlls/ddraw/tests/Makefile.in
@@ -10,7 +10,8 @@ CTESTS = \
 	d3d.c \
 	ddrawmodes.c \
 	dsurface.c \
-	refcount.c
+	refcount.c \
+	visual.c
 
 @MAKE_TEST_RULES@
 
diff --git a/dlls/ddraw/tests/visual.c b/dlls/ddraw/tests/visual.c
new file mode 100644
index 0000000..8ca793f
--- /dev/null
+++ b/dlls/ddraw/tests/visual.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 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
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/* See comment in dlls/d3d9/tests/visual.c for general guidelines */
+
+#include <assert.h>
+#include "wine/test.h"
+#include "ddraw.h"
+#include "d3d.h"
+
+HWND window;
+IDirectDraw7        *DirectDraw = NULL;
+IDirectDrawSurface7 *Surface;
+IDirect3D7          *Direct3D = NULL;
+IDirect3DDevice7    *Direct3DDevice = NULL;
+
+static HRESULT (WINAPI *pDirectDrawCreateEx)(LPGUID,LPVOID*,REFIID,LPUNKNOWN);
+
+static BOOL createObjects()
+{
+    HRESULT hr;
+    HMODULE hmod = GetModuleHandleA("ddraw.dll");
+    WNDCLASS wc = {0};
+    DDSURFACEDESC2 ddsd;
+
+
+    if(!hmod) return FALSE;
+    pDirectDrawCreateEx = (void*)GetProcAddress(hmod, "DirectDrawCreateEx");
+    if(!pDirectDrawCreateEx) return FALSE;
+
+    hr = pDirectDrawCreateEx(NULL, (void **) &DirectDraw, &IID_IDirectDraw7, NULL);
+    ok(hr==DD_OK || hr==DDERR_NODIRECTDRAWSUPPORT, "DirectDrawCreateEx returned: %x\n", hr);
+    if(!DirectDraw) goto err;
+
+    wc.lpfnWndProc = &DefWindowProc;
+    wc.lpszClassName = "d3d7_test_wc";
+    RegisterClass(&wc);
+    window = CreateWindow("d3d7_test_wc", "d3d7_test", WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION , 0, 0, 640, 480, 0, 0, 0, 0);
+
+    hr = IDirectDraw7_SetCooperativeLevel(DirectDraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(hr == DD_OK, "IDirectDraw7_SetCooperativeLevel failed with %08x\n", hr);
+    if(FAILED(hr)) goto err;
+    hr = IDirectDraw7_SetDisplayMode(DirectDraw, 640, 480, 32, 0, 0);
+    if(FAILED(hr)) {
+        /* 24 bit is fine too */
+        hr = IDirectDraw7_SetDisplayMode(DirectDraw, 640, 480, 24, 0, 0);
+
+    }
+    ok(hr == DD_OK, "IDirectDraw7_SetDisplayMode failed with %08x\n", hr);
+    if(FAILED(hr)) goto err;
+
+    hr = IDirectDraw7_QueryInterface(DirectDraw, &IID_IDirect3D7, (void**) &Direct3D);
+    if (hr == E_NOINTERFACE) goto err;
+    ok(hr==DD_OK, "QueryInterface returned: %08x\n", hr);
+
+    /* DirectDraw Flipping behavior doesn't seem that well-defined. The reference rasterizer behaves differently
+     * than hardware implementations. Request single buffering, that seems to work everywhere
+     */
+    memset(&ddsd, 0, sizeof(ddsd));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.dwFlags = DDSD_CAPS;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE;
+    ddsd.dwBackBufferCount = 1;
+    hr = IDirectDraw7_CreateSurface(DirectDraw, &ddsd, &Surface, NULL);
+    ok(hr==DD_OK, "CreateSurface returned: %08x\n", hr);
+    if(!Surface) goto err;
+
+    hr = IDirect3D7_CreateDevice(Direct3D, &IID_IDirect3DTnLHalDevice, Surface, &Direct3DDevice);
+    if(FAILED(hr))
+    {
+        trace("Creating a TnLHal Device failed, trying HAL\n");
+        hr = IDirect3D7_CreateDevice(Direct3D, &IID_IDirect3DHALDevice, Surface, &Direct3DDevice);
+        if(FAILED(hr))
+        {
+            trace("Creating a HAL device failed, trying Ref\n");
+            hr = IDirect3D7_CreateDevice(Direct3D, &IID_IDirect3DRefDevice, Surface, &Direct3DDevice);
+        }
+    }
+    ok(hr == D3D_OK, "IDirect3D7_CreateDevice failed with %08x\n", hr);
+    if(!Direct3DDevice) goto err;
+    return TRUE;
+
+    err:
+    if(DirectDraw) IDirectDraw7_Release(DirectDraw);
+    if(Surface) IDirectDrawSurface7_Release(Surface);
+    if(Direct3D) IDirect3D7_Release(Direct3D);
+    if(Direct3DDevice) IDirect3DDevice7_Release(Direct3DDevice);
+    if(window) DestroyWindow(window);
+    return FALSE;
+}
+
+static void releaseObjects()
+{
+    IDirect3DDevice7_Release(Direct3DDevice);
+    IDirect3D7_Release(Direct3D);
+    IDirectDrawSurface7_Release(Surface);
+    IDirectDraw7_Release(DirectDraw);
+    DestroyWindow(window);
+}
+
+static DWORD getPixelColor(IDirect3DDevice7 *device, UINT x, UINT y)
+{
+    DWORD ret;
+    HRESULT hr;
+    DDSURFACEDESC2 ddsd;
+    RECT rectToLock = {x, y, x+1, y+1};
+    IDirectDrawSurface7 *surf = NULL;
+
+    /* Some implementations seem to dislike direct locking on the front buffer. Thus copy the front buffer
+     * to an offscreen surface and lock it instead of the front buffer
+     */
+    memset(&ddsd, 0, sizeof(ddsd));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
+    ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
+    ddsd.dwWidth = 640;
+    ddsd.dwHeight = 480;
+    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
+    hr = IDirectDraw7_CreateSurface(DirectDraw, &ddsd, &surf, NULL);
+    ok(hr == DD_OK, "IDirectDraw7_CreateSurface failed with %08x\n", hr);
+    if(!surf)
+    {
+        trace("cannot create helper surface\n");
+        return 0xdeadbeef;
+    }
+
+    memset(&ddsd, 0, sizeof(ddsd));
+    ddsd.dwSize = sizeof(ddsd);
+    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
+
+    hr = IDirectDrawSurface_BltFast(surf, 0, 0, Surface, NULL, 0);
+    ok(hr == DD_OK, "IDirectDrawSurface7_BltFast returned %08x\n", hr);
+    if(FAILED(hr))
+    {
+        trace("Cannot blit\n");
+        ret = 0xdeadbee;
+        goto out;
+    }
+
+    hr = IDirectDrawSurface7_Lock(surf, &rectToLock, &ddsd, DDLOCK_READONLY | DDLOCK_WAIT, NULL);
+    if(FAILED(hr))
+    {
+        trace("Can't lock the offscreen surface, hr=%08x\n", hr);
+        ret = 0xdeadbeec;
+        goto out;
+    }
+
+    /* Remove the X channel for now. DirectX and OpenGL have different ideas how to treat it apparently, and it isn't
+     * really important for these tests
+     */
+    ret = ((DWORD *) ddsd.lpSurface)[0] & 0x00ffffff;
+    hr = IDirectDrawSurface7_Unlock(surf, &rectToLock);
+    if(FAILED(hr))
+    {
+        trace("Can't unlock the offscreen surface, hr=%08x\n", hr);
+    }
+
+out:
+    IDirectDrawSurface7_Release(surf);
+    return ret;
+}
+
+START_TEST(visual)
+{
+    HRESULT hr;
+    DWORD color;
+    if(!createObjects())
+    {
+        skip("Cannot initialize DirectDraw and Direct3D, skipping\n");
+        return;
+    }
+
+    /* Check for the reliability of the returned data */
+    hr = IDirect3DDevice7_Clear(Direct3DDevice, 0, NULL, D3DCLEAR_TARGET, 0xffff0000, 0.0, 0);
+    if(FAILED(hr))
+    {
+        trace("Clear failed, can't assure correctness of the test results, skipping\n");
+        goto cleanup;
+    }
+
+    color = getPixelColor(Direct3DDevice, 1, 1);
+    if(color !=0x00ff0000)
+    {
+        trace("Sanity check returned an incorrect color(%08x), can't assure the correctness of the tests, skipping\n", color);
+        goto cleanup;
+    }
+
+    hr = IDirect3DDevice7_Clear(Direct3DDevice, 0, NULL, D3DCLEAR_TARGET, 0xff00ddee, 0.0, 0);
+    if(FAILED(hr))
+    {
+        trace("Clear failed, can't assure correctness of the test results, skipping\n");
+        goto cleanup;
+    }
+
+    color = getPixelColor(Direct3DDevice, 639, 479);
+    if(color != 0x0000ddee)
+    {
+        trace("Sanity check returned an incorrect color(%08x), can't assure the correctness of the tests, skipping\n", color);
+        goto cleanup;
+    }
+
+cleanup:
+    releaseObjects();
+}
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 3e37a81..3ad864e 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4258,6 +4258,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
     checkGLcall("glDisable");
     LEAVE_GL();
 
+    /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
+     * it is most likely more efficient to perform a clear on the sysmem copy too isntead of downloading it
+     */
+    ((IWineD3DSurfaceImpl *)This->render_targets[0])->Flags |= SFLAG_GLDIRTY;
     return WINED3D_OK;
 }
 
-- 
1.4.4.3



More information about the wine-patches mailing list