From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/tests/ddraw1.c | 556 +++++++++++++++++++++++++++++++++++--- 1 file changed, 522 insertions(+), 34 deletions(-) diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 007daf29407..6ce50821590 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -452,6 +452,21 @@ static void fill_surface(IDirectDrawSurface *surface, D3DCOLOR color) ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr); } +#define check_surface_caps(a, b, c, d) check_surface_caps_(__LINE__, (a), (b), (c), (d)) +static void check_surface_caps_(unsigned int line, IDirectDrawSurface *surface, DWORD expected_caps, + DWORD exclude_caps, DWORD expected_buffer_count) +{ + DDSURFACEDESC surface_desc = {.dwSize = sizeof(surface_desc) }; + HRESULT hr; + + hr = IDirectDrawSurface_GetSurfaceDesc(surface, &surface_desc); + ok_(__FILE__, line)(hr == DD_OK, "got %#lx.\n", hr); + ok_(__FILE__, line)((surface_desc.ddsCaps.dwCaps & ~exclude_caps) == expected_caps, "got %#lx, expected %#lx.\n", + surface_desc.ddsCaps.dwCaps & ~exclude_caps, expected_caps); + ok_(__FILE__, line)(surface_desc.dwBackBufferCount == expected_buffer_count, "got backbuffer count %ld, expected %ld.\n", + surface_desc.dwBackBufferCount, expected_buffer_count); +} + static void check_rect(IDirectDrawSurface *surface, RECT r) { LONG x_coords[2][2] = @@ -5406,13 +5421,16 @@ static void test_flip(void) IDirectDrawSurface *frontbuffer, *backbuffer1, *backbuffer2, *backbuffer3, *surface; DDSCAPS caps = {DDSCAPS_FLIP}; DDSURFACEDESC surface_desc; + IDirect3DDevice *device; unsigned int color, i; + DWORD expected_caps; BOOL sysmem_primary; IDirectDraw *ddraw; - DWORD expected_caps; + BOOL have_3ddevice; ULONG refcount; HWND window; HRESULT hr; + LONG ref; static const struct { @@ -5430,6 +5448,16 @@ static void test_flip(void) ddraw = create_ddraw(); ok(!!ddraw, "Failed to create a ddraw object.\n"); + if ((device = create_device(ddraw, window, DDSCL_NORMAL))) + { + have_3ddevice = TRUE; + IDirect3DDevice_Release(device); + } + else + { + have_3ddevice = FALSE; + } + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); ok(SUCCEEDED(hr), "Failed to set cooperative level, hr %#lx.\n", hr); @@ -5489,52 +5517,26 @@ static void test_flip(void) hr = restore_surfaces(ddraw); ok(SUCCEEDED(hr), "%s: Failed to restore surfaces, hr %#lx.\n", test_data[i].name, hr); - memset(&surface_desc, 0, sizeof(surface_desc)); - surface_desc.dwSize = sizeof(surface_desc); - hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc); - ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr); expected_caps = DDSCAPS_FRONTBUFFER | DDSCAPS_COMPLEX | DDSCAPS_FLIP | test_data[i].caps; if (test_data[i].caps & DDSCAPS_PRIMARYSURFACE) expected_caps |= DDSCAPS_VISIBLE; - ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps, - "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps); + check_surface_caps(frontbuffer, expected_caps, placement, 3); sysmem_primary = surface_desc.ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY; hr = IDirectDrawSurface_GetAttachedSurface(frontbuffer, &caps, &backbuffer1); ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr); - memset(&surface_desc, 0, sizeof(surface_desc)); - surface_desc.dwSize = sizeof(surface_desc); - hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer1, &surface_desc); - ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr); - ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n", - test_data[i].name, surface_desc.dwBackBufferCount); expected_caps &= ~(DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER); expected_caps |= DDSCAPS_BACKBUFFER; - ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps, - "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps); + check_surface_caps(backbuffer1, expected_caps, placement, 0); hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &backbuffer2); ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr); - memset(&surface_desc, 0, sizeof(surface_desc)); - surface_desc.dwSize = sizeof(surface_desc); - hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer2, &surface_desc); - ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr); - ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n", - test_data[i].name, surface_desc.dwBackBufferCount); expected_caps &= ~DDSCAPS_BACKBUFFER; - ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps, - "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps); + check_surface_caps(backbuffer2, expected_caps, placement, 0); hr = IDirectDrawSurface_GetAttachedSurface(backbuffer2, &caps, &backbuffer3); ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr); - memset(&surface_desc, 0, sizeof(surface_desc)); - surface_desc.dwSize = sizeof(surface_desc); - hr = IDirectDrawSurface_GetSurfaceDesc(backbuffer3, &surface_desc); - ok(SUCCEEDED(hr), "%s: Failed to get surface desc, hr %#lx.\n", test_data[i].name, hr); - ok(!surface_desc.dwBackBufferCount, "%s: Got unexpected back buffer count %lu.\n", - test_data[i].name, surface_desc.dwBackBufferCount); - ok((surface_desc.ddsCaps.dwCaps & ~placement) == expected_caps, - "%s: Got unexpected caps %#lx.\n", test_data[i].name, surface_desc.ddsCaps.dwCaps); + check_surface_caps(backbuffer3, expected_caps, placement, 0); hr = IDirectDrawSurface_GetAttachedSurface(backbuffer3, &caps, &surface); ok(SUCCEEDED(hr), "%s: Failed to get attached surface, hr %#lx.\n", test_data[i].name, hr); @@ -5631,6 +5633,222 @@ static void test_flip(void) IDirectDrawSurface_Release(frontbuffer); } + /* Test adding backbuffers to primary surface in exclusive fullscreen mode. */ + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(frontbuffer, 0xffff0000); + + hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc); + ok(hr == DD_OK, "got %#lx.\n", hr); + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &backbuffer1, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(backbuffer1, 0xff00ff00); + + hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc); + ok(hr == DD_OK, "got %#lx.\n", hr); + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER | DDSCAPS_3DDEVICE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &backbuffer2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(backbuffer2, 0xff0000ff); + + hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "Got unexpected hr %#lx.\n", hr); + + check_surface_caps(frontbuffer, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER, placement, 0); + check_surface_caps(backbuffer1, DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE, placement, 0); + check_surface_caps(backbuffer2, DDSCAPS_FRONTBUFFER | DDSCAPS_3DDEVICE, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer1, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(frontbuffer, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER, placement, 0); + check_surface_caps(backbuffer1, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE, placement, 0); + check_surface_caps(backbuffer2, DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER | DDSCAPS_3DDEVICE, placement, 0); + + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer2, 0, backbuffer1); + ok(hr == DDERR_CANNOTDETACHSURFACE, "Failed to delete attached surface, hr %#lx.\n", hr); + + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 2, "got %ld.\n", ref); + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 1, "got %ld.\n", ref); + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer1, 0, backbuffer2); + ok(hr == DD_OK, "Failed to delete attached surface, hr %#lx.\n", hr); + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 1, "got %ld.\n", ref); + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 1, "got %ld.\n", ref); + + check_surface_caps(backbuffer2, DDSCAPS_3DDEVICE, placement, 0); + + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 1, "got %ld.\n", ref); + hr = IDirectDrawSurface_AddAttachedSurface(frontbuffer, backbuffer1); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 2, "got %ld.\n", ref); + + check_surface_caps(frontbuffer, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP, placement, 0); + check_surface_caps(backbuffer1, DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE | DDSCAPS_FLIP, placement, 0); + + hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT); + ok(hr == DD_OK, "got %#lx.\n", hr); + + if (have_3ddevice) + { + hr = IDirectDrawSurface_QueryInterface(backbuffer1, &IID_IDirect3DHALDevice, (void **)&device); + todo_wine ok(hr == DD_OK || broken(hr == E_FAIL), "got %#lx.\n", hr); + if (SUCCEEDED(hr)) + IDirect3DDevice_Release(device); + } + + color = get_surface_color(frontbuffer, 1, 1); + ok(color == 0x0000ff00, "got %#x.\n", color); + color = get_surface_color(backbuffer1, 1, 1); + ok(color == 0x00ff0000, "got %#x.\n", color); + + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 1, "got %ld.\n", ref); + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer1, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 2, "got %ld.\n", ref); + check_surface_caps(backbuffer2, DDSCAPS_3DDEVICE | DDSCAPS_FLIP, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer1, backbuffer2); + ok(hr == DDERR_SURFACEALREADYATTACHED, "got %#lx.\n", hr); + hr = IDirectDrawSurface_AddAttachedSurface(frontbuffer, backbuffer2); + ok(hr == DDERR_CANNOTATTACHSURFACE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_Flip(backbuffer2, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT); + ok(hr == DD_OK, "got %#lx.\n", hr); + + color = get_surface_color(frontbuffer, 1, 1); + ok(color == 0x00ff0000, "got %#x.\n", color); + color = get_surface_color(backbuffer1, 1, 1); + ok(color == 0x000000ff, "got %#x.\n", color); + color = get_surface_color(backbuffer2, 1, 1); + ok(color == 0x0000ff00, "got %#x.\n", color); + + hr = IDirectDrawSurface_DeleteAttachedSurface(frontbuffer, 0, backbuffer2); + ok(hr == DDERR_SURFACENOTATTACHED, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)frontbuffer); + ok(ref == 1, "got %ld.\n", ref); + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer1, 0, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)frontbuffer); + todo_wine ok(ref == 2, "got %ld.\n", ref); + + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 2, "got %ld.\n", ref); + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 1, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(frontbuffer); + todo_wine ok(ref == 1, "got %ld.\n", ref); + if (ref) + IDirectDrawSurface_Release(frontbuffer); + ref = IDirectDrawSurface_Release(backbuffer1); + ok(!ref, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(backbuffer2); + ok(!ref, "got %ld.\n", ref); + + /* Test adding backbuffers to primary surface in windowed mode. */ + hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &frontbuffer, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(frontbuffer, 0xffff0000); + + hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc); + ok(hr == DD_OK, "got %#lx.\n", hr); + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &backbuffer1, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(backbuffer1, 0xff00ff00); + + hr = IDirectDrawSurface_GetSurfaceDesc(frontbuffer, &surface_desc); + ok(hr == DD_OK, "got %#lx.\n", hr); + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER | DDSCAPS_3DDEVICE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &backbuffer2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + fill_surface(backbuffer2, 0xff0000ff); + + hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "Got unexpected hr %#lx.\n", hr); + + check_surface_caps(frontbuffer, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER, placement, 0); + + hr = IDirectDrawSurface_AddAttachedSurface(frontbuffer, backbuffer1); + ok(hr == DDERR_NOEXCLUSIVEMODE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_AddAttachedSurface(frontbuffer, backbuffer2); + ok(hr == DDERR_NOEXCLUSIVEMODE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer1, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(backbuffer1, DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE | DDSCAPS_FLIP, placement, 0); + + hr = IDirectDrawSurface_AddAttachedSurface(frontbuffer, backbuffer1); + ok(hr == DDERR_NOEXCLUSIVEMODE, "got %#lx.\n", hr); + + check_surface_caps(backbuffer2, DDSCAPS_FRONTBUFFER | DDSCAPS_3DDEVICE | DDSCAPS_FLIP, placement, 0); + + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer2, 0, backbuffer1); + ok(hr == DDERR_CANNOTDETACHSURFACE, "Failed to delete attached surface, hr %#lx.\n", hr); + + hr = IDirectDrawSurface_AddAttachedSurface(frontbuffer, backbuffer1); + ok(hr == DDERR_NOEXCLUSIVEMODE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_Flip(backbuffer2, NULL, DDFLIP_WAIT); + ok(hr == DD_OK, "got %#lx.\n", hr); + + color = get_surface_color(backbuffer1, 1, 1); + ok(color == 0x000000ff, "got %#x.\n", color); + color = get_surface_color(backbuffer2, 1, 1); + ok(color == 0x0000ff00, "got %#x.\n", color); + + hr = IDirectDrawSurface_Flip(backbuffer2, NULL, DDFLIP_WAIT); + ok(hr == DD_OK, "got %#lx.\n", hr); + hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "got %#lx.\n", hr); + + color = get_surface_color(backbuffer1, 1, 1); + ok(color == 0x0000ff00, "got %#x.\n", color); + color = get_surface_color(backbuffer2, 1, 1); + ok(color == 0x000000ff, "got %#x.\n", color); + + ref = IDirectDrawSurface_Release(frontbuffer); + ok(!ref, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(backbuffer1); + ok(!ref, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(backbuffer2); + ok(!ref, "got %ld.\n", ref); + + hr = IDirectDraw_SetCooperativeLevel(ddraw, NULL, DDSCL_NORMAL); + ok(hr == DD_OK, "got %#lx.\n", hr); + refcount = IDirectDraw_Release(ddraw); ok(!refcount, "Unexpected refcount %lu.\n", refcount); DestroyWindow(window); @@ -5840,14 +6058,17 @@ static HRESULT WINAPI surface_counter(IDirectDrawSurface *surface, DDSURFACEDESC static void test_surface_attachment(void) { - IDirectDrawSurface *surface1, *surface2, *surface3, *surface4; - DDSCAPS caps = {DDSCAPS_TEXTURE}; + const DWORD placement = DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY; + IDirectDrawSurface *surface1, *surface2, *surface3, *surface4, *surface5, *surface6, *tmp; + IDirectDrawSurface *backbuffer1, *backbuffer2; DDSURFACEDESC surface_desc; IDirectDraw *ddraw; UINT surface_count; ULONG refcount; + DDSCAPS caps; HWND window; HRESULT hr; + LONG ref; window = create_window(); ddraw = create_ddraw(); @@ -5865,6 +6086,7 @@ static void test_surface_attachment(void) hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL); ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr); + caps.dwCaps = DDSCAPS_TEXTURE; hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &surface2); ok(SUCCEEDED(hr), "Failed to get mip level, hr %#lx.\n", hr); hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &surface3); @@ -5980,8 +6202,30 @@ static void test_surface_attachment(void) hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface4, NULL); ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\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_BACKBUFFER; + surface_desc.dwWidth = registry_mode.dmPelsWidth; + surface_desc.dwHeight = registry_mode.dmPelsHeight; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface5, NULL); + ok(hr == DD_OK, "got %#lx.\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_FRONTBUFFER; + surface_desc.dwWidth = registry_mode.dmPelsWidth; + surface_desc.dwHeight = registry_mode.dmPelsHeight; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface6, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + check_surface_caps(surface1, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE, + placement, 0); hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr); + check_surface_caps(surface1, DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_VISIBLE | DDSCAPS_FLIP, + placement, 0); /* Try the reverse without detaching first. */ hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#lx.\n", hr); @@ -6006,10 +6250,250 @@ static void test_surface_attachment(void) hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1); ok(hr == DDERR_CANNOTATTACHSURFACE, "Got unexpected hr %#lx.\n", hr); + check_surface_caps(surface5, DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, DDSCAPS_FRONTBUFFER, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(surface5, surface6); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(surface5, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface6); + ok(hr == DDERR_CANNOTATTACHSURFACE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface5); + ok(hr == DDERR_CANNOTATTACHSURFACE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_DeleteAttachedSurface(surface5, 0, surface6); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(surface5, DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, 0, placement, 0); + check_surface_caps(surface1, DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface5); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(surface1, DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER | DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE, placement, 0); + check_surface_caps(surface5, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, 0, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(surface5, surface6); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(surface1, DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP, placement, 0); + check_surface_caps(surface5, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, DDSCAPS_FLIP, placement, 0); + + caps.dwCaps = DDSCAPS_FLIP; + hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == surface5, "got %p, %p.\n", tmp, surface5); + IDirectDrawSurface_Release(tmp); + hr = IDirectDrawSurface_GetAttachedSurface(surface5, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == surface6, "got %p, %p.\n", tmp, surface5); + IDirectDrawSurface_Release(tmp); + hr = IDirectDrawSurface_GetAttachedSurface(surface6, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == surface1, "got %p, %p.\n", tmp, surface5); + IDirectDrawSurface_Release(tmp); + + hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface6); + ok(hr == DDERR_SURFACENOTATTACHED, "got %#lx.\n", hr); + hr = IDirectDrawSurface_DeleteAttachedSurface(surface6, 0, surface1); + ok(hr == DDERR_CANNOTDETACHSURFACE, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)surface5); + ok(ref == 2, "got %ld,\n", ref); + ref = get_refcount((IUnknown *)surface6); + ok(ref == 2, "got %ld,\n", ref); + check_surface_caps(surface1, DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP, placement, 0); + check_surface_caps(surface5, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, DDSCAPS_FLIP, placement, 0); + hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface5); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)surface5); + ok(ref == 1, "got %ld,\n", ref); + ref = get_refcount((IUnknown *)surface6); + ok(ref == 2, "got %ld,\n", ref); + check_surface_caps(surface1, DDSCAPS_VISIBLE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP, placement, 0); + check_surface_caps(surface5, DDSCAPS_BACKBUFFER, placement, 0); + check_surface_caps(surface6, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER, placement, 0); + + hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == surface6, "got %p, %p.\n", tmp, surface6); + IDirectDrawSurface_Release(surface6); + + hr = IDirectDrawSurface_GetAttachedSurface(surface5, &caps, &tmp); + ok(hr == DDERR_NOTFOUND, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_DeleteAttachedSurface(surface5, 0, surface6); + ok(hr == DDERR_SURFACENOTATTACHED, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)surface6); + ok(ref == 2, "got %ld,\n", ref); + + hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface6); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(surface6, 0, placement, 0); + + hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &tmp); + ok(hr == DDERR_NOTFOUND, "got %#lx.\n", hr); + + ref = IDirectDrawSurface_Release(surface1); + ok(!ref, "got %ld\n", ref); + check_surface_caps(surface6, 0, placement, 0); + + ref = IDirectDrawSurface_Release(surface6); + ok(!ref, "got %ld\n", ref); + ref = IDirectDrawSurface_Release(surface5); + ok(!ref, "got %ld\n", ref); IDirectDrawSurface_Release(surface4); IDirectDrawSurface_Release(surface3); IDirectDrawSurface_Release(surface2); - IDirectDrawSurface_Release(surface1); + + /* Test adding backbuffers to complex surface with auto created backbuffers. */ + caps.dwCaps = DDSCAPS_FLIP; + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + surface_desc.dwBackBufferCount = 2; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &backbuffer1); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 2, "got %ld.\n", ref); + + hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface1); + ok(hr == DDERR_SURFACENOTATTACHED, "got %#lx.\n", hr); + hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, backbuffer1); + ok(hr == DDERR_CANNOTDETACHSURFACE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_GetSurfaceDesc(surface1, &surface_desc); + ok(hr == DD_OK, "got %#lx.\n", hr); + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_3DDEVICE; + surface_desc.dwWidth /= 2; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &backbuffer2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + /* size mismatch */ + hr = IDirectDrawSurface_AddAttachedSurface(surface1, backbuffer2); + ok(hr == DDERR_CANNOTATTACHSURFACE, "got %#lx.\n", hr); + IDirectDrawSurface_Release(backbuffer2); + + hr = IDirectDrawSurface_GetSurfaceDesc(surface1, &surface_desc); + ok(hr == DD_OK, "got %#lx.\n", hr); + surface_desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_3DDEVICE; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &backbuffer2, NULL); + ok(hr == DD_OK, "got %#lx.\n", hr); + + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT; + surface_desc.ddsCaps.dwCaps = DDSCAPS_ZBUFFER; + surface_desc.ddpfPixelFormat.dwSize = sizeof(surface_desc.ddpfPixelFormat); + surface_desc.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER; + surface_desc.ddpfPixelFormat.dwZBufferBitDepth = 16; + surface_desc.ddpfPixelFormat.dwZBitMask = 0x0000ffff; + surface_desc.dwWidth = registry_mode.dmPelsWidth; + surface_desc.dwHeight = registry_mode.dmPelsHeight; + hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface2, NULL); + ok(hr == D3D_OK, "Failed to create surface, hr %#lx.\n", hr); + + hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)surface1); + ok(ref == 1, "got %ld.\n", ref); + caps.dwCaps = DDSCAPS_ZBUFFER; + hr = IDirectDrawSurface_GetAttachedSurface(surface1, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == surface2, "got %p, %p.\n", tmp, surface2); + IDirectDrawSurface_Release(tmp); + + caps.dwCaps = DDSCAPS_FLIP; + hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &surface3); + ok(hr == DD_OK, "got %#lx.\n", hr); + + caps.dwCaps = DDSCAPS_COMPLEX; + hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == surface3, "got %p, %p.\n", tmp, surface3); + IDirectDrawSurface_Release(tmp); + caps.dwCaps = DDSCAPS_ZBUFFER; + hr = IDirectDrawSurface_GetAttachedSurface(backbuffer1, &caps, &tmp); + ok(hr == DDERR_NOTFOUND, "got %#lx.\n", hr); + ref = IDirectDrawSurface_Release(surface3); + ok(ref == 1, "got %ld.\n", ref); + + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 2, "got %ld.\n", ref); + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 1, "got %ld.\n", ref); + hr = IDirectDrawSurface_AddAttachedSurface(surface1, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + ref = get_refcount((IUnknown *)backbuffer2); + ok(ref == 2, "got %ld.\n", ref); + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 2, "got %ld.\n", ref); + check_surface_caps(surface1, DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER + | DDSCAPS_FLIP, placement, 3); + caps.dwCaps = DDSCAPS_FLIP; + hr = IDirectDrawSurface_GetAttachedSurface(backbuffer2, &caps, &tmp); + ok(hr == DD_OK, "got %#lx.\n", hr); + ok(tmp == backbuffer1, "got %p, %p.\n", backbuffer1, tmp); + ref = IDirectDrawSurface_Release(tmp); + ok(ref == 2, "got %ld.\n", ref); + + caps.dwCaps = DDSCAPS_PRIMARYSURFACE; + hr = IDirectDrawSurface_GetAttachedSurface(backbuffer2, &caps, &tmp); + ok(hr == DDERR_NOTFOUND, "got %#lx.\n", hr); + caps.dwCaps = DDSCAPS_FLIP; + + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer2, 0, backbuffer1); + ok(hr == DDERR_CANNOTDETACHSURFACE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer1, 0, backbuffer2); + ok(hr == DDERR_SURFACENOTATTACHED, "got %#lx.\n", hr); + + ref = get_refcount((IUnknown *)backbuffer1); + ok(ref == 2, "got %ld.\n", ref); + hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + /* Looks like here is a ddraw bug here, when deleting a surface the next one in chain gets an extra reference. */ + ref = get_refcount((IUnknown *)backbuffer1); + todo_wine ok(ref == 3, "got %ld.\n", ref); + check_surface_caps(surface1, DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER + | DDSCAPS_FLIP, placement, 2); + check_surface_caps(backbuffer1, DDSCAPS_FLIP | DDSCAPS_BACKBUFFER | DDSCAPS_COMPLEX, placement, 0); + check_surface_caps(backbuffer2, DDSCAPS_3DDEVICE, placement, 0); + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer1, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(backbuffer1, DDSCAPS_BACKBUFFER | DDSCAPS_FLIP | DDSCAPS_COMPLEX, placement, 0); + check_surface_caps(backbuffer2, DDSCAPS_3DDEVICE | DDSCAPS_FLIP, placement, 0); + check_surface_caps(surface1, DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER + | DDSCAPS_FLIP, placement, 3); + + hr = IDirectDrawSurface_AddAttachedSurface(surface1, backbuffer2); + ok(hr == DDERR_CANNOTATTACHSURFACE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer2, surface1); + ok(hr == DDERR_CANNOTATTACHSURFACE , "got %#lx.\n", hr); + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer2, backbuffer1); + ok(hr == DDERR_CANNOTATTACHSURFACE, "got %#lx.\n", hr); + + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer1, 0, backbuffer2); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(surface1, DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER + | DDSCAPS_FLIP, placement, 2); + check_surface_caps(backbuffer1, DDSCAPS_BACKBUFFER | DDSCAPS_FLIP | DDSCAPS_COMPLEX, placement, 0); + check_surface_caps(backbuffer2, DDSCAPS_3DDEVICE, placement, 0); + + ref = IDirectDrawSurface_Release(backbuffer1); + todo_wine ok(ref == 2, "got %ld.\n", ref); + if (ref == 2) + ref = IDirectDrawSurface_Release(backbuffer1); + ref = IDirectDrawSurface_Release(surface1); + ok(!ref, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(backbuffer1); + ok(!ref, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(backbuffer2); + ok(!ref, "got %ld.\n", ref); + ref = IDirectDrawSurface_Release(surface2); + ok(!ref, "got %ld.\n", ref); /* Test depth surfaces of different sizes. */ memset(&surface_desc, 0, sizeof(surface_desc)); @@ -6087,6 +6571,10 @@ static void test_surface_attachment(void) ok(SUCCEEDED(hr), "Failed to attach surface, hr %#lx.\n", hr); refcount = get_refcount((IUnknown *)surface2); ok(refcount == 2, "Got unexpected refcount %lu.\n", refcount); + caps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + hr = IDirectDrawSurface_GetAttachedSurface(surface2, &caps, &tmp); + ok(hr == DDERR_NOTFOUND, "got %#lx.\n", hr); + hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); ok(hr == DDERR_SURFACEALREADYATTACHED, "Got unexpected hr %#lx.\n", hr); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10992