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