[PATCH v4 0/4] MR10992: ddraw: Allow attaching flip chain surfaces surfaces (for v1 surfaces).
-- v4: ddraw: Force render target bind flags on v1 swapchain candidate surfaces. ddraw/tests: Add tests for attaching and detaching backbuffers on ddraw1. ddraw: Allow attaching flip chain surfaces. https://gitlab.winehq.org/wine/wine/-/merge_requests/10992
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/ddraw_private.h | 5 +---- dlls/ddraw/surface.c | 13 +++++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index f2c99a30d57..01d3b84b208 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -199,10 +199,7 @@ struct ddraw_surface */ #define MAX_COMPLEX_ATTACHED 6 struct ddraw_surface *complex_array[MAX_COMPLEX_ATTACHED]; - /* You can't traverse the tree upwards. Only a flag for Surface::Release because it's needed there, - * but no pointer to prevent temptations to traverse it in the wrong direction. - */ - unsigned int is_root : 1; + unsigned int is_implicit : 1; unsigned int is_lost : 1; unsigned int sysmem_fallback : 1; diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 829fbf699ff..76d7c922eb0 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -596,7 +596,7 @@ static void ddraw_surface_cleanup(struct ddraw_surface *surface) surf = surface->complex_array[i]; surface->complex_array[i] = NULL; - if (!surf->is_root) + if (surf->is_implicit) { struct ddraw_texture *texture = wined3d_texture_get_parent(surf->wined3d_texture); struct wined3d_device *wined3d_device = texture->wined3d_device; @@ -646,7 +646,7 @@ static ULONG ddraw_surface_release_iface(struct ddraw_surface *This) /* Complex attached surfaces are destroyed implicitly when the root is released */ wined3d_mutex_lock(); - if (!This->is_root) + if (This->is_implicit) { WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This); wined3d_mutex_unlock(); @@ -2659,9 +2659,9 @@ static HRESULT WINAPI ddraw_surface7_GetPriority(IDirectDrawSurface7 *iface, DWO WARN("Called on offscreenplain surface, returning DDERR_INVALIDOBJECT.\n"); hr = DDERR_INVALIDOBJECT; } - else if (!(surface->surface_desc.ddsCaps.dwCaps2 & managed) || !surface->is_root) + else if (!(surface->surface_desc.ddsCaps.dwCaps2 & managed) || surface->is_implicit) { - WARN("Called on non-managed texture or non-root surface, returning DDERR_INVALIDPARAMS.\n"); + WARN("Called on non-managed texture implicit surface, returning DDERR_INVALIDPARAMS.\n"); hr = DDERR_INVALIDPARAMS; } else @@ -5173,7 +5173,7 @@ static HRESULT ddraw_surface_set_color_key(struct ddraw_surface *surface, DWORD } } - if (surface->is_root) + if (!surface->is_implicit) hr = ddraw_surface_set_wined3d_textures_colour_key(surface, flags, color_key ? (struct wined3d_color_key *)&fixed_color_key : NULL); @@ -6117,6 +6117,7 @@ static void ddraw_surface_init(struct ddraw_surface *surface, struct ddraw *ddra surface->iface_count = 1; surface->version = version; surface->ddraw = ddraw; + surface->is_implicit = 1; if (version == 7) { @@ -6979,7 +6980,7 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_ } root = texture->root; - root->is_root = TRUE; + root->is_implicit = 0; if (desc->dwFlags & DDSD_BACKBUFFERCOUNT) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10992
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/ddraw_private.h | 2 + dlls/ddraw/surface.c | 156 ++++++++++++++++++++++++++++++++++-- dlls/ddraw/tests/d3d.c | 6 +- dlls/ddraw/tests/dsurface.c | 18 ++--- dlls/ddraw/tests/visual.c | 4 +- 5 files changed, 164 insertions(+), 22 deletions(-) diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h index 01d3b84b208..7baf43a3f24 100644 --- a/dlls/ddraw/ddraw_private.h +++ b/dlls/ddraw/ddraw_private.h @@ -191,6 +191,7 @@ struct ddraw_surface struct ddraw_surface *next_attached; struct ddraw_surface *first_attached; IUnknown *attached_iface; + DWORD attach_saved_caps; /* Complex surfaces are organized in a tree, although the tree is degenerated to a list in most cases. * In mipmap and primary surfaces each level has only one attachment, which is the next surface level. @@ -200,6 +201,7 @@ struct ddraw_surface #define MAX_COMPLEX_ATTACHED 6 struct ddraw_surface *complex_array[MAX_COMPLEX_ATTACHED]; unsigned int is_implicit : 1; + unsigned int is_flip_chain_start : 1; unsigned int is_lost : 1; unsigned int sysmem_fallback : 1; diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 76d7c922eb0..b3cc5c684e5 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -28,11 +28,19 @@ WINE_DECLARE_DEBUG_CHANNEL(fps); static struct ddraw_surface *unsafe_impl_from_IDirectDrawSurface2(IDirectDrawSurface2 *iface); static struct ddraw_surface *unsafe_impl_from_IDirectDrawSurface3(IDirectDrawSurface3 *iface); +static HRESULT ddraw_surface_delete_attached_surface(struct ddraw_surface *surface, + struct ddraw_surface *attachment, IUnknown *detach_iface); static const struct wined3d_parent_ops ddraw_surface_wined3d_parent_ops; static const struct wined3d_parent_ops ddraw_texture_wined3d_parent_ops; static const struct wined3d_parent_ops ddraw_view_wined3d_parent_ops; +static BOOL surface_attachable_for_flip(struct ddraw_surface *surface) +{ + return surface->version == 1 && !surface->is_implicit + && !(surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER | DDSCAPS_TEXTURE | DDSCAPS_OVERLAY)); +} + static inline struct ddraw_surface *impl_from_IDirectDrawGammaControl(IDirectDrawGammaControl *iface) { return CONTAINING_RECORD(iface, struct ddraw_surface, IDirectDrawGammaControl_iface); @@ -595,6 +603,18 @@ static void ddraw_surface_cleanup(struct ddraw_surface *surface) break; surf = surface->complex_array[i]; + while (surf && !surf->is_implicit && !surf->is_flip_chain_start) + { + if (FAILED(ddraw_surface_delete_attached_surface(surface, surf, surf->attached_iface))) + { + ERR("ddraw_surface_delete_attached_surface failed.\n"); + break; + } + surf = surface->complex_array[i]; + } + if (!surf) + continue; + surface->complex_array[i] = NULL; if (surf->is_implicit) { @@ -1401,7 +1421,8 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface1_Flip(IDirectDrawSurface * TRACE("iface %p, src %p, flags %#lx.\n", iface, src, flags); - if (src == iface || !(dst_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY))) + if (src == iface || !(dst_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY)) + || !(dst_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_FLIP)) return DDERR_NOTFLIPPABLE; if (ddraw_surface_is_lost(dst_impl)) @@ -1960,6 +1981,22 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface2_Blt(IDirectDrawSurface2 * src ? &src->IDirectDrawSurface_iface : NULL, src_rect, flags, fx); } +static void surface_update_backbuffer_count(struct ddraw_surface *surface, int inc) +{ + struct ddraw_surface *s; + + s = surface; + do + { + if (!s->is_implicit && s->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT) + { + s->surface_desc.dwBackBufferCount += inc; + break; + } + s = s->complex_array[0]; + } while (s != surface); +} + /***************************************************************************** * IDirectDrawSurface7::AddAttachedSurface * @@ -1981,15 +2018,15 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH ddraw_surface2_Blt(IDirectDrawSurface2 * * the surface that the app requested, not the complex root. See * GetAttachedSurface for a description how surfaces are found. * + * Attachments forming flip chain can only be explicitly attached on ddraw v1. That + * is implemented by inserting those into complex_array chain so that appear + * the same way as auto created back buffers in the attachment structure. + * * This is how the current implementation works, and it was coded by looking * at the needs of the applications. * - * So far only Z-Buffer attachments are tested, and they are activated in + * So far only Z-Buffer and flip chain attachments are tested, and they are activated in * WineD3D. Mipmaps could be tricky to activate in WineD3D. - * Back buffers should work in 2D mode, but they are not tested(They can be - * attached in older iface versions). Rendering to the front buffer and - * switching between that and double buffering is not yet implemented in - * WineD3D, so for 3D it might have unexpected results. * * ddraw_surface_attach_surface is the real thing, * ddraw_surface7_AddAttachedSurface is a wrapper around it that @@ -2015,6 +2052,55 @@ static HRESULT ddraw_surface_attach_surface(struct ddraw_surface *This, struct d wined3d_mutex_lock(); + if (surface_attachable_for_flip(Surf)) + { + if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE + && !(This->ddraw->cooperative_level & DDERR_NOEXCLUSIVEMODE)) + { + wined3d_mutex_unlock(); + return DDERR_NOEXCLUSIVEMODE; + } + if (This->complex_array[0] == Surf) + { + wined3d_mutex_unlock(); + return DDERR_SURFACEALREADYATTACHED; + } + if (Surf->complex_array[0] || Surf->surface_desc.dwWidth != This->surface_desc.dwWidth + || Surf->surface_desc.dwHeight != This->surface_desc.dwHeight + || wined3dformat_from_ddrawformat(&Surf->surface_desc.ddpfPixelFormat) + != wined3dformat_from_ddrawformat(&This->surface_desc.ddpfPixelFormat)) + { + wined3d_mutex_unlock(); + return DDERR_CANNOTATTACHSURFACE; + } + Surf->attach_saved_caps = Surf->surface_desc.ddsCaps.dwCaps & ~DDSCAPS_FRONTBUFFER; + Surf->is_flip_chain_start = 0; + Surf->surface_desc.ddsCaps.dwCaps |= DDSCAPS_FLIP; + if (!This->complex_array[0]) + { + This->is_flip_chain_start = 1; + This->complex_array[0] = Surf; + Surf->complex_array[0] = This; + This->attach_saved_caps = This->surface_desc.ddsCaps.dwCaps & ~DDSCAPS_FRONTBUFFER; + This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_FLIP; + if (!(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))) + This->surface_desc.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER; + + if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_BACKBUFFER) + Surf->surface_desc.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER; + else + Surf->surface_desc.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; + } + else + { + Surf->complex_array[0] = This->complex_array[0]; + This->complex_array[0] = Surf; + } + surface_update_backbuffer_count(This, 1); + wined3d_mutex_unlock(); + return DD_OK; + } + /* Check if the surface is already attached somewhere */ if (Surf->next_attached || Surf->first_attached != Surf) { @@ -2095,8 +2181,11 @@ static HRESULT WINAPI ddraw_surface4_AddAttachedSurface(IDirectDrawSurface4 *ifa return DDERR_CANNOTATTACHSURFACE; } } - else if (!(surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE)) - || !(attachment_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER))) + else if ((!(surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE)) + || !(attachment_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)) + && !(surface->version == 1 + && !(surface->surface_desc.ddsCaps.dwCaps & ((DDSCAPS_ZBUFFER | DDSCAPS_TEXTURE | DDSCAPS_OVERLAY))) + && surface_attachable_for_flip(attachment_impl))) { WARN("Invalid attachment combination.\n"); return DDERR_CANNOTATTACHSURFACE; @@ -2188,7 +2277,57 @@ static HRESULT ddraw_surface_delete_attached_surface(struct ddraw_surface *surfa TRACE("surface %p, attachment %p, detach_iface %p.\n", surface, attachment, detach_iface); + if (!attachment) + return DDERR_CANNOTDETACHSURFACE; + wined3d_mutex_lock(); + + if (surface_attachable_for_flip(attachment)) + { + struct ddraw_surface *next; + if (surface->version != 1 || surface->complex_array[0] != attachment) + { + WARN("backbuffer %p is not attached to %p.\n", attachment, surface); + wined3d_mutex_unlock(); + return DDERR_SURFACENOTATTACHED; + } + if (attachment->is_implicit || attachment->is_flip_chain_start) + { + wined3d_mutex_unlock(); + WARN("trying to detach non-root attachment %p.\n", attachment); + return DDERR_CANNOTDETACHSURFACE; + } + assert(attachment->complex_array[0]); + surface_update_backbuffer_count(surface, -1); + next = surface->complex_array[0] = attachment->complex_array[0]; + if (next == surface) + { + surface->is_flip_chain_start = 0; + surface->complex_array[0] = NULL; + surface->surface_desc.ddsCaps.dwCaps = surface->attach_saved_caps; + } + else + { + next->surface_desc.ddsCaps.dwCaps &= ~(DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER); + if (attachment->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) + { + surface->surface_desc.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; + next->surface_desc.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER; + } + else + { + next->surface_desc.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER; + } + } + attachment->surface_desc.ddsCaps.dwCaps = attachment->attach_saved_caps; + attachment->complex_array[0] = NULL; + IUnknown_Release(detach_iface); + attachment->attached_iface = NULL; + + wined3d_mutex_unlock(); + return DD_OK; + } + if (!attachment || (attachment->first_attached != surface) || (attachment == surface) ) { wined3d_mutex_unlock(); @@ -6987,6 +7126,7 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_ unsigned int count = desc->dwBackBufferCount; struct ddraw_surface *last = root; + root->is_flip_chain_start = 1; attach = &last->complex_array[0]; for (i = 0; i < count; ++i) { diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c index ec536a83729..d9e795118f7 100644 --- a/dlls/ddraw/tests/d3d.c +++ b/dlls/ddraw/tests/d3d.c @@ -1605,7 +1605,7 @@ static void BackBuffer3DAttachmentTest(void) ok(hr == DD_OK, "Got hr %#lx.\n", hr); hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); if(SUCCEEDED(hr)) { /* Try the reverse without detaching first */ @@ -1615,7 +1615,7 @@ static void BackBuffer3DAttachmentTest(void) ok(hr == DD_OK, "Got hr %#lx.\n", hr); } hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); if(SUCCEEDED(hr)) { /* Try to detach reversed */ @@ -1626,7 +1626,7 @@ static void BackBuffer3DAttachmentTest(void) ok(hr == DD_OK, "Got hr %#lx.\n", hr); } hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); if(SUCCEEDED(hr)) { hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3); diff --git a/dlls/ddraw/tests/dsurface.c b/dlls/ddraw/tests/dsurface.c index e65160034f6..ad6eddb5ad2 100644 --- a/dlls/ddraw/tests/dsurface.c +++ b/dlls/ddraw/tests/dsurface.c @@ -1720,15 +1720,15 @@ static void BackBufferAttachmentFlipTest(void) ok(hr==DD_OK, "Got hr %#lx.\n", hr); hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Attaching a back buffer to a front buffer returned %#lx\n", hr); if(SUCCEEDED(hr)) { /* Try flipping the surfaces */ hr = IDirectDrawSurface_Flip(surface1, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DD_OK, "Got hr %#lx.\n", hr); + ok(hr == DD_OK, "Got hr %#lx.\n", hr); hr = IDirectDrawSurface_Flip(surface2, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); + ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); /* Try the reverse without detaching first */ hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); @@ -1737,15 +1737,15 @@ static void BackBufferAttachmentFlipTest(void) ok(hr == DD_OK, "Got hr %#lx.\n", hr); } hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Attaching a front buffer to a back buffer returned %#lx\n", hr); if(SUCCEEDED(hr)) { /* Try flipping the surfaces */ hr = IDirectDrawSurface_Flip(surface1, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DD_OK, "Got hr %#lx.\n", hr); + ok(hr == DD_OK, "Got hr %#lx.\n", hr); hr = IDirectDrawSurface_Flip(surface2, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); + ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); /* Try to detach reversed */ hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2); @@ -1755,15 +1755,15 @@ static void BackBufferAttachmentFlipTest(void) ok(hr == DD_OK, "Got hr %#lx.\n", hr); } hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Attaching a back buffer to another back buffer returned %#lx\n", hr); if(SUCCEEDED(hr)) { /* Try flipping the surfaces */ hr = IDirectDrawSurface_Flip(surface3, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DD_OK, "Got hr %#lx.\n", hr); + ok(hr == DD_OK, "Got hr %#lx.\n", hr); hr = IDirectDrawSurface_Flip(surface2, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); + ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); hr = IDirectDrawSurface_Flip(surface1, NULL, DDFLIP_WAIT); ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); diff --git a/dlls/ddraw/tests/visual.c b/dlls/ddraw/tests/visual.c index f5c6e79f832..347e0d21fb4 100644 --- a/dlls/ddraw/tests/visual.c +++ b/dlls/ddraw/tests/visual.c @@ -1540,7 +1540,7 @@ static void DX1_BackBufferFlipTest(void) if(FAILED(hr)) goto out; hr = IDirectDrawSurface_AddAttachedSurface(Primary, Backbuffer); - todo_wine ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); + ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); if (FAILED(hr)) goto out; attached = TRUE; @@ -1567,7 +1567,7 @@ static void DX1_BackBufferFlipTest(void) GetRValue(color), GetGValue(color), GetBValue(color)); hr = IDirectDrawSurface_Flip(Primary, NULL, DDFLIP_WAIT); - todo_wine ok(hr == DD_OK, "Got hr %#lx.\n", hr); + ok(hr == DD_OK, "Got hr %#lx.\n", hr); if (hr == DD_OK) { -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10992
From: Paul Gofman <pgofman@codeweavers.com> And remove smaller duplicating variants from elsewhere. --- dlls/ddraw/tests/d3d.c | 96 ------ dlls/ddraw/tests/ddraw1.c | 575 +++++++++++++++++++++++++++++++++--- dlls/ddraw/tests/dsurface.c | 119 -------- dlls/ddraw/tests/visual.c | 140 --------- 4 files changed, 541 insertions(+), 389 deletions(-) diff --git a/dlls/ddraw/tests/d3d.c b/dlls/ddraw/tests/d3d.c index d9e795118f7..0403d8da6dd 100644 --- a/dlls/ddraw/tests/d3d.c +++ b/dlls/ddraw/tests/d3d.c @@ -1554,101 +1554,6 @@ static void BackBuffer3DCreateSurfaceTest(void) IDirectDraw7_Release(dd7); } -static void BackBuffer3DAttachmentTest(void) -{ - HRESULT hr; - IDirectDrawSurface *surface1, *surface2, *surface3, *surface4; - DDSURFACEDESC ddsd; - HWND window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW, - 100, 100, 160, 160, NULL, NULL, NULL, NULL); - - hr = IDirectDraw_SetCooperativeLevel(DirectDraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - /* Perform attachment tests on a back-buffer */ - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE; - ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN); - ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN); - hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface2, NULL); - ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr); - - if (surface2 != NULL) - { - /* Try a single primary and a two back buffers */ - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface1, NULL); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER | DDSCAPS_3DDEVICE; - ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN); - ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN); - hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface3, NULL); - ok(hr == DD_OK, "Got hr %#lx.\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_BACKBUFFER | DDSCAPS_3DDEVICE; - ddsd.dwWidth = 128; - ddsd.dwHeight = 128; - hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &surface4, NULL); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); - if(SUCCEEDED(hr)) - { - /* Try the reverse without detaching first */ - hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); - ok(hr == DDERR_SURFACEALREADYATTACHED, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); - if(SUCCEEDED(hr)) - { - /* Try to detach reversed */ - hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2); - ok(hr == DDERR_CANNOTDETACHSURFACE, "Got hr %#lx.\n", hr); - /* Now the proper detach */ - hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); - if(SUCCEEDED(hr)) - { - hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4); - ok(hr == DDERR_CANNOTATTACHSURFACE, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1); - ok(hr == DDERR_CANNOTATTACHSURFACE, "Got hr %#lx.\n", hr); - - IDirectDrawSurface_Release(surface4); - IDirectDrawSurface_Release(surface3); - IDirectDrawSurface_Release(surface2); - IDirectDrawSurface_Release(surface1); - } - - hr =IDirectDraw_SetCooperativeLevel(DirectDraw1, NULL, DDSCL_NORMAL); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - DestroyWindow(window); -} - static void dump_format(const DDPIXELFORMAT *fmt) { trace("dwFlags %08lx, FourCC %08lx, dwZBufferBitDepth %lu, stencil %08lx\n", fmt->dwFlags, fmt->dwFourCC, @@ -2101,7 +2006,6 @@ START_TEST(d3d) TextureLoadTest(); ViewportTest(); BackBuffer3DCreateSurfaceTest(); - BackBuffer3DAttachmentTest(); test_get_caps1(); D3D1_releaseObjects(); } diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 007daf29407..3e5457e464b 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,241 @@ 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); + + hr = IDirectDrawSurface_AddAttachedSurface(backbuffer1, frontbuffer); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(frontbuffer, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE | DDSCAPS_FRONTBUFFER | DDSCAPS_FLIP, placement, 0); + check_surface_caps(backbuffer1, DDSCAPS_3DDEVICE | DDSCAPS_BACKBUFFER | DDSCAPS_FLIP, placement, 0); + hr = IDirectDrawSurface_Flip(frontbuffer, NULL, DDFLIP_WAIT); + ok(hr == DD_OK, "got %#lx.\n", hr); + 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); + + hr = IDirectDrawSurface_Flip(backbuffer1, NULL, DDFLIP_WAIT); + ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); + + hr = IDirectDrawSurface_DeleteAttachedSurface(frontbuffer, 0, backbuffer1); + ok(hr == DDERR_CANNOTDETACHSURFACE, "got %#lx.\n", hr); + hr = IDirectDrawSurface_DeleteAttachedSurface(backbuffer1, 0, frontbuffer); + ok(hr == DD_OK, "got %#lx.\n", hr); + check_surface_caps(frontbuffer, DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE, placement, 0); + check_surface_caps(backbuffer1, DDSCAPS_3DDEVICE | DDSCAPS_BACKBUFFER, 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, 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 == 0x00ff0000, "got %#x.\n", color); + color = get_surface_color(backbuffer1, 1, 1); + ok(color == 0x000ff00, "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 == 0x0000ff00, "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 == 0x00ff0000, "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 +6077,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 +6105,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 +6221,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 +6269,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 +6590,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); diff --git a/dlls/ddraw/tests/dsurface.c b/dlls/ddraw/tests/dsurface.c index ad6eddb5ad2..422386857fc 100644 --- a/dlls/ddraw/tests/dsurface.c +++ b/dlls/ddraw/tests/dsurface.c @@ -1669,124 +1669,6 @@ static void BackBufferCreateSurfaceTest(void) IDirectDraw7_Release(dd7); } -static void BackBufferAttachmentFlipTest(void) -{ - HRESULT hr; - IDirectDrawSurface *surface1, *surface2, *surface3, *surface4; - DDSURFACEDESC ddsd; - HWND window = CreateWindowA("static", "ddraw_test", WS_OVERLAPPEDWINDOW, - 100, 100, 160, 160, NULL, NULL, NULL, NULL); - - hr = IDirectDraw_SetCooperativeLevel(lpDD, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - /* Perform attachment tests on a back-buffer */ - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; - ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN); - ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN); - hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface2, NULL); - ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr); - - if (surface2 != NULL) - { - /* Try a single primary and a two back buffers */ - 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, "Got hr %#lx.\n", hr); - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; - ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; - ddsd.dwWidth = GetSystemMetrics(SM_CXSCREEN); - ddsd.dwHeight = GetSystemMetrics(SM_CYSCREEN); - hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface3, NULL); - ok(hr==DD_OK, "Got hr %#lx.\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_BACKBUFFER; - ddsd.dwWidth = 128; - ddsd.dwHeight = 128; - hr = IDirectDraw_CreateSurface(lpDD, &ddsd, &surface4, NULL); - ok(hr==DD_OK, "Got hr %#lx.\n", hr); - - hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface2); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), - "Attaching a back buffer to a front buffer returned %#lx\n", hr); - if(SUCCEEDED(hr)) - { - /* Try flipping the surfaces */ - hr = IDirectDrawSurface_Flip(surface1, NULL, DDFLIP_WAIT); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_Flip(surface2, NULL, DDFLIP_WAIT); - ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); - - /* Try the reverse without detaching first */ - hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); - ok(hr == DDERR_SURFACEALREADYATTACHED, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface1); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), - "Attaching a front buffer to a back buffer returned %#lx\n", hr); - if(SUCCEEDED(hr)) - { - /* Try flipping the surfaces */ - hr = IDirectDrawSurface_Flip(surface1, NULL, DDFLIP_WAIT); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_Flip(surface2, NULL, DDFLIP_WAIT); - ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); - - /* Try to detach reversed */ - hr = IDirectDrawSurface_DeleteAttachedSurface(surface1, 0, surface2); - ok(hr == DDERR_CANNOTDETACHSURFACE, "Got hr %#lx.\n", hr); - /* Now the proper detach */ - hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface1); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - hr = IDirectDrawSurface_AddAttachedSurface(surface2, surface3); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), - "Attaching a back buffer to another back buffer returned %#lx\n", hr); - if(SUCCEEDED(hr)) - { - /* Try flipping the surfaces */ - hr = IDirectDrawSurface_Flip(surface3, NULL, DDFLIP_WAIT); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_Flip(surface2, NULL, DDFLIP_WAIT); - ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_Flip(surface1, NULL, DDFLIP_WAIT); - ok(hr == DDERR_NOTFLIPPABLE, "Got hr %#lx.\n", hr); - - hr = IDirectDrawSurface_DeleteAttachedSurface(surface2, 0, surface3); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - hr = IDirectDrawSurface_AddAttachedSurface(surface1, surface4); - ok(hr == DDERR_CANNOTATTACHSURFACE, "Got hr %#lx.\n", hr); - hr = IDirectDrawSurface_AddAttachedSurface(surface4, surface1); - ok(hr == DDERR_CANNOTATTACHSURFACE, "Got hr %#lx.\n", hr); - - IDirectDrawSurface_Release(surface4); - IDirectDrawSurface_Release(surface3); - IDirectDrawSurface_Release(surface2); - IDirectDrawSurface_Release(surface1); - } - - hr =IDirectDraw_SetCooperativeLevel(lpDD, NULL, DDSCL_NORMAL); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - DestroyWindow(window); -} - static void CreateSurfaceBadCapsSizeTest(void) { DDSURFACEDESC ddsd_ok; @@ -2506,7 +2388,6 @@ START_TEST(dsurface) PaletteTest(); SurfaceCapsTest(); BackBufferCreateSurfaceTest(); - BackBufferAttachmentFlipTest(); CreateSurfaceBadCapsSizeTest(); no_ddsd_caps_test(); zbufferbitdepth_test(); diff --git a/dlls/ddraw/tests/visual.c b/dlls/ddraw/tests/visual.c index 347e0d21fb4..08cac331d18 100644 --- a/dlls/ddraw/tests/visual.c +++ b/dlls/ddraw/tests/visual.c @@ -1154,25 +1154,6 @@ static void D3D3_ViewportClearTest(void) if(window) DestroyWindow(window); } -static COLORREF getPixelColor_GDI(IDirectDrawSurface *Surface, UINT x, UINT y) -{ - COLORREF clr = CLR_INVALID; - HDC hdc; - HRESULT hr; - - hr = IDirectDrawSurface_GetDC(Surface, &hdc); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - if (SUCCEEDED(hr)) { - clr = GetPixel(hdc, x, y); - - hr = IDirectDrawSurface_ReleaseDC(Surface, hdc); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - } - - return clr; -} - static void cubemap_test(IDirect3DDevice7 *device) { IDirect3D7 *d3d; @@ -1476,126 +1457,6 @@ static void depth_clamp_test(IDirect3DDevice7 *device) ok(SUCCEEDED(hr), "Got hr %#lx.\n", hr); } -static void DX1_BackBufferFlipTest(void) -{ - HRESULT hr; - IDirectDraw *DirectDraw1 = NULL; - IDirectDrawSurface *Primary = NULL; - IDirectDrawSurface *Backbuffer = NULL; - WNDCLASSA wc = {0}; - DDSURFACEDESC ddsd; - DDBLTFX ddbltfx; - COLORREF color; - const DWORD white = 0xffffff; - const DWORD red = 0xff0000; - BOOL attached = FALSE; - - wc.lpfnWndProc = DefWindowProcA; - wc.lpszClassName = "DX1_BackBufferFlipTest_wc"; - RegisterClassA(&wc); - window = CreateWindowA("DX1_BackBufferFlipTest_wc", "DX1_BackBufferFlipTest", - WS_MAXIMIZE | WS_VISIBLE | WS_CAPTION, 0, 0, 640, 480, 0, 0, 0, 0); - - hr = DirectDrawCreate( NULL, &DirectDraw1, NULL ); - ok(hr == DD_OK || hr == DDERR_NODIRECTDRAWSUPPORT, "Got hr %#lx.\n", hr); - if(FAILED(hr)) goto out; - - hr = IDirectDraw_SetCooperativeLevel(DirectDraw1, window, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - if(FAILED(hr)) goto out; - - hr = IDirectDraw_SetDisplayMode(DirectDraw1, 640, 480, 32); - if(FAILED(hr)) { - /* 24 bit is fine too */ - hr = IDirectDraw_SetDisplayMode(DirectDraw1, 640, 480, 24); - } - ok(hr == DD_OK || hr == DDERR_UNSUPPORTED, "Got hr %#lx.\n", hr); - if (FAILED(hr)) { - goto out; - } - - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - - hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &Primary, NULL); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - memset(&ddsd, 0, sizeof(DDSURFACEDESC)); - ddsd.dwSize = sizeof(DDSURFACEDESC); - ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; - ddsd.dwWidth = 640; - ddsd.dwHeight = 480; - ddsd.ddpfPixelFormat.dwSize = sizeof(ddsd.ddpfPixelFormat); - ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB; - ddsd.ddpfPixelFormat.dwRGBBitCount = 32; - ddsd.ddpfPixelFormat.dwRBitMask = 0x00ff0000; - ddsd.ddpfPixelFormat.dwGBitMask = 0x0000ff00; - ddsd.ddpfPixelFormat.dwBBitMask = 0x000000ff; - - hr = IDirectDraw_CreateSurface(DirectDraw1, &ddsd, &Backbuffer, NULL); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - if(FAILED(hr)) goto out; - - hr = IDirectDrawSurface_AddAttachedSurface(Primary, Backbuffer); - ok(hr == DD_OK || broken(hr == DDERR_CANNOTATTACHSURFACE), "Got hr %#lx.\n", hr); - if (FAILED(hr)) goto out; - - attached = TRUE; - - memset(&ddbltfx, 0, sizeof(ddbltfx)); - ddbltfx.dwSize = sizeof(ddbltfx); - ddbltfx.dwFillColor = red; - hr = IDirectDrawSurface_Blt(Backbuffer, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - ddbltfx.dwFillColor = white; - hr = IDirectDrawSurface_Blt(Primary, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - /* Check it out */ - color = getPixelColor_GDI(Primary, 5, 5); - ok(GetRValue(color) == 0xFF && GetGValue(color) == 0xFF && GetBValue(color) == 0xFF, - "got R %02X G %02X B %02X, expected R FF G FF B FF\n", - GetRValue(color), GetGValue(color), GetBValue(color)); - - color = getPixelColor_GDI(Backbuffer, 5, 5); - ok(GetRValue(color) == 0xFF && GetGValue(color) == 0 && GetBValue(color) == 0, - "got R %02X G %02X B %02X, expected R FF G 00 B 00\n", - GetRValue(color), GetGValue(color), GetBValue(color)); - - hr = IDirectDrawSurface_Flip(Primary, NULL, DDFLIP_WAIT); - ok(hr == DD_OK, "Got hr %#lx.\n", hr); - - if (hr == DD_OK) - { - color = getPixelColor_GDI(Primary, 5, 5); - ok(GetRValue(color) == 0xFF && GetGValue(color) == 0 && GetBValue(color) == 0, - "got R %02X G %02X B %02X, expected R FF G 00 B 00\n", - GetRValue(color), GetGValue(color), GetBValue(color)); - - color = getPixelColor_GDI(Backbuffer, 5, 5); - ok((GetRValue(color) == 0xFF && GetGValue(color) == 0xFF && GetBValue(color) == 0xFF) || - broken(GetRValue(color) == 0xFF && GetGValue(color) == 0 && GetBValue(color) == 0), /* broken driver */ - "got R %02X G %02X B %02X, expected R FF G FF B FF\n", - GetRValue(color), GetGValue(color), GetBValue(color)); - } - - out: - - if (Backbuffer) - { - if (attached) - IDirectDrawSurface_DeleteAttachedSurface(Primary, 0, Backbuffer); - IDirectDrawSurface_Release(Backbuffer); - } - if (Primary) IDirectDrawSurface_Release(Primary); - if (DirectDraw1) IDirectDraw_Release(DirectDraw1); - if (window) DestroyWindow(window); -} - START_TEST(visual) { unsigned int color; @@ -1647,7 +1508,6 @@ START_TEST(visual) releaseObjects(); /* release DX7 interfaces to test D3D1 */ D3D3_ViewportClearTest(); - DX1_BackBufferFlipTest(); return ; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10992
From: Paul Gofman <pgofman@codeweavers.com> --- dlls/ddraw/surface.c | 17 +++++++++++------ dlls/ddraw/tests/ddraw1.c | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index b3cc5c684e5..1355b527933 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -6347,10 +6347,15 @@ static HRESULT ddraw_surface_reserve_memory(struct wined3d_texture *wined3d_text return hr; } +static BOOL force_3ddevice(struct ddraw *ddraw, const DDSURFACEDESC2 *desc, unsigned int surface_version) +{ + return surface_version == 1 && desc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE && !(ddraw->flags & DDRAW_NO3D); +} + static void wined3d_resource_desc_from_ddraw(struct ddraw *ddraw, - struct wined3d_resource_desc *wined3d_desc, const DDSURFACEDESC2 *desc) + struct wined3d_resource_desc *wined3d_desc, const DDSURFACEDESC2 *desc, unsigned int version) { - const DWORD caps = desc->ddsCaps.dwCaps; + DWORD caps = desc->ddsCaps.dwCaps; const DWORD caps2 = desc->ddsCaps.dwCaps2; wined3d_desc->resource_type = WINED3D_RTYPE_TEXTURE_2D; @@ -6370,7 +6375,7 @@ static void wined3d_resource_desc_from_ddraw(struct ddraw *ddraw, wined3d_desc->bind_flags |= WINED3D_BIND_SHADER_RESOURCE; if (caps & DDSCAPS_ZBUFFER) wined3d_desc->bind_flags |= WINED3D_BIND_DEPTH_STENCIL; - else if (caps & DDSCAPS_3DDEVICE) + else if ((caps & DDSCAPS_3DDEVICE) || force_3ddevice(ddraw, desc, version)) wined3d_desc->bind_flags |= WINED3D_BIND_RENDER_TARGET; if ((caps & DDSCAPS_SYSTEMMEMORY) && !(caps2 & (DDSCAPS2_TEXTUREMANAGE | DDSCAPS2_D3DTEXTUREMANAGE))) @@ -6388,7 +6393,7 @@ static void wined3d_resource_desc_from_ddraw(struct ddraw *ddraw, else if (caps & DDSCAPS_VIDEOMEMORY) { /* Dynamic resources can't be written by the GPU. */ - if (!(caps & (DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER))) + if (!(caps & (DDSCAPS_3DDEVICE | DDSCAPS_ZBUFFER)) && !force_3ddevice(ddraw, desc, version)) wined3d_desc->usage |= WINED3DUSAGE_DYNAMIC; } } @@ -6417,7 +6422,7 @@ static HRESULT ddraw_texture_init(struct ddraw_texture *texture, struct ddraw *d unsigned int i, j; HRESULT hr; - wined3d_resource_desc_from_ddraw(ddraw, &wined3d_desc, desc); + wined3d_resource_desc_from_ddraw(ddraw, &wined3d_desc, desc, texture->version); if (wined3d_desc.format == WINED3DFMT_UNKNOWN) { @@ -6996,7 +7001,7 @@ HRESULT ddraw_surface_create(struct ddraw *ddraw, const DDSURFACEDESC2 *surface_ if (desc->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) bind_flags |= WINED3D_BIND_DEPTH_STENCIL; - else if (desc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) + else if ((desc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) || force_3ddevice(ddraw, desc, version)) bind_flags |= WINED3D_BIND_RENDER_TARGET; if (!(ddraw->flags & DDRAW_NO3D) && SUCCEEDED(hr = wined3d_check_device_format(ddraw->wined3d, diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c index 3e5457e464b..9ddb58b1bbb 100644 --- a/dlls/ddraw/tests/ddraw1.c +++ b/dlls/ddraw/tests/ddraw1.c @@ -5724,7 +5724,7 @@ static void test_flip(void) 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); + ok(hr == DD_OK || broken(hr == E_FAIL), "got %#lx.\n", hr); if (SUCCEEDED(hr)) IDirect3DDevice_Release(device); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10992
v3: * get NULL check back in ddraw_surface_delete_attached_surface(). -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10992#note_141627
```diff + * Attachments forming flip chain can only be explicitly attached on ddraw v1. That + * is implemented by inserting those into complex_array chain so that appear + * the same way as auto created back buffers in the attachment structure. ```
I'd suggest ```diff + * Attachments forming a flip chain can only be explicitly attached on ddraw + * v1. That is implemented by inserting those into the complex_array[] chain + * so that they appear the same way as implicitly created back buffers in the + * attachment structure. ```
```diff +static BOOL force_3ddevice(struct ddraw *ddraw, const DDSURFACEDESC2 *desc, unsigned int surface_version) +{ + return surface_version == 1 && desc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE && !(ddraw->flags & DDRAW_NO3D); +} ```
We could perhaps also do something like this: ```c static bool is_render_target(struct ddraw *ddraw, DWORD caps, unsigned int surface_version) { if (caps & DDSCAPS_3DDEVICE) return true; return surface_version == 1 && caps & DDSCAPS_PRIMARYSURFACE && !(ddraw->flags & DDRAW_NO3D); } ``` Looks good to me though. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10992#note_141987
participants (3)
-
Henri Verbeet (@hverbeet) -
Paul Gofman -
Paul Gofman (@gofman)