After talking with Lionel Ulmer offline I came up with the following patch for bug 829. It includes a hopefully more clear comment of when the corruption can occure and a better set of rules.
Change log: fix same surface corruption when no flags are set and areas are the same size
Tony Lambregts tony_lambregts@telusplanet.net
Index: dib.c =================================================================== RCS file: /home/wine/wine/dlls/ddraw/dsurface/dib.c,v retrieving revision 1.11 diff -u -r1.11 dib.c --- dib.c 28 Jun 2002 17:32:25 -0000 1.11 +++ dib.c 9 Jul 2002 03:57:37 -0000 @@ -351,6 +351,7 @@ int bpp, srcheight, srcwidth, dstheight, dstwidth, width; int x, y; LPBYTE dbuf, sbuf; + BOOL SameSurfaceOK = TRUE;
TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This,rdst,src,rsrc,dwFlags,lpbltfx);
@@ -474,6 +475,18 @@ sbase = (BYTE*)sdesc.lpSurface+(xsrc.top*sdesc.u1.lPitch)+xsrc.left*bpp; xinc = (srcwidth << 16) / dstwidth; yinc = (srcheight << 16) / dstheight; + SameSurfaceOK = ((src != iface)|| + (sbase >= dbuf)|| + (xdst.top > xsrc.bottom)||(xdst.left > xsrc.right)||(xdst.right < xsrc.left)); + + /* + A little explination: Screen coruption can occure if the following set of circumstances is true + + 1.) Both the source and destination are the same surface. -->(src != iface) + 2.) The start of the source is less than the destination . -->(sbase >= dbuf) + 3.) There is overlap. -->(xdst.top < xsrc.bottom)&&(xdst.left < xsrc.right)(xdst.right < xsrc.left) + This is fixed in the case where no flags are set and the areas are the same size. + */
if (!dwFlags) { /* No effects, we can cheat here */ @@ -482,11 +495,29 @@ /* No stretching in either direction. This needs to be as * fast as possible */ sbuf = sbase; - for (y = 0; y < dstheight; y++) { - memcpy(dbuf, sbuf, width); - sbuf += sdesc.u1.lPitch; - dbuf += ddesc.u1.lPitch; - } + if (SameSurfaceOK) { + for (y = 0; y < dstheight; y++) { + memcpy(dbuf, sbuf, width); + sbuf += sdesc.u1.lPitch; + dbuf += ddesc.u1.lPitch; + } + } else { + sbuf += (sdesc.u1.lPitch*dstheight); + dbuf += (ddesc.u1.lPitch*dstheight); + if (xdst.top == xsrc.top) { /* Are the source and destination on the same line? */ + for (y = 0; y < dstheight; y++) { + sbuf -= sdesc.u1.lPitch; + dbuf -= ddesc.u1.lPitch; + memmove(dbuf, sbuf, width); + } + } else { + for (y = 0; y < dstheight; y++) { + sbuf -= sdesc.u1.lPitch; + dbuf -= ddesc.u1.lPitch; + memcpy(dbuf, sbuf, width); + } + } + } } else { /* Stretching in Y direction only */ for (y = sy = 0; y < dstheight; y++, sy += yinc) { @@ -544,6 +575,10 @@ } } else if (dwFlags & (DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE)) { DWORD keylow, keyhigh; + + if (!SameSurfaceOK) { + FIXME("\tSoure and destination surfaces are the same and could cause display problems\n"); + }
if (dwFlags & DDBLT_KEYSRC) { keylow = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;