DDRAW: Surface locking patch, take 3 [repost]

Matthew Mastracci matt at aclaro.com
Sun Apr 3 11:57:00 CDT 2005


*** This is a repost of my previous patch - there was a discussion about 
the patch, but no changes needed to be made.

This patch (correctly) fixes the locking problems in SimCity 3000.  We 
now check to see if the blit src and dest are the same surface and, if 
so, we make sure to lock the surface only once and, in the case of 
BltFast, re-adjust the surface pointers.  This patch also makes sure the 
surfaces are correctly unlocked if a bad rectangle is passed.

ChangeLog
Correctly lock and unlock surface for a single-surface Blt() and 
BltFast() call.
-------------- next part --------------
Index: dlls/ddraw/dsurface/dib.c
===================================================================
RCS file: /home/wine/wine/dlls/ddraw/dsurface/dib.c,v
retrieving revision 1.46
diff -u -r1.46 dib.c
--- dlls/ddraw/dsurface/dib.c	10 Mar 2005 11:13:11 -0000	1.46
+++ dlls/ddraw/dsurface/dib.c	20 Mar 2005 16:49:40 -0000
@@ -528,9 +528,15 @@
     DD_STRUCT_INIT(&sdesc);
 
     sdesc.dwSize = sizeof(sdesc);
-    if (src) IDirectDrawSurface7_Lock(src, NULL, &sdesc, DDLOCK_READONLY, 0);
     ddesc.dwSize = sizeof(ddesc);
-    IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
+
+    if (src == iface) {
+        IDirectDrawSurface7_Lock(iface, NULL, &ddesc, 0, 0);
+        DD_STRUCT_COPY_BYSIZE(&sdesc, &ddesc);
+    } else {
+        if (src) IDirectDrawSurface7_Lock(src, NULL, &sdesc, DDLOCK_READONLY, 0);
+        IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
+    }
 
     if ((sdesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) &&
 	(ddesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)) {
@@ -581,7 +587,8 @@
 	 (xsrc.right > sdesc.dwWidth) || (xsrc.right < 0) ||
 	 (xsrc.right < xsrc.left) || (xsrc.bottom < xsrc.top))) {
         WARN("Application gave us bad source rectangle for Blt.\n");
-	return DDERR_INVALIDRECT;
+	ret = DDERR_INVALIDRECT;
+	goto release;
     }
     /* For the Destination rect, it can be out of bounds on the condition that a clipper
        is set for the given surface.
@@ -593,7 +600,8 @@
 	 (xdst.right > ddesc.dwWidth) || (xdst.right < 0) ||
 	 (xdst.right < xdst.left) || (xdst.bottom < xdst.top))) {
         WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
-	return DDERR_INVALIDRECT;
+	ret = DDERR_INVALIDRECT;
+	goto release;
     }
     
     /* Now handle negative values in the rectangles. Warning: only supported for now
@@ -958,7 +966,7 @@
 
 release:
     IDirectDrawSurface7_Unlock(iface,NULL);
-    if (src) IDirectDrawSurface7_Unlock(src,NULL);
+    if (src && src != iface) IDirectDrawSurface7_Unlock(src,NULL);
     return DD_OK;
 }
 
@@ -975,7 +983,7 @@
     HRESULT		ret = DD_OK;
     LPBYTE		sbuf, dbuf;
     RECT		rsrc2;
-    RECT                lock_src, lock_dst;
+    RECT                lock_src, lock_dst, lock_union;
 
     if (TRACE_ON(ddraw)) {
 	TRACE("(%p)->(%ld,%ld,%p,%p,%08lx)\n",
@@ -1043,11 +1051,28 @@
     lock_dst.right = dstx + w;
     lock_dst.bottom = dsty + h;
     
+    bpp = GET_BPP(This->surface_desc);
+
     /* We need to lock the surfaces, or we won't get refreshes when done. */
-    sdesc.dwSize = sizeof(sdesc);
-    IDirectDrawSurface7_Lock(src, &lock_src, &sdesc, DDLOCK_READONLY, 0);
-    ddesc.dwSize = sizeof(ddesc);
-    IDirectDrawSurface7_Lock(iface, &lock_dst, &ddesc, DDLOCK_WRITEONLY, 0);
+    if (src == iface) {
+        int pitch;
+
+        UnionRect(&lock_union, &lock_src, &lock_dst);
+
+        /* Lock the union of the two rectangles */
+        IDirectDrawSurface7_Lock(iface, &lock_union, &ddesc, 0, 0);
+
+        pitch = This->surface_desc.u1.lPitch;
+
+        /* Since sdesc was originally copied from this surface's description, we can just reuse it */
+        sdesc.lpSurface = (BYTE *)This->surface_desc.lpSurface + lock_src.top * pitch + lock_src.left * bpp; 
+        ddesc.lpSurface = (BYTE *)This->surface_desc.lpSurface + lock_dst.top * pitch + lock_dst.left * bpp; 
+    } else {
+        sdesc.dwSize = sizeof(sdesc);
+        IDirectDrawSurface7_Lock(src, &lock_src, &sdesc, DDLOCK_READONLY, 0);
+        ddesc.dwSize = sizeof(ddesc);
+        IDirectDrawSurface7_Lock(iface, &lock_dst, &ddesc, DDLOCK_WRITEONLY, 0);
+    }
 
     /* Handle first the FOURCC surfaces... */
     if ((sdesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) && (ddesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)) {
@@ -1069,7 +1094,6 @@
 	goto error;
     }
     
-    bpp = GET_BPP(This->surface_desc);
     sbuf = (BYTE *) sdesc.lpSurface;
     dbuf = (BYTE *) ddesc.lpSurface;
     
@@ -1141,8 +1165,13 @@
     }
     
 error:
-    IDirectDrawSurface7_Unlock(iface, &lock_dst);
-    IDirectDrawSurface7_Unlock(src, &lock_src);
+    if (src == iface) {
+        IDirectDrawSurface7_Unlock(iface, &lock_union);
+    } else {
+        IDirectDrawSurface7_Unlock(iface, &lock_dst);
+        IDirectDrawSurface7_Unlock(src, &lock_src);
+    }
+
     return ret;
 }
 


More information about the wine-patches mailing list