ddraw: Allow flipping of arbitrary attached surfaces (test included)
unavowed at vexillium.org
unavowed at vexillium.org
Tue Mar 20 12:29:24 CDT 2007
This fixes http://bugs.winehq.org/show_bug.cgi?id=7655
This patch implements behaviour that is illegal according to the ddraw
documentation, but it is what the reference implementation on Windows actually
does.
ChangeLog:
ddraw: Allow flipping of arbitrary attached surfaces (test included)
--
Unavowed
-------------- next part --------------
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index 5eca9c2..3f058ab 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -622,7 +622,6 @@ IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
* Returns:
* DD_OK on success
* DDERR_NOTFLIPPABLE if no flip target could be found
- * DDERR_INVALIDOBJECT if the surface isn't a front buffer
* For more details, see IWineD3DSurface::Flip
*
*****************************************************************************/
@@ -637,19 +636,31 @@ IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
HRESULT hr;
TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
- /* Flip has to be called from a front buffer
- * What about overlay surfaces, AFAIK they can flip too?
+ /*
+ * Not really sure about which caps are allowed here. Not checking for
+ * DDSCAPS_FRONTBUFFER is against the documentation but tries to follow
+ * the reference implementation.
+ * if( !(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) )
+ * return DDERR_INVALIDOBJECT; / * Unchecked * /
*/
- if( !(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) )
- return DDERR_INVALIDOBJECT; /* Unckecked */
/* WineD3D doesn't keep track of attached surface, so find the target */
if(!Override)
{
DDSCAPS2 Caps;
-
memset(&Caps, 0, sizeof(Caps));
- Caps.dwCaps |= DDSCAPS_BACKBUFFER;
+
+ if ((This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER) == 0)
+ {
+ /* Since we're going against the documentation here to follow the
+ * reference implementation, let's try to be strict in what we
+ * allow.
+ */
+ Caps = This->surface_desc.ddsCaps;
+ }
+ else
+ Caps.dwCaps = DDSCAPS_BACKBUFFER;
+
hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
if(hr != DD_OK)
{
diff --git a/dlls/ddraw/tests/dsurface.c b/dlls/ddraw/tests/dsurface.c
index 2d5a625..b8fa574 100644
--- a/dlls/ddraw/tests/dsurface.c
+++ b/dlls/ddraw/tests/dsurface.c
@@ -885,12 +885,115 @@ static void GetDDInterface_7(void)
IDirectDrawSurface7_Release(dsurface7);
}
+/*
+ * This function tests for compliance with undocumented behaviour: contrary to
+ * MSDN, an offscreen, non-front-buffer surface may be flipped with its
+ * attached surface. An example of a program that makes use of this feature
+ * is the game Seven Kingoms II.
+ */
+static void OffscreenSurfaceFlipTest(void)
+{
+ LPDIRECTDRAWSURFACE surface = NULL;
+ LPDIRECTDRAWSURFACE surface2 = NULL;
+ DDSURFACEDESC desc;
+ DDSURFACEDESC desc2;
+ HRESULT ret;
+
+ /* Create and attach two surfaces */
+
+ memset(&desc, 0, sizeof(desc));
+ desc.dwSize = sizeof(desc);
+ desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
+ desc.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN;
+ desc.dwWidth = 640;
+ desc.dwHeight = 480;
+ desc2 = desc;
+
+ ret = IDirectDraw_CreateSurface(lpDD, &desc, &surface, NULL);
+ ok(ret == DD_OK, "CreateSurface returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to create surface\n");
+ goto end;
+ }
+
+ ret = IDirectDraw_CreateSurface(lpDD, &desc2, &surface2, NULL);
+ ok(ret == DD_OK, "CreateSurface returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to create surface\n");
+ goto end;
+ }
+
+ ret = IDirectDrawSurface_AddAttachedSurface(surface, surface2);
+ ok(ret == DD_OK, "AddAttachedSurface returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to attach surface\n");
+ goto end;
+ }
+
+ /* Put pixel data into second surface and call Flip() on the first */
+
+ ret = IDirectDrawSurface_Lock(surface2, NULL, &desc, DDLOCK_WAIT, NULL);
+ ok(ret == DD_OK, "Lock returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to lock surface\n");
+ goto end;
+ }
+
+ *(long *)desc.lpSurface = 0xdeadbeefl;
+
+ ret = IDirectDrawSurface_Unlock(surface2, NULL);
+ ok(ret == DD_OK, "Unlock returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to unlock surface\n");
+ goto end;
+ }
+
+ ret = IDirectDrawSurface_Flip(surface, NULL, DDFLIP_WAIT);
+ ok(ret == DD_OK, "Flip returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ goto end;
+
+ /* Check if the pixel data is present in the first surface */
+
+ ret = IDirectDrawSurface_Lock(surface, NULL, &desc, DDLOCK_WAIT, NULL);
+ ok(ret == DD_OK, "Lock returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to lock surface\n");
+ goto end;
+ }
+
+ ok(*(long *)desc.lpSurface == 0xdeadbeefl,
+ "Data not transferred from attached surface by Flip(): %lx\n",
+ *(long *)desc.lpSurface);
+
+ ret = IDirectDrawSurface_Unlock(surface, NULL);
+ ok(ret == DD_OK, "Unlock returned: 0x%x\n", ret);
+ if (FAILED(ret))
+ {
+ skip("Failed to unlock surface\n");
+ goto end;
+ }
+
+end:
+ if (surface != NULL)
+ IDirectDraw_Release(surface);
+ if (surface2 != NULL)
+ IDirectDraw_Release(surface2);
+}
+
START_TEST(dsurface)
{
if (!CreateDirectDraw())
return;
MipMapCreationTest();
SrcColorKey32BlitTest();
+ OffscreenSurfaceFlipTest();
QueryInterface();
GetDDInterface_1();
GetDDInterface_2();
More information about the wine-patches
mailing list