From eab8f9c5e49199c0b82cbc91886e8660d2daf579 Mon Sep 17 00:00:00 2001
From: --global <stefan@codeweavers.com>
Date: Mon, 14 Dec 2015 23:04:08 +0000
Subject: [PATCH 8/8] d3d9/tests: Add a test for software cursors.

---
 dlls/d3d9/tests/visual.c | 137 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 137 insertions(+)

diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 120d688..79782d5 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -21449,6 +21449,142 @@ done:
     DestroyWindow(window);
 }
 
+static void fill_surface_rect(IDirect3DSurface9 *surface, DWORD color, const RECT *rect)
+{
+    D3DLOCKED_RECT lr;
+    HRESULT hr;
+    LONG x, y;
+    DWORD *mem;
+
+    hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, 0);
+    ok(hr == D3D_OK, "IDirect3DSurface9_LockRect failed, hr %#x.\n", hr);
+    if (FAILED(hr)) return;
+
+    for (y = rect->top; y < rect->bottom; ++y)
+    {
+        mem = (DWORD *)((BYTE *)lr.pBits + y * lr.Pitch);
+        for (x = rect->left; x < rect->right; ++x)
+        {
+            mem[x] = color;
+        }
+    }
+    hr = IDirect3DSurface9_UnlockRect(surface);
+    ok(hr == D3D_OK, "IDirect3DSurface9_UnlockRect failed, hr %#x\n", hr);
+}
+
+static void test_software_cursor(void)
+{
+    IDirect3DDevice9 *device;
+    IDirect3DSurface9 *surface;
+    IDirect3D9 *d3d;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+    RECT r;
+    HDC dc;
+    D3DCOLOR color;
+    BOOL getdc_ok = TRUE, get_fb_data_ok = TRUE;
+
+    window = CreateWindowA("static", "d3d9_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
+            0, 0, 640, 480, NULL, NULL, NULL, NULL);
+    d3d = Direct3DCreate9(D3D_SDK_VERSION);
+    ok(!!d3d, "Failed to create a D3D object.\n");
+
+    if (!(device = create_device(d3d, window, window, FALSE)))
+    {
+        skip("Failed to create a D3D device, skipping tests.\n");
+        IDirect3D9_Release(d3d);
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, 0x00cacaca, 0.0f, 0);
+    ok(SUCCEEDED(hr), "Clear failed, hr %#x.\n", hr);
+    hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 64, 64, D3DFMT_A8R8G8B8,
+            D3DPOOL_SCRATCH, &surface, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x\n", hr);
+
+    SetRect(&r, 0, 0, 64, 64);
+    fill_surface_rect(surface, 0xffff0000, &r);
+    SetRect(&r, 16, 16, 31, 31);
+    fill_surface_rect(surface, 0x00ff0000, &r);
+    SetRect(&r, 32, 32, 48, 48);
+    fill_surface_rect(surface, 0xff0000ff, &r);
+
+    hr = IDirect3DDevice9_SetCursorProperties(device, 0, 0, surface);
+    ok(SUCCEEDED(hr), "Failed to set cursor properties, hr %#x.\n", hr);
+    IDirect3DDevice9_SetCursorPosition(device, 100, 100, 0);
+    refcount = IDirect3DSurface9_Release(surface);
+    ok(!refcount, "Surface has %u references left.\n", refcount);
+    hr = IDirect3DDevice9_ShowCursor(device, TRUE);
+    ok(SUCCEEDED(hr), "Failed to show cursor, hr %#x.\n", hr);
+
+    hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
+    ok(hr == D3D_OK, "Present failed, hr %#x.\n", hr);
+
+    /* On Windows 7 and earlier the software cursor does not show up in GetFrontBufferData. It does
+     * show when the screen is read with GetDC though. The behavior with SetCursorPosition(IMMEDIATE)
+     * and no present calls is similar to that of a ddraw overlay.
+     *
+     * On Windows 10 GetDC doesn't work at all with fullscreen applications, it just returns data from
+     * below the fullscreen window. However, GetFrontBufferData shows the cursor.
+     *
+     * In windowed mode Windows downscale the cursor to a 32x32 hardware cursor.
+     *
+     * Question: How does this work with Win7 and Aero on? What about Win8? */
+    dc = GetDC(window);
+    color = GetPixel(dc, 99, 99);
+    if (!color_match(color, 0x00cacaca, 1))
+        getdc_ok = FALSE;
+    color = GetPixel(dc, 108, 108);
+    if (!color_match(color, 0x00ff0000, 1))
+        getdc_ok = FALSE;
+    color = GetPixel(dc, 124, 124);
+    if (!color_match(color, 0x00cacaca, 1))
+        getdc_ok = FALSE;
+    color = GetPixel(dc, 140, 140);
+    if (!color_match(color, 0x000000ff, 1))
+        getdc_ok = FALSE;
+    color = GetPixel(dc, 165, 165);
+    if (!color_match(color, 0x00cacaca, 1))
+        getdc_ok = FALSE;
+    ReleaseDC(window, dc);
+
+    if (!getdc_ok)
+    {
+        hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 640, 480, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL);
+        ok(SUCCEEDED(hr), "Failed to create surface, hr %#x\n", hr);
+        hr = IDirect3DDevice9_GetFrontBufferData(device, 0, surface);
+        ok(SUCCEEDED(hr), "Failed to get front buffer data, hr %#x\n", hr);
+
+        color = getPixelColorFromSurface(surface, 99, 99);
+        if (!color_match(color, 0x00cacaca, 1))
+            get_fb_data_ok = FALSE;
+        color = getPixelColorFromSurface(surface, 108, 108);
+        if (!color_match(color, 0x00ff0000, 1))
+            get_fb_data_ok = FALSE;
+        color = getPixelColorFromSurface(surface, 124, 124);
+        if (!color_match(color, 0x00cacaca, 1))
+            get_fb_data_ok = FALSE;
+        color = getPixelColorFromSurface(surface, 140, 140);
+        if (!color_match(color, 0x000000ff, 1))
+            get_fb_data_ok = FALSE;
+        color = getPixelColorFromSurface(surface, 165, 165);
+        if (!color_match(color, 0x00cacaca, 1))
+            get_fb_data_ok = FALSE;
+
+        IDirect3DSurface9_Release(surface);
+    }
+
+    trace("getdc %u, get_fb_data %u\n",getdc_ok, get_fb_data_ok);
+    ok(getdc_ok || get_fb_data_ok, "Software cursor is broken.\n");
+
+    refcount = IDirect3DDevice9_Release(device);
+    ok(!refcount, "Device has %u references left.\n", refcount);
+    IDirect3D9_Release(d3d);
+    DestroyWindow(window);
+}
+
 START_TEST(visual)
 {
     D3DADAPTER_IDENTIFIER9 identifier;
@@ -21571,4 +21707,5 @@ START_TEST(visual)
     test_uninitialized_varyings();
     test_multisample_init();
     test_texture_blending();
+    test_software_cursor();
 }
-- 
2.5.4 (Apple Git-61)

