[PATCH 1/5] ddraw/tests: Rewrite AttachmentTest() and AttachmentTest7().

Henri Verbeet hverbeet at codeweavers.com
Mon Jan 27 03:07:51 CST 2014


---
 dlls/ddraw/tests/ddraw1.c   |  247 ++++++++++++++++++
 dlls/ddraw/tests/ddraw2.c   |  247 ++++++++++++++++++
 dlls/ddraw/tests/ddraw4.c   |  273 ++++++++++++++++++++
 dlls/ddraw/tests/ddraw7.c   |  255 +++++++++++++++++++
 dlls/ddraw/tests/dsurface.c |  583 -------------------------------------------
 5 files changed, 1022 insertions(+), 583 deletions(-)

diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 7ab339f..809753c 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -4153,6 +4153,252 @@ static void test_primary_palette(void)
     DestroyWindow(window);
 }
 
+static HRESULT WINAPI surface_counter(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
+{
+    UINT *surface_count = context;
+
+    ++(*surface_count);
+    IDirectDrawSurface_Release(surface);
+
+    return DDENUMRET_OK;
+}
+
+static void test_surface_attachment(void)
+{
+    IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
+    DDSCAPS caps = {DDSCAPS_TEXTURE};
+    DDSURFACEDESC surface_desc;
+    IDirectDraw *ddraw;
+    UINT surface_count;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(ddraw = create_ddraw()))
+    {
+        skip("Failed to create a ddraw object, skipping test.\n");
+        return;
+    }
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    U2(surface_desc).dwMipMapCount = 3;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &surface2);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &surface3);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_GetAttachedSurface(surface3, &caps, &surface4);
+    ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
+
+    surface_count = 0;
+    IDirectDrawSurface_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
+    ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface_Release(surface4);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    if (SUCCEEDED(hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4)))
+    {
+        skip("Running on refrast, skipping some tests.\n");
+        hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface4);
+        ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    }
+    else
+    {
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    }
+
+    IDirectDrawSurface_Release(surface4);
+    IDirectDrawSurface_Release(surface3);
+    IDirectDrawSurface_Release(surface2);
+    IDirectDrawSurface_Release(surface1);
+
+    hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    /* Try a single primary and two offscreen plain surfaces. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    /* This one has a different size. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    /* Try the reverse without detaching first. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
+    ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    /* Try to detach reversed. */
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(hr == DDERR_CANNOTDETACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface_Release(surface4);
+    IDirectDrawSurface_Release(surface3);
+    IDirectDrawSurface_Release(surface2);
+    IDirectDrawSurface_Release(surface1);
+
+    /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 64;
+    surface_desc.dwHeight = 64;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+    surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
+    surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
+    U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
+    U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
+    U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
+    U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+    surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+    U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
+    U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
+    hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+
+    /* Attaching while already attached to other surface. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface3, 0, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    IDirectDrawSurface_Release(surface3);
+
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+
+    /* Automatic detachment on release. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface2);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDraw_Release(ddraw);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw1)
 {
     test_coop_level_create_device_window();
@@ -4185,4 +4431,5 @@ START_TEST(ddraw1)
     test_flip();
     test_sysmem_overlay();
     test_primary_palette();
+    test_surface_attachment();
 }
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index e4e8ff3..1890eeb 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -5250,6 +5250,252 @@ static void test_primary_palette(void)
     DestroyWindow(window);
 }
 
+static HRESULT WINAPI surface_counter(IDirectDrawSurface *surface, DDSURFACEDESC *desc, void *context)
+{
+    UINT *surface_count = context;
+
+    ++(*surface_count);
+    IDirectDrawSurface_Release(surface);
+
+    return DDENUMRET_OK;
+}
+
+static void test_surface_attachment(void)
+{
+    IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
+    DDSCAPS caps = {DDSCAPS_TEXTURE};
+    DDSURFACEDESC surface_desc;
+    IDirectDraw2 *ddraw;
+    UINT surface_count;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(ddraw = create_ddraw()))
+    {
+        skip("Failed to create a ddraw object, skipping test.\n");
+        return;
+    }
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    U2(surface_desc).dwMipMapCount = 3;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &surface2);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &surface3);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_GetAttachedSurface(surface3, &caps, &surface4);
+    ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
+
+    surface_count = 0;
+    IDirectDrawSurface_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
+    ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface_Release(surface4);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    if (SUCCEEDED(hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4)))
+    {
+        skip("Running on refrast, skipping some tests.\n");
+        hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface4);
+        ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    }
+    else
+    {
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface4);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface3);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface4);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface2);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    }
+
+    IDirectDrawSurface_Release(surface4);
+    IDirectDrawSurface_Release(surface3);
+    IDirectDrawSurface_Release(surface2);
+    IDirectDrawSurface_Release(surface1);
+
+    hr = IDirectDraw2_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    /* Try a single primary and two offscreen plain surfaces. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    /* This one has a different size. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    /* Try the reverse without detaching first. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
+    ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    /* Try to detach reversed. */
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(hr == DDERR_CANNOTDETACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface_Release(surface4);
+    IDirectDrawSurface_Release(surface3);
+    IDirectDrawSurface_Release(surface2);
+    IDirectDrawSurface_Release(surface1);
+
+    /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 64;
+    surface_desc.dwHeight = 64;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+    surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat);
+    surface_desc.ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
+    U1(surface_desc.ddpfPixelFormat).dwRGBBitCount = 16;
+    U2(surface_desc.ddpfPixelFormat).dwRBitMask = 0xf800;
+    U3(surface_desc.ddpfPixelFormat).dwGBitMask = 0x07e0;
+    U4(surface_desc.ddpfPixelFormat).dwBBitMask = 0x001f;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+    surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+    U1(surface_desc.ddpfPixelFormat).dwZBufferBitDepth = 16;
+    U3(surface_desc.ddpfPixelFormat).dwZBitMask = 0x0000ffff;
+    hr = IDirectDraw2_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+
+    /* Attaching while already attached to other surface. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface3, 0, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    IDirectDrawSurface_Release(surface3);
+
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+
+    /* Automatic detachment on release. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface2);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDraw2_Release(ddraw);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw2)
 {
     test_coop_level_create_device_window();
@@ -5288,4 +5534,5 @@ START_TEST(ddraw2)
     test_user_memory_getdc();
     test_sysmem_overlay();
     test_primary_palette();
+    test_surface_attachment();
 }
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index a639834..a9d8237 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -5846,6 +5846,278 @@ static void test_primary_palette(void)
     DestroyWindow(window);
 }
 
+static HRESULT WINAPI surface_counter(IDirectDrawSurface4 *surface, DDSURFACEDESC2 *desc, void *context)
+{
+    UINT *surface_count = context;
+
+    ++(*surface_count);
+    IDirectDrawSurface_Release(surface);
+
+    return DDENUMRET_OK;
+}
+
+static void test_surface_attachment(void)
+{
+    IDirectDrawSurface4 *surface1, *surface2, *surface3, *surface4;
+    IDirectDrawSurface *surface1v1, *surface2v1;
+    DDSCAPS2 caps = {DDSCAPS_TEXTURE, 0, 0, 0};
+    DDSURFACEDESC2 surface_desc;
+    IDirectDraw4 *ddraw;
+    UINT surface_count;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(ddraw = create_ddraw()))
+    {
+        skip("Failed to create a ddraw object, skipping test.\n");
+        return;
+    }
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    U2(surface_desc).dwMipMapCount = 3;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_GetAttachedSurface(surface1, &caps, &surface2);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_GetAttachedSurface(surface2, &caps, &surface3);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_GetAttachedSurface(surface3, &caps, &surface4);
+    ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
+
+    surface_count = 0;
+    IDirectDrawSurface4_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface4_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface4_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
+    ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface3, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface3);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface2, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface2);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface4_Release(surface4);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    if (SUCCEEDED(hr = IDirectDrawSurface4_AddAttachedSurface(surface1, surface4)))
+    {
+        skip("Running on refrast, skipping some tests.\n");
+        hr = IDirectDrawSurface4_DeleteAttachedSurface(surface1, 0, surface4);
+        ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    }
+    else
+    {
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface1);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface4_AddAttachedSurface(surface3, surface4);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface3);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface4_AddAttachedSurface(surface2, surface4);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+        hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface2);
+        ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    }
+
+    IDirectDrawSurface4_Release(surface4);
+    IDirectDrawSurface4_Release(surface3);
+    IDirectDrawSurface4_Release(surface2);
+    IDirectDrawSurface4_Release(surface1);
+
+    hr = IDirectDraw4_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    /* Try a single primary and two offscreen plain surfaces. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    /* This one has a different size. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface1, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    /* Try the reverse without detaching first. */
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface2, surface1);
+    todo_wine ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface1, 0, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface2, surface1);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    /* Try to detach reversed. */
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(hr == DDERR_CANNOTDETACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface2, 0, surface1);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface2, surface3);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface2, 0, surface3);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface4_Release(surface4);
+    IDirectDrawSurface4_Release(surface3);
+    IDirectDrawSurface4_Release(surface2);
+    IDirectDrawSurface4_Release(surface1);
+
+    /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 64;
+    surface_desc.dwHeight = 64;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+    U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
+    U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 16;
+    U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0xf800;
+    U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x07e0;
+    U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x001f;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+    U1(U4(surface_desc).ddpfPixelFormat).dwZBufferBitDepth = 16;
+    U3(U4(surface_desc).ddpfPixelFormat).dwZBitMask = 0x0000ffff;
+    hr = IDirectDraw4_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_QueryInterface(surface1, &IID_IDirectDrawSurface, (void **)&surface1v1);
+    ok(SUCCEEDED(hr), "Failed to get interface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_QueryInterface(surface2, &IID_IDirectDrawSurface, (void **)&surface2v1);
+    ok(SUCCEEDED(hr), "Failed to get interface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    refcount = get_refcount((IUnknown *)surface2v1);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface1, surface2);
+    ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
+    todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1v1, 0, surface2v1);
+    ok(hr == DDERR_SURFACENOTATTACHED, "Got unexpected hr %#x.\n", hr);
+
+    /* Attaching while already attached to other surface. */
+    hr = IDirectDrawSurface4_AddAttachedSurface(surface3, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface3, 0, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    IDirectDrawSurface4_Release(surface3);
+
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+    refcount = get_refcount((IUnknown *)surface2v1);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+
+    /* DeleteAttachedSurface() when attaching via IDirectDrawSurface. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface4_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(hr == DDERR_SURFACENOTATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1v1, 0, surface2v1);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    refcount = IDirectDrawSurface4_Release(surface2);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface4_Release(surface1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+
+    /* Automatic detachment on release. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2v1);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface1v1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface2v1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDraw4_Release(ddraw);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw4)
 {
     test_process_vertices();
@@ -5889,4 +6161,5 @@ START_TEST(ddraw4)
     test_user_memory_getdc();
     test_sysmem_overlay();
     test_primary_palette();
+    test_surface_attachment();
 }
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 9520842..dcd4d1e 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -5725,6 +5725,260 @@ static void test_primary_palette(void)
     DestroyWindow(window);
 }
 
+static HRESULT WINAPI surface_counter(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *desc, void *context)
+{
+    UINT *surface_count = context;
+
+    ++(*surface_count);
+    IDirectDrawSurface_Release(surface);
+
+    return DDENUMRET_OK;
+}
+
+static void test_surface_attachment(void)
+{
+    IDirectDrawSurface7 *surface1, *surface2, *surface3, *surface4;
+    IDirectDrawSurface *surface1v1, *surface2v1;
+    DDSCAPS2 caps = {DDSCAPS_TEXTURE, 0, 0, 0};
+    DDSURFACEDESC2 surface_desc;
+    IDirectDraw7 *ddraw;
+    UINT surface_count;
+    ULONG refcount;
+    HWND window;
+    HRESULT hr;
+
+    if (!(ddraw = create_ddraw()))
+    {
+        skip("Failed to create a ddraw object, skipping test.\n");
+        return;
+    }
+
+    window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
+            0, 0, 640, 480, 0, 0, 0, 0);
+    hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
+    U2(surface_desc).dwMipMapCount = 3;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    if (FAILED(hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface1, NULL)))
+    {
+        skip("Failed to create a texture, skipping tests.\n");
+        IDirectDraw7_Release(ddraw);
+        DestroyWindow(window);
+        return;
+    }
+
+    hr = IDirectDrawSurface7_GetAttachedSurface(surface1, &caps, &surface2);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_GetAttachedSurface(surface2, &caps, &surface3);
+    ok(SUCCEEDED(hr), "Failed to get mip level, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_GetAttachedSurface(surface3, &caps, &surface4);
+    ok(hr == DDERR_NOTFOUND, "Got unexpected hr %#x.\n", hr);
+
+    surface_count = 0;
+    IDirectDrawSurface7_EnumAttachedSurfaces(surface1, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface7_EnumAttachedSurfaces(surface2, &surface_count, surface_counter);
+    ok(surface_count == 1, "Got unexpected surface_count %u.\n", surface_count);
+    surface_count = 0;
+    IDirectDrawSurface7_EnumAttachedSurfaces(surface3, &surface_count, surface_counter);
+    ok(!surface_count, "Got unexpected surface_count %u.\n", surface_count);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface3);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface2);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface7_Release(surface4);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 16;
+    surface_desc.dwHeight = 16;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface3);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface2);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface7_Release(surface4);
+    IDirectDrawSurface7_Release(surface3);
+    IDirectDrawSurface7_Release(surface2);
+    IDirectDrawSurface7_Release(surface1);
+
+    hr = IDirectDraw7_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
+    ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#x.\n", hr);
+
+    /* Try a single primary and two offscreen plain surfaces. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = GetSystemMetrics(SM_CXSCREEN);
+    surface_desc.dwHeight = GetSystemMetrics(SM_CYSCREEN);
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    /* This one has a different size. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
+    surface_desc.dwWidth = 128;
+    surface_desc.dwHeight = 128;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface4, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface3);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface4);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface1);
+    ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+
+    IDirectDrawSurface7_Release(surface4);
+    IDirectDrawSurface7_Release(surface3);
+    IDirectDrawSurface7_Release(surface2);
+    IDirectDrawSurface7_Release(surface1);
+
+    /* Test DeleteAttachedSurface() and automatic detachment of attached surfaces on release. */
+    memset(&surface_desc, 0, sizeof(surface_desc));
+    surface_desc.dwSize = sizeof(surface_desc);
+    surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
+    surface_desc.dwWidth = 64;
+    surface_desc.dwHeight = 64;
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
+    U4(surface_desc).ddpfPixelFormat.dwSize = sizeof(U4(surface_desc).ddpfPixelFormat);
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
+    U1(U4(surface_desc).ddpfPixelFormat).dwRGBBitCount = 16;
+    U2(U4(surface_desc).ddpfPixelFormat).dwRBitMask = 0xf800;
+    U3(U4(surface_desc).ddpfPixelFormat).dwGBitMask = 0x07e0;
+    U4(U4(surface_desc).ddpfPixelFormat).dwBBitMask = 0x001f;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface3, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
+    U4(surface_desc).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
+    U1(U4(surface_desc).ddpfPixelFormat).dwZBufferBitDepth = 16;
+    U3(U4(surface_desc).ddpfPixelFormat).dwZBitMask = 0x0000ffff;
+    hr = IDirectDraw7_CreateSurface(ddraw, &surface_desc, &surface2, NULL);
+    ok(SUCCEEDED(hr), "Failed to create surface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_QueryInterface(surface1, &IID_IDirectDrawSurface, (void **)&surface1v1);
+    ok(SUCCEEDED(hr), "Failed to get interface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_QueryInterface(surface2, &IID_IDirectDrawSurface, (void **)&surface2v1);
+    ok(SUCCEEDED(hr), "Failed to get interface, hr %#x.\n", hr);
+
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    refcount = get_refcount((IUnknown *)surface2v1);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
+    ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
+    todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1v1, 0, surface2v1);
+    ok(hr == DDERR_SURFACENOTATTACHED, "Got unexpected hr %#x.\n", hr);
+
+    /* Attaching while already attached to other surface. */
+    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_DeleteAttachedSurface(surface3, 0, surface2);
+    todo_wine ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    IDirectDrawSurface7_Release(surface3);
+
+    hr = IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+    refcount = get_refcount((IUnknown *)surface2v1);
+    ok(refcount == 1, "Got unexpected refcount %u.\n", refcount);
+
+    /* DeleteAttachedSurface() when attaching via IDirectDrawSurface. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    hr = IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface2);
+    ok(hr == DDERR_SURFACENOTATTACHED, "Got unexpected hr %#x.\n", hr);
+    hr = IDirectDrawSurface_DeleteAttachedSurface(surface1v1, 0, surface2v1);
+    ok(SUCCEEDED(hr), "Failed to detach surface, hr %#x.\n", hr);
+    refcount = IDirectDrawSurface7_Release(surface2);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface7_Release(surface1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+
+    /* Automatic detachment on release. */
+    hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
+    ok(SUCCEEDED(hr), "Failed to attach surface, hr %#x.\n", hr);
+    refcount = get_refcount((IUnknown *)surface2v1);
+    ok(refcount == 2, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface1v1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDrawSurface_Release(surface2v1);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    refcount = IDirectDraw7_Release(ddraw);
+    ok(!refcount, "Got unexpected refcount %u.\n", refcount);
+    DestroyWindow(window);
+}
+
 START_TEST(ddraw7)
 {
     HMODULE module = GetModuleHandleA("ddraw.dll");
@@ -5776,4 +6030,5 @@ START_TEST(ddraw7)
     test_user_memory_getdc();
     test_sysmem_overlay();
     test_primary_palette();
+    test_surface_attachment();
 }
diff --git a/dlls/ddraw/tests/dsurface.c b/dlls/ddraw/tests/dsurface.c
index b07eddb..560c323 100644
--- a/dlls/ddraw/tests/dsurface.c
+++ b/dlls/ddraw/tests/dsurface.c
@@ -1111,587 +1111,6 @@ static void EnumTest(void)
     IDirectDrawSurface_Release(surface);
 }
 
-static HRESULT WINAPI SurfaceCounter(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *desc, void *context)
-{
-    UINT *num = context;
-    (*num)++;
-    IDirectDrawSurface_Release(surface);
-    return DDENUMRET_OK;
-}
-
-static void AttachmentTest7(void)
-{
-    HRESULT hr;
-    IDirectDraw7 *dd7;
-    IDirectDrawSurface7 *surface1, *surface2, *surface3, *surface4;
-    IDirectDrawSurface *surface1v1, *surface2v1;
-    DDSCAPS2 caps = {DDSCAPS_TEXTURE, 0, 0, 0};
-    DDSURFACEDESC2 ddsd, ddsd2;
-    DWORD ref;
-    UINT num;
-    HWND window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
-            100, 100, 160, 160, NULL, NULL, NULL, NULL);
-
-    hr = IDirectDraw_QueryInterface(lpDD, &IID_IDirectDraw7, (void **) &dd7);
-    ok(hr == DD_OK, "IDirectDraw_QueryInterface returned %08x\n", hr);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
-    U2(ddsd).dwMipMapCount = 3; /* Will create 128x128, 64x64, 32x32 */
-    ddsd.dwWidth = 128;
-    ddsd.dwHeight = 128;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface1, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    /* ROOT */
-    num = 0;
-    IDirectDrawSurface7_EnumAttachedSurfaces(surface1, &num, SurfaceCounter);
-    ok(num == 1, "Mipmap root has %d surfaces attached, expected 1\n", num);
-    /* DONE ROOT */
-
-    /* LEVEL 1 */
-    hr = IDirectDrawSurface7_GetAttachedSurface(surface1, &caps, &surface2);
-    ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
-    num = 0;
-    IDirectDrawSurface7_EnumAttachedSurfaces(surface2, &num, SurfaceCounter);
-    ok(num == 1, "First mip level has %d surfaces attached, expected 1\n", num);
-    /* DONE LEVEL 1 */
-
-    /* LEVEL 2 */
-    hr = IDirectDrawSurface7_GetAttachedSurface(surface2, &caps, &surface3);
-    ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
-    IDirectDrawSurface7_Release(surface2);
-    num = 0;
-    IDirectDrawSurface7_EnumAttachedSurfaces(surface3, &num, SurfaceCounter);
-    ok(num == 0, "Second mip level has %d surfaces attached, expected 1\n", num);
-    /* Done level 2 */
-    /* Mip level 3 is still needed */
-    hr = IDirectDrawSurface7_GetAttachedSurface(surface3, &caps, &surface4);
-    ok(hr == DDERR_NOTFOUND, "GetAttachedSurface returned %08x\n", hr);
-    ok(!surface4, "expected NULL pointer\n");
-
-    /* Try to attach a 16x16 miplevel - Should not work as far I can see */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
-    ddsd.dwWidth = 16;
-    ddsd.dwHeight = 16;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface2, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 surface to a 128x128 texture root returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface1);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 128x128 texture root to a 16x16 texture returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 surface to a 32x32 texture mip level returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface3);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 32x32 texture mip level to a 16x16 surface returned %08x\n", hr);
-
-    IDirectDrawSurface7_Release(surface2);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 16;
-    ddsd.dwHeight = 16;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface2, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 offscreen plain surface to a 128x128 texture root returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface1);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 128x128 texture root to a 16x16 offscreen plain surface returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 offscreen plain surface to a 32x32 texture mip level returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface3);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 32x32 texture mip level to a 16x16 offscreen plain surface returned %08x\n", hr);
-
-    IDirectDrawSurface7_Release(surface3);
-    IDirectDrawSurface7_Release(surface2);
-    IDirectDrawSurface7_Release(surface1);
-
-    hr = IDirectDraw7_SetCooperativeLevel(dd7, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
-    ok(hr == DD_OK, "SetCooperativeLevel returned %08x\n", hr);
-
-    /* Those are some invalid descriptions, no need to test attachments with them */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface1, NULL);
-    ok(hr==DDERR_INVALIDCAPS,"CreateSurface returned: %x\n",hr);
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface2, NULL);
-    ok(hr==DDERR_INVALIDCAPS,"CreateSurface returned: %x\n",hr);
-
-    /* Try a single primary and two offscreen plain surfaces */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface1, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN);
-    ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface2, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN);
-    ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface3, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    /* This one has a different size */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 128;
-    ddsd.dwHeight = 128;
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface4, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching an offscreen plain surface to a front buffer returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface1);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a front buffer to an offscreen plain surface returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface3);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching an offscreen plain surface to another offscreen plain surface returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface4);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching an offscreen plain surface to a front buffer of different size returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface1);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a front buffer to an offscreen plain surface of different size returned %08x\n", hr);
-
-    IDirectDrawSurface7_Release(surface4);
-    IDirectDrawSurface7_Release(surface3);
-    IDirectDrawSurface7_Release(surface2);
-    IDirectDrawSurface7_Release(surface1);
-
-    /* Test DeleteAttachedSurface and automatic detachment of attached surfaces on release */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
-    ddsd.dwWidth = 64;
-    ddsd.dwHeight = 64;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
-    U4(ddsd).ddpfPixelFormat.dwSize = sizeof(U4(ddsd).ddpfPixelFormat);
-    U4(ddsd).ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
-    U1(U4(ddsd).ddpfPixelFormat).dwRGBBitCount = 16;
-    U2(U4(ddsd).ddpfPixelFormat).dwRBitMask = 0xF800;
-    U3(U4(ddsd).ddpfPixelFormat).dwGBitMask = 0x07E0;
-    U4(U4(ddsd).ddpfPixelFormat).dwBBitMask = 0x001F;
-
-    memset(&ddsd2, 0, sizeof(ddsd2));
-    ddsd2.dwSize = sizeof(ddsd2);
-    ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
-    ddsd2.dwWidth = ddsd.dwWidth;
-    ddsd2.dwHeight = ddsd.dwHeight;
-    ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
-    U4(ddsd2).ddpfPixelFormat.dwSize = sizeof(U4(ddsd2).ddpfPixelFormat);
-    U4(ddsd2).ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
-    U1(U4(ddsd2).ddpfPixelFormat).dwZBufferBitDepth = 16;
-    U3(U4(ddsd2).ddpfPixelFormat).dwZBitMask = 0x0000FFFF;
-
-    hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface1, NULL);
-    ok(hr == DD_OK, "CreateSurface returned %08x\n", hr);
-    if (SUCCEEDED(hr))
-    {
-        hr = IDirectDraw7_CreateSurface(dd7, &ddsd2, &surface2, NULL);
-        ok(hr == DD_OK, "CreateSurface returned %08x\n", hr);
-        if (SUCCEEDED(hr))
-        {
-            hr = IDirectDrawSurface7_QueryInterface(surface1, &IID_IDirectDrawSurface, (void **)&surface1v1);
-            ok(hr == DD_OK, "IDirectDrawSurface7_QueryInterface returned %08x\n", hr);
-            hr = IDirectDrawSurface7_QueryInterface(surface2, &IID_IDirectDrawSurface, (void **)&surface2v1);
-            ok(hr == DD_OK, "IDirectDrawSurface7_QueryInterface returned %08x\n", hr);
-
-            /* DeleteAttachedSurface when attaching via IDirectDrawSurface7 */
-            hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
-            ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-            if (SUCCEEDED(hr))
-            {
-                ref = getRefcount((IUnknown *)surface2);
-                ok(ref == 2, "Got refcount %d, expected 2\n", ref);
-                ref = getRefcount((IUnknown *)surface2v1);
-                ok(ref == 1, "Got refcount %d, expected 1\n", ref);
-
-                /* Try reattach */
-                hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface2);
-                ok(hr == DDERR_SURFACEALREADYATTACHED, "AddAttachedSurface returned %08x\n", hr);
-
-                /* Attachment / detachment on another interface */
-                hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
-                todo_wine ok(hr == DDERR_CANNOTATTACHSURFACE, "AddAttachedSurface returned %08x\n", hr);
-                hr = IDirectDrawSurface_DeleteAttachedSurface(surface1v1, 0, surface2v1);
-                ok(hr == DDERR_SURFACENOTATTACHED, "DeleteAttachedSurface returned %08x\n", hr);
-
-                /* Attaching while already attached to other surface */
-                hr = IDirectDraw7_CreateSurface(dd7, &ddsd, &surface3, NULL);
-                ok(hr == DD_OK, "CreateSurface returned %08x\n", hr);
-                if (SUCCEEDED(hr))
-                {
-                    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface2);
-                    todo_wine ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-                    if (SUCCEEDED(hr))
-                    {
-                        hr = IDirectDrawSurface7_DeleteAttachedSurface(surface3, 0, surface2);
-                        ok(hr == DD_OK, "DeleteAttachedSurface returned %08x\n", hr);
-                    }
-                    IDirectDrawSurface7_Release(surface3);
-                }
-
-                hr = IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface2);
-                ok(hr == DD_OK, "DeleteAttachedSurface returned %08x\n", hr);
-                ref = getRefcount((IUnknown *)surface2);
-                ok(ref == 1, "Got refcount %d, expected 1\n", ref);
-                ref = getRefcount((IUnknown *)surface2v1);
-                ok(ref == 1, "Got refcount %d, expected 1\n", ref);
-            }
-
-            /* DeleteAttachedSurface when attaching via IDirectDrawSurface */
-            hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
-            ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-            if (SUCCEEDED(hr))
-            {
-                hr = IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface2);
-                ok(hr == DDERR_SURFACENOTATTACHED, "DeleteAttachedSurface returned %08x\n", hr);
-                hr = IDirectDrawSurface_DeleteAttachedSurface(surface1v1, 0, surface2v1);
-                ok(hr == DD_OK, "DeleteAttachedSurface returned %08x\n", hr);
-            }
-            ref = IDirectDrawSurface7_Release(surface2);
-            ok(!ref, "Got refcount %d, expected 0\n", ref);
-            ref = IDirectDrawSurface7_Release(surface1);
-            ok(!ref, "Got refcount %d, expected 0\n", ref);
-
-            /* Automatic detachment on release */
-            hr = IDirectDrawSurface_AddAttachedSurface(surface1v1, surface2v1);
-            ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-            ref = getRefcount((IUnknown *)surface2v1);
-            ok(ref == 2, "Got refcount %d, expected 2\n", ref);
-            ref = IDirectDrawSurface_Release(surface1v1);
-            ok(!ref, "Got refcount %d, expected 0\n", ref);
-            ref = getRefcount((IUnknown *)surface2v1);
-            ok(ref == 1, "Got refcount %d, expected 1\n", ref);
-            ref = IDirectDrawSurface_Release(surface2v1);
-            ok(!ref, "Got refcount %d, expected 0\n", ref);
-        }
-        else
-            IDirectDrawSurface7_Release(surface1);
-    }
-
-    hr =IDirectDraw7_SetCooperativeLevel(dd7, NULL, DDSCL_NORMAL);
-    ok(hr == DD_OK, "SetCooperativeLevel returned %08x\n", hr);
-    IDirectDraw7_Release(dd7);
-}
-
-static void AttachmentTest(void)
-{
-    HRESULT hr;
-    IDirectDrawSurface *surface1, *surface2, *surface3, *surface4;
-    DDSURFACEDESC ddsd, ddsd2;
-    DWORD ref;
-    DDSCAPS caps = {DDSCAPS_TEXTURE};
-    BOOL refrast = FALSE;
-    HWND window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW,
-            100, 100, 160, 160, NULL, NULL, NULL, NULL);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_MIPMAPCOUNT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP;
-    U2(ddsd).dwMipMapCount = 3; /* Will create 128x128, 64x64, 32x32 */
-    ddsd.dwWidth = 128;
-    ddsd.dwHeight = 128;
-    hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &surface1, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    hr = IDirectDrawSurface7_GetAttachedSurface(surface1, &caps, &surface2);
-    ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
-    hr = IDirectDrawSurface7_GetAttachedSurface(surface2, &caps, &surface3);
-    ok(hr == DD_OK, "GetAttachedSurface returned %08x\n", hr);
-
-    /* Try to attach a 16x16 miplevel - Should not work as far I can see */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE;
-    ddsd.dwWidth = 16;
-    ddsd.dwHeight = 16;
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface4, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface4);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 surface to a 128x128 texture root returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface1);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 128x128 texture root to a 16x16 texture returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface4);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 surface to a 32x32 texture mip level returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface3);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 32x32 texture mip level to a 16x16 surface returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface4);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 surface to a 64x64 texture sublevel returned %08x\n", hr);
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 64x64 texture sublevel to a 16x16 texture returned %08x\n", hr);
-
-    IDirectDrawSurface7_Release(surface4);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 16;
-    ddsd.dwHeight = 16;
-    hr = IDirectDraw7_CreateSurface(lpDD, &ddsd, &surface4, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    if (SUCCEEDED(IDirectDrawSurface7_AddAttachedSurface(surface1, surface4)))
-    {
-        IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface4);
-        refrast = TRUE;
-    }
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface1, surface4); /* Succeeds on refrast */
-    if (refrast)
-        ok(hr == S_OK, "Attaching a 16x16 offscreen plain surface to a 128x128 texture root returned %08x\n", hr);
-    else
-        ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 offscreen plain surface to a 128x128 texture root returned %08x\n", hr);
-    if(SUCCEEDED(hr)) IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface4);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface1);  /* Succeeds on refrast */
-    if (refrast)
-        ok(hr == S_OK, "Attaching a 128x128 texture root to a 16x16 offscreen plain surface returned %08x\n", hr);
-    else
-        ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 128x128 texture root to a 16x16 offscreen plain surface returned %08x\n", hr);
-    if(SUCCEEDED(hr)) IDirectDrawSurface7_DeleteAttachedSurface(surface1, 0, surface1);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface3, surface4);  /* Succeeds on refrast */
-    if (refrast)
-        ok(hr == S_OK, "Attaching a 16x16 offscreen plain surface to a 32x32 texture mip level returned %08x\n", hr);
-    else
-        ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 offscreen plain surface to a 32x32 texture mip level returned %08x\n", hr);
-    if(SUCCEEDED(hr)) IDirectDrawSurface7_DeleteAttachedSurface(surface3, 0, surface4);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface3);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 32x32 texture mip level to a 16x16 offscreen plain surface returned %08x\n", hr);
-    if(SUCCEEDED(hr)) IDirectDrawSurface7_DeleteAttachedSurface(surface4, 0, surface3);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface2, surface4);  /* Succeeds on refrast */
-    if (refrast)
-        ok(hr == S_OK, "Attaching a 16x16 offscreen plain surface to a 64x64 texture sublevel returned %08x\n", hr);
-    else
-        ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 16x16 offscreen plain surface to a 64x64 texture sublevel returned %08x\n", hr);
-    if(SUCCEEDED(hr)) IDirectDrawSurface7_DeleteAttachedSurface(surface2, 0, surface4);
-
-    hr = IDirectDrawSurface7_AddAttachedSurface(surface4, surface2);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a 64x64 texture sublevel to a 16x16 offscreen plain surface returned %08x\n", hr);
-    if(SUCCEEDED(hr)) IDirectDrawSurface7_DeleteAttachedSurface(surface4, 0, surface2);
-
-    IDirectDrawSurface7_Release(surface4);
-    IDirectDrawSurface7_Release(surface3);
-    IDirectDrawSurface7_Release(surface2);
-    IDirectDrawSurface7_Release(surface1);
-
-    hr = IDirectDraw_SetCooperativeLevel(lpDD, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
-    ok(hr == DD_OK, "SetCooperativeLevel returned %08x\n", hr);
-
-    /* Creating a back buffer as-is, is not allowed. No need to perform attachment tests */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER;
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface2, NULL);
-    ok(hr==DDERR_INVALIDCAPS,"CreateSurface returned: %x\n",hr);
-    /* This old ddraw version happily creates explicit front buffers */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER;
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface1, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-    IDirectDrawSurface_Release(surface1);
-
-    /* Try a single primary and two offscreen plain surfaces */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface1, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN);
-    ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface2, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN);
-    ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN);
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface3, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    /* This one has a different size */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
-    ddsd.dwWidth = 128;
-    ddsd.dwHeight = 128;
-    hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface4, NULL);
-    ok(hr==DD_OK,"CreateSurface returned: %x\n",hr);
-
-    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
-    ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE),
-       "Attaching an offscreen plain surface to a front buffer returned %08x\n", hr);
-    if(SUCCEEDED(hr))
-    {
-        /* Try the reverse without detaching first */
-        hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
-        ok(hr == DDERR_SURFACEALREADYATTACHED, "Attaching an attached surface to its attachee returned %08x\n", hr);
-        hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
-        ok(hr == DD_OK, "DeleteAttachedSurface failed with %08x\n", hr);
-    }
-    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1);
-    ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE),
-       "Attaching a front buffer to an offscreen plain surface returned %08x\n", hr);
-    if(SUCCEEDED(hr))
-    {
-        /* Try to detach reversed */
-        hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
-        ok(hr == DDERR_CANNOTDETACHSURFACE, "DeleteAttachedSurface returned %08x\n", hr);
-        /* Now the proper detach */
-        hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1);
-        ok(hr == DD_OK, "DeleteAttachedSurface failed with %08x\n", hr);
-    }
-    hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3); /* Fails on refrast */
-    ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE),
-       "Attaching an offscreen plain surface to another offscreen plain surface returned %08x\n", hr);
-    if(SUCCEEDED(hr))
-    {
-        hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3);
-        ok(hr == DD_OK, "DeleteAttachedSurface failed with %08x\n", hr);
-    }
-    hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching an offscreen plain surface to a front buffer of different size returned %08x\n", hr);
-    hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1);
-    ok(hr == DDERR_CANNOTATTACHSURFACE, "Attaching a front buffer to an offscreen plain surface of different size returned %08x\n", hr);
-
-    IDirectDrawSurface_Release(surface4);
-    IDirectDrawSurface_Release(surface3);
-    IDirectDrawSurface_Release(surface2);
-    IDirectDrawSurface_Release(surface1);
-
-    /* Test DeleteAttachedSurface and automatic detachment of attached surfaces on release */
-    memset(&ddsd, 0, sizeof(ddsd));
-    ddsd.dwSize = sizeof(ddsd);
-    ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
-    ddsd.dwWidth = 64;
-    ddsd.dwHeight = 64;
-    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
-    ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat);
-    ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; /* D3DFMT_R5G6B5 */
-    U1(ddsd.ddpfPixelFormat).dwRGBBitCount = 16;
-    U2(ddsd.ddpfPixelFormat).dwRBitMask = 0xF800;
-    U3(ddsd.ddpfPixelFormat).dwGBitMask = 0x07E0;
-    U4(ddsd.ddpfPixelFormat).dwBBitMask = 0x001F;
-
-    memset(&ddsd2, 0, sizeof(ddsd2));
-    ddsd2.dwSize = sizeof(ddsd2);
-    ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
-    ddsd2.dwWidth = ddsd.dwWidth;
-    ddsd2.dwHeight = ddsd.dwHeight;
-    ddsd2.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
-    ddsd2.ddpfPixelFormat.dwSize = sizeof(ddsd2.ddpfPixelFormat);
-    ddsd2.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER;
-    U1(ddsd2.ddpfPixelFormat).dwZBufferBitDepth = 16;
-    U3(ddsd2.ddpfPixelFormat).dwZBitMask = 0x0000FFFF;
-
-    hr = IDirectDraw_CreateSurface(lpDD, (DDSURFACEDESC *)&ddsd, &surface1, NULL);
-    ok(hr == DD_OK, "CreateSurface returned %08x\n", hr);
-    if (SUCCEEDED(hr))
-    {
-        hr = IDirectDraw_CreateSurface(lpDD, (DDSURFACEDESC *)&ddsd2, &surface2, NULL);
-        ok(hr == DD_OK, "CreateSurface returned %08x\n", hr);
-        if (SUCCEEDED(hr))
-        {
-            /* DeleteAttachedSurface */
-            hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
-            ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-            if (SUCCEEDED(hr))
-            {
-                ref = getRefcount((IUnknown *)surface2);
-                ok(ref == 2, "Got refcount %d, expected 2\n", ref);
-
-                /* Try reattach */
-                hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
-                ok(hr == DDERR_SURFACEALREADYATTACHED, "AddAttachedSurface returned %08x\n", hr);
-
-                /* Attaching while already attached to other surface */
-                hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface3, NULL);
-                ok(hr == DD_OK, "CreateSurface returned %08x\n", hr);
-                if (SUCCEEDED(hr))
-                {
-                    hr = IDirectDrawSurface_AddAttachedSurface(surface3, surface2);
-                    todo_wine ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-                    if (SUCCEEDED(hr))
-                    {
-                        hr = IDirectDrawSurface_DeleteAttachedSurface(surface3, 0, surface2);
-                        ok(hr == DD_OK, "DeleteAttachedSurface returned %08x\n", hr);
-                    }
-                    IDirectDrawSurface_Release(surface3);
-                }
-
-                hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2);
-                ok(hr == DD_OK, "DeleteAttachedSurface returned %08x\n", hr);
-                ref = getRefcount((IUnknown *)surface2);
-                ok(ref == 1, "Got refcount %d, expected 2\n", ref);
-            }
-
-            /* Automatic detachment on release */
-            hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2);
-            ok(hr == DD_OK, "AddAttachedSurface returned %08x\n", hr);
-            ref = getRefcount((IUnknown *)surface2);
-            ok(ref == 2, "Got refcount %d, expected 2\n", ref);
-            ref = IDirectDrawSurface_Release(surface1);
-            ok(!ref, "Got refcount %d, expected 0\n", ref);
-            ref = getRefcount((IUnknown *)surface2);
-            ok(ref == 1, "Got refcount %d, expected 1\n", ref);
-            ref = IDirectDrawSurface_Release(surface2);
-            ok(!ref, "Got refcount %d, expected 0\n", ref);
-        }
-        else
-            IDirectDrawSurface_Release(surface1);
-    }
-
-    hr =IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL);
-    ok(hr == DD_OK, "SetCooperativeLevel returned %08x\n", hr);
-
-    DestroyWindow(window);
-}
-
 struct compare
 {
     DWORD width, height;
@@ -4606,8 +4025,6 @@ START_TEST(dsurface)
     GetDDInterface_4();
     GetDDInterface_7();
     EnumTest();
-    AttachmentTest();
-    AttachmentTest7();
     CubeMapTest();
     test_lockrect_invalid();
     CompressedTest();
-- 
1.7.10.4




More information about the wine-patches mailing list