[2/9] DDraw: Make IDirectDrawSurfaceImpl thread safe

Stefan Dösinger stefandoesinger at gmx.at
Sat Aug 19 16:49:41 CDT 2006


-------------- next part --------------
From nobody Mon Sep 17 00:00:00 2001
From: Stefan Dösinger <stefan at codeweavers.com>
Date: Sat Aug 19 07:12:07 2006 +0200
Subject: [PATCH] DDraw: Make IDirectDrawSurfaceImpl thread safe

---

 dlls/ddraw/ddraw.c         |    7 ++++++
 dlls/ddraw/ddraw_private.h |    4 +++
 dlls/ddraw/device.c        |   11 +++++++++
 dlls/ddraw/surface.c       |   53 ++++++++++++++++++++++++++++++++++++++++----
 dlls/ddraw/texture.c       |   25 +++++++++++++++++++++
 5 files changed, 95 insertions(+), 5 deletions(-)

96c2f90fd7e305caf9ab6185e9bc4a0af3348a00
diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index a07d7dc..8d91240 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -1914,6 +1914,13 @@ IDirectDrawImpl_CreateNewSurface(IDirect
     /* For D3DDevice creation */
     (*ppSurf)->isRenderTarget = FALSE;
 
+    /* Thread protection */
+    if(This->hasCrit)
+    {
+        InitializeCriticalSection(&(*ppSurf)->crit);
+        (*ppSurf)->hasCrit = TRUE;
+    }
+
     /* A trace message for debugging */
     TRACE("(%p) Created IDirectDrawSurface implementation structure at %p\n", This, *ppSurf);
 
diff --git a/dlls/ddraw/ddraw_private.h b/dlls/ddraw/ddraw_private.h
index e404e5e..ae33e14 100644
--- a/dlls/ddraw/ddraw_private.h
+++ b/dlls/ddraw/ddraw_private.h
@@ -244,6 +244,10 @@ struct IDirectDrawSurfaceImpl
     IDirectDrawSurfaceImpl *prev;
 
     DWORD                   Handle;
+
+    /* Multithreading protection */
+    CRITICAL_SECTION        crit;
+    BOOL                    hasCrit;
 };
 
 /* VTable declaration. It's located in surface.c / surface_thunks.c */
diff --git a/dlls/ddraw/device.c b/dlls/ddraw/device.c
index c9d5854..c6435c4 100644
--- a/dlls/ddraw/device.c
+++ b/dlls/ddraw/device.c
@@ -331,7 +331,11 @@ IDirect3DDeviceImpl_7_Release(IDirect3DD
                     {
                         IDirectDrawSurfaceImpl *surf = (IDirectDrawSurfaceImpl *) This->Handles[i].ptr;
                         FIXME("Texture Handle %ld not unset properly\n", i + 1);
+
+                        /* Can I use InterlockedExchange on DWORDS? */
+                        DDOBJ_LOCK(surf);
                         surf->Handle = 0;
+                        DDOBJ_UNLOCK(surf);
                     }
                     break;
 
@@ -541,6 +545,10 @@ IDirect3DDeviceImpl_2_SwapTextureHandles
     IDirectDrawSurfaceImpl *surf2 = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirect3DTexture2, Tex2);
     TRACE("(%p)->(%p,%p)\n", This, surf1, surf2);
 
+    DDOBJ_LOCK(surf1);
+    DDOBJ_LOCK(surf2);
+
+    /* Hold the device lock too(other patch) */
     This->Handles[surf1->Handle - 1].ptr = surf2;
     This->Handles[surf2->Handle - 1].ptr = surf1;
 
@@ -548,6 +556,9 @@ IDirect3DDeviceImpl_2_SwapTextureHandles
     surf2->Handle = surf1->Handle;
     surf1->Handle = swap;
 
+    DDOBJ_UNLOCK(surf2);
+    DDOBJ_UNLOCK(surf1);
+
     return D3D_OK;
 }
 
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index a55347f..806bd5b 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -182,6 +182,7 @@ IDirectDrawSurfaceImpl_AddRef(IDirectDra
 static void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
 {
     TRACE("(%p)\n", This);
+    DDOBJ_LOCK(This);
 
     /* Check the refcount and give a warning */
     if(This->ref > 1)
@@ -250,6 +251,12 @@ static void IDirectDrawSurfaceImpl_Destr
         This->next->prev = This->prev;
     DDOBJ_UNLOCK(This->ddraw);
 
+    DDOBJ_UNLOCK(This);
+    if(This->hasCrit)
+    {
+        DeleteCriticalSection(&This->crit);
+        This->hasCrit = FALSE;
+    }
     HeapFree(GetProcessHeap(), 0, This);
 }
 
@@ -295,6 +302,7 @@ IDirectDrawSurfaceImpl_Release(IDirectDr
         IDirectDrawImpl *ddraw;
         IUnknown *ifaceToRelease = This->ifaceToRelease;
 
+        DDOBJ_LOCK(This);
         /* Destroy all complex attached surfaces
          * Therefore, start with the first surface,
          * except for textures. Not entirely sure what has
@@ -379,12 +387,15 @@ IDirectDrawSurfaceImpl_Release(IDirectDr
          */
         while( (surf = This->next_complex) )
         {
+            DDOBJ_LOCK(surf);
             This->next_complex = surf->next_complex;  /* Unchain it from the complex listing */
+            DDOBJ_UNLOCK(surf);
             IDirectDrawSurfaceImpl_Destroy(surf);     /* Destroy it */
         }
 
         /* Destroy the surface.
          */
+        DDOBJ_UNLOCK(This);
         IDirectDrawSurfaceImpl_Destroy(This);
 
         /* Reduce the ddraw refcount */
@@ -448,6 +459,7 @@ IDirectDrawSurfaceImpl_GetAttachedSurfac
 
     while( (surf = surf->next_complex) )
     {
+        DDOBJ_LOCK(surf);
         if (TRACE_ON(ddraw))
         {
             TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx\n", surf,
@@ -467,12 +479,14 @@ IDirectDrawSurfaceImpl_GetAttachedSurfac
              * apparently apps expect the first found surface to be returned.
              */
 
+            DDOBJ_UNLOCK(surf);
             TRACE("(%p): Returning surface %p\n", This, surf);
             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
             IDirectDrawSurface7_AddRef(*Surface);
             return DD_OK;
         }
+        DDOBJ_UNLOCK(surf);
     }
 
     /* Next, look at the attachment chain */
@@ -480,6 +494,7 @@ IDirectDrawSurfaceImpl_GetAttachedSurfac
 
     while( (surf = surf->next_attached) )
     {
+        DDOBJ_LOCK(surf);
         if (TRACE_ON(ddraw))
         {
             TRACE("Surface: (%p) caps: %lx,%lx,%lx,%lx\n", surf,
@@ -499,11 +514,13 @@ IDirectDrawSurfaceImpl_GetAttachedSurfac
              * apparently apps expect the first found surface to be returned.
              */
 
+            DDOBJ_UNLOCK(surf);
             TRACE("(%p): Returning surface %p\n", This, surf);
             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
             IDirectDrawSurface7_AddRef(*Surface);
             return DD_OK;
         }
+        DDOBJ_UNLOCK(surf);
     }
 
     /* Is this valid? */
@@ -577,7 +594,9 @@ IDirectDrawSurfaceImpl_Lock(IDirectDrawS
         DDSD->dwSize = sizeof(DDSURFACEDESC2);
     }
 
+    DDOBJ_LOCK(This);
     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
+    DDOBJ_UNLOCK(This);
     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
                                   &LockedRect,
                                   Rect,
@@ -771,6 +790,8 @@ IDirectDrawSurfaceImpl_AddAttachedSurfac
      * But apparently backbuffers and mipmaps can be attached too. */
 
     /* Set MIPMAPSUBLEVEL if this seems to be one */
+    DDOBJ_LOCK(This);
+    DDOBJ_LOCK(Surf);
     if (This->surface_desc.ddsCaps.dwCaps &
         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
     {
@@ -783,7 +804,9 @@ IDirectDrawSurfaceImpl_AddAttachedSurfac
     if( (Surf->next_attached != NULL) ||
         (Surf->first_attached != Surf) )
     {
-         ERR("(%p) The Surface %p is already attached somewhere else: next_attached = %p, first_attached = %p, can't handle by now\n", This, Surf, Surf->next_attached, Surf->first_attached);
+        ERR("(%p) The Surface %p is already attached somewhere else: next_attached = %p, first_attached = %p, can't handle by now\n", This, Surf, Surf->next_attached, Surf->first_attached);
+        DDOBJ_UNLOCK(Surf);
+        DDOBJ_UNLOCK(This);
         return DDERR_CANNOTATTACHSURFACE;
     }
 
@@ -795,6 +818,8 @@ IDirectDrawSurfaceImpl_AddAttachedSurfac
     /* MSDN: 
      * "This method increments the reference count of the surface being attached."
      */
+    DDOBJ_UNLOCK(Surf);
+    DDOBJ_UNLOCK(This);
     IDirectDrawSurface7_AddRef(Attach);
     return DD_OK;
 }
@@ -827,6 +852,9 @@ IDirectDrawSurfaceImpl_DeleteAttachedSur
     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
         return DDERR_SURFACENOTATTACHED; /* unchecked */
 
+    DDOBJ_LOCK(This);
+    DDOBJ_LOCK(Surf);
+
     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
     if (This->surface_desc.ddsCaps.dwCaps &
         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
@@ -851,6 +879,8 @@ IDirectDrawSurfaceImpl_DeleteAttachedSur
     Surf->next_attached = NULL;
     Surf->first_attached = Surf;
 
+    DDOBJ_UNLOCK(Surf);
+    DDOBJ_UNLOCK(This);
     IDirectDrawSurface7_Release(Attach);
     return DD_OK;
 }
@@ -879,7 +909,7 @@ IDirectDrawSurfaceImpl_AddOverlayDirtyRe
      * (Stefan Dösinger)
      */
 #if 0
-    return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
+    return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, Rect);
 #endif
     return DDERR_UNSUPPORTED; /* unchecked */
 }
@@ -958,7 +988,9 @@ IDirectDrawSurfaceImpl_GetCaps(IDirectDr
     if(!Caps)
         return DDERR_INVALIDPARAMS;
 
+    DDOBJ_LOCK(This);
     *Caps = This->surface_desc.ddsCaps;
+    DDOBJ_UNLOCK(This);
     return DD_OK;
 }
 
@@ -1197,18 +1229,22 @@ IDirectDrawSurfaceImpl_EnumAttachedSurfa
 
     for (surf = This->next_complex; surf != NULL; surf = surf->next_complex)
     {
+        DDOBJ_LOCK(surf);
         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
         desc = surf->surface_desc;
         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
+        DDOBJ_UNLOCK(surf);
         if (cb(ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
             return DD_OK;
     }
 
     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
     {
+        DDOBJ_LOCK(surf);
         IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
         desc = surf->surface_desc;
         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
+        DDOBJ_UNLOCK(surf);
         if (cb( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, context) == DDENUMRET_CANCEL)
             return DD_OK;
     }
@@ -1850,12 +1886,14 @@ IDirectDrawSurfaceImpl_SetClipper(IDirec
     if (ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper) == This->clipper)
         return DD_OK;
 
+    DDOBJ_LOCK(This);
     if (This->clipper != NULL)
         IDirectDrawClipper_Release(ICOM_INTERFACE(This->clipper, IDirectDrawClipper) );
 
     This->clipper = ICOM_OBJECT(IDirectDrawClipperImpl, IDirectDrawClipper, Clipper);
     if (Clipper != NULL)
         IDirectDrawClipper_AddRef(Clipper);
+    DDOBJ_UNLOCK(This);
 
     return DD_OK;
 }
@@ -1882,7 +1920,7 @@ IDirectDrawSurfaceImpl_SetSurfaceDesc(ID
                                       DWORD Flags)
 {
     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
-    WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
+    WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN, oldFormat;
     HRESULT hr;
     TRACE("(%p)->(%p,%lx)\n", This, DDSD, Flags);
 
@@ -1893,8 +1931,8 @@ IDirectDrawSurfaceImpl_SetSurfaceDesc(ID
     {
         ERR("Setting the surface memory isn't supported yet\n");
         return DDERR_INVALIDPARAMS;
-
     }
+
     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
     {
         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
@@ -1904,7 +1942,10 @@ IDirectDrawSurfaceImpl_SetSurfaceDesc(ID
             ERR("Requested to set an unknown pixelformat\n");
             return DDERR_INVALIDPARAMS;
         }
-        if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
+        DDOBJ_LOCK(This);
+        oldFormat = PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat);
+        DDOBJ_UNLOCK(This);
+        if(newFormat != oldFormat)
         {
             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
                                            newFormat);
@@ -1945,7 +1986,9 @@ IDirectDrawSurfaceImpl_SetSurfaceDesc(ID
         }
     }
 
+    DDOBJ_LOCK(This);
     This->surface_desc = *DDSD;
+    DDOBJ_UNLOCK(This);
 
     return DD_OK;
 }
diff --git a/dlls/ddraw/texture.c b/dlls/ddraw/texture.c
index c3a2717..dfdf15c 100644
--- a/dlls/ddraw/texture.c
+++ b/dlls/ddraw/texture.c
@@ -219,6 +219,8 @@ IDirect3DTextureImpl_GetHandle(IDirect3D
 
     TRACE("(%p)->(%p,%p)\n", This, d3d, lpHandle);
 
+    DDOBJ_LOCK(This);
+    /* Lock the device too(later patch) */
     if(!This->Handle)
     {
         This->Handle = IDirect3DDeviceImpl_CreateHandle(d3d);
@@ -229,6 +231,7 @@ IDirect3DTextureImpl_GetHandle(IDirect3D
         }
     }
     *lpHandle = This->Handle;
+    DDOBJ_UNLOCK(This);
 
     TRACE(" returning handle %08lx.\n", *lpHandle);
 
@@ -307,6 +310,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
 
     TRACE("(%p)->(%p)\n", This, src_ptr);
 
+    DDOBJ_LOCK(This);
+    DDOBJ_LOCK(src_ptr);
     if (((src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP) != (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)) ||
         (src_ptr->surface_desc.u2.dwMipMapCount != This->surface_desc.u2.dwMipMapCount))
     {
@@ -332,6 +337,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
         ret_value = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wine_pal);
         if( ret_value != D3D_OK)
         {
+            DDOBJ_UNLOCK(This);
+            DDOBJ_UNLOCK(src_ptr);
             ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n");
             return D3DERR_TEXTURE_LOAD_FAILED;
         }
@@ -340,6 +347,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
             ret_value = IWineD3DPalette_GetParent(wine_pal, (IUnknown **) &pal);
             if(ret_value != D3D_OK)
             {
+                DDOBJ_UNLOCK(This);
+                DDOBJ_UNLOCK(src_ptr);
                 ERR("IWineD3DPalette::GetParent failed! This is unexpected\n");
                 return D3DERR_TEXTURE_LOAD_FAILED;
             }
@@ -353,6 +362,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
         ret_value = IWineD3DSurface_GetPalette(src_ptr->WineD3DSurface, &wine_pal_src);
         if( ret_value != D3D_OK)
         {
+            DDOBJ_UNLOCK(This);
+            DDOBJ_UNLOCK(src_ptr);
             ERR("IWineD3DSurface::GetPalette failed! This is unexpected\n");
             return D3DERR_TEXTURE_LOAD_FAILED;
         }
@@ -361,6 +372,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
             ret_value = IWineD3DPalette_GetParent(wine_pal_src, (IUnknown **) &pal_src);
             if(ret_value != D3D_OK)
             {
+                DDOBJ_UNLOCK(This);
+                DDOBJ_UNLOCK(src_ptr);
                 ERR("IWineD3DPalette::GetParent failed! This is unexpected\n");
                 return D3DERR_TEXTURE_LOAD_FAILED;
             }
@@ -397,6 +410,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
         {
             /* Should also check for same pixel format, u1.lPitch, ... */
             ERR("Error in surface sizes\n");
+            DDOBJ_UNLOCK(This);
+            DDOBJ_UNLOCK(src_ptr);
             return D3DERR_TEXTURE_LOAD_FAILED;
         }
         else
@@ -420,6 +435,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
             ret_value = IWineD3DSurface_LockRect(src_ptr->WineD3DSurface, &pSrcRect, NULL, 0);
             if(ret_value != D3D_OK)
             {
+                DDOBJ_UNLOCK(This);
+                DDOBJ_UNLOCK(src_ptr);
                 ERR(" (%p) Locking the source surface failed\n", This);
                 return D3DERR_TEXTURE_LOAD_FAILED;
             }
@@ -427,6 +444,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
             ret_value = IWineD3DSurface_LockRect(This->WineD3DSurface, &pDstRect, NULL, 0);
             if(ret_value != D3D_OK)
             {
+                DDOBJ_UNLOCK(This);
+                DDOBJ_UNLOCK(src_ptr);
                 ERR(" (%p) Locking the destination surface failed\n", This);
                 IWineD3DSurface_UnlockRect(src_ptr->WineD3DSurface);
                 return D3DERR_TEXTURE_LOAD_FAILED;
@@ -441,17 +460,21 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
             IWineD3DSurface_UnlockRect(This->WineD3DSurface);
         }
 
+        DDOBJ_UNLOCK(src_ptr);
         if (src_ptr->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
         {
             src_ptr = get_sub_mimaplevel(src_ptr);
+            DDOBJ_LOCK(src_ptr);
         }
         else
         {
             src_ptr = NULL;
         }
+        DDOBJ_UNLOCK(This);
         if (This->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
         {
             This = get_sub_mimaplevel(This);
+            DDOBJ_LOCK(This);
         }
         else
         {
@@ -468,6 +491,8 @@ IDirect3DTextureImpl_Load(IDirect3DTextu
         }
     }
 
+    if(This) DDOBJ_UNLOCK(This);
+    if(src_ptr) DDOBJ_UNLOCK(src_ptr);
     return ret_value;
 }
 
-- 
1.2.4



More information about the wine-patches mailing list