winex11: Add support for performing GL calls on a top-level window DC.
[wine] / dlls / ddraw / ddraw.c
index df107ce..230533f 100644 (file)
@@ -3,6 +3,7 @@
  * Copyright 1998-2000 Lionel Ulmer
  * Copyright 2000-2001 TransGaming Technologies Inc.
  * Copyright 2006 Stefan Dösinger
+ * Copyright 2008 Denver Gingerich
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include "windef.h"
 #include "winbase.h"
-#include "winnls.h"
 #include "winerror.h"
 #include "wingdi.h"
 #include "wine/exception.h"
-#include "excpt.h"
 
 #include "ddraw.h"
 #include "d3d.h"
@@ -75,10 +74,6 @@ static const DDDEVICEIDENTIFIER2 deviceidentifier =
  * method.
  * The returned interface is AddRef()-ed before it's returned
  *
- * Rules for QueryInterface:
- *  http://msdn.microsoft.com/library/default.asp? \
- *    url=/library/en-us/com/html/6db17ed8-06e4-4bae-bc26-113176cc7e0e.asp
- *
  * Used for version 1, 2, 4 and 7
  *
  * Params:
@@ -99,11 +94,17 @@ IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
 
     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
 
+    /* Can change surface impl type */
+    EnterCriticalSection(&ddraw_cs);
+
     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
     *obj = NULL;
 
     if(!refiid)
+    {
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_INVALIDPARAMS;
+    }
 
     /* Check DirectDraw Interfaces */
     if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
@@ -195,10 +196,12 @@ IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
     else
     {
         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
+        LeaveCriticalSection(&ddraw_cs);
         return E_NOINTERFACE;
     }
 
     IUnknown_AddRef( (IUnknown *) *obj );
+    LeaveCriticalSection(&ddraw_cs);
     return S_OK;
 }
 
@@ -246,14 +249,6 @@ IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
 void
 IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
 {
-    int i;
-
-    for(i = 0; i < This->numConvertedDecls; i++)
-    {
-        IWineD3DVertexDeclaration_Release(This->decls[i].decl);
-    }
-    HeapFree(GetProcessHeap(), 0, This->decls);
-
     /* Clear the cooplevel to restore window and display mode */
     IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7),
                                         NULL,
@@ -270,7 +265,9 @@ IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
     /* Unregister the window class */
     UnregisterClassA(This->classname, 0);
 
-    remove_ddraw_object(This);
+    EnterCriticalSection(&ddraw_cs);
+    list_remove(&This->ddraw_list_entry);
+    LeaveCriticalSection(&ddraw_cs);
 
     /* Release the attached WineD3D stuff */
     IWineD3DDevice_Release(This->wineD3DDevice);
@@ -342,7 +339,7 @@ IDirectDrawImpl_Release(IDirectDraw7 *iface)
  *
  * Unsure about these: DDSCL_FPUSETUP DDSCL_FPURESERVE
  *
- * These seem not really imporant for wine
+ * These don't seem very important for wine:
  *  DDSCL_ALLOWREBOOT, DDSCL_NOWINDOWCHANGES, DDSCL_ALLOWMODEX
  *
  * Returns:
@@ -361,14 +358,17 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
     HWND window;
     HRESULT hr;
 
-    FIXME("(%p)->(%p,%08x)\n",This,hwnd,cooplevel);
+    TRACE("(%p)->(%p,%08x)\n",This,hwnd,cooplevel);
     DDRAW_dump_cooperativelevel(cooplevel);
 
+    EnterCriticalSection(&ddraw_cs);
+
     /* Get the old window */
     hr = IWineD3DDevice_GetHWND(This->wineD3DDevice, &window);
     if(hr != D3D_OK)
     {
         ERR("IWineD3DDevice::GetHWND failed, hr = %08x\n", hr);
+        LeaveCriticalSection(&ddraw_cs);
         return hr;
     }
 
@@ -378,6 +378,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
                       DDSCL_EXCLUSIVE      )))
     {
         TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_INVALIDPARAMS;
     }
 
@@ -396,11 +397,13 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
                          DDSCL_FULLSCREEN      ) )
         {
             TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
+            LeaveCriticalSection(&ddraw_cs);
             return DDERR_INVALIDPARAMS;
         }
         else if( (This->cooperative_level & DDSCL_FULLSCREEN) && window)
         {
             TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET\n");
+            LeaveCriticalSection(&ddraw_cs);
             return DDERR_HWNDALREADYSET;
         }
 
@@ -425,6 +428,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
         if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
         {
             TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
+            LeaveCriticalSection(&ddraw_cs);
             return DDERR_INVALIDPARAMS;
         }
 
@@ -457,6 +461,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
         if(!(cooplevel & DDSCL_EXCLUSIVE) )
         {
             TRACE("(%p) DDSCL_FULLSCREEN needs DDSCL_EXCLUSIVE\n", This);
+            LeaveCriticalSection(&ddraw_cs);
             return DDERR_INVALIDPARAMS;
         }
         /* Need a HWND
@@ -467,13 +472,9 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
         }
         */
 
-        /* Switch from normal to full screen mode? */
-        if(This->cooperative_level & DDSCL_NORMAL)
-        {
-            This->cooperative_level &= ~DDSCL_NORMAL;
-            IWineD3DDevice_SetFullscreen(This->wineD3DDevice,
-                                         TRUE);
-        }
+        This->cooperative_level &= ~DDSCL_NORMAL;
+        IWineD3DDevice_SetFullscreen(This->wineD3DDevice,
+                                     TRUE);
 
         /* Don't override focus windows or private device windows */
         if( hwnd &&
@@ -487,6 +488,7 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
     else if(cooplevel & DDSCL_EXCLUSIVE)
     {
         TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN\n", This);
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_INVALIDPARAMS;
     }
 
@@ -511,8 +513,6 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
 
     if(cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
     {
-        FIXME("DirectDraw is not thread safe yet\n");
-
         /* Enable thread safety in wined3d */
         IWineD3DDevice_SetMultithreaded(This->wineD3DDevice);
     }
@@ -530,48 +530,41 @@ IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
     /* Store the cooperative_level */
     This->cooperative_level |= cooplevel;
     TRACE("SetCooperativeLevel retuning DD_OK\n");
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
 /*****************************************************************************
- * IDirectDraw7::SetDisplayMode
  *
- * Sets the display screen resolution, color depth and refresh frequency
- * when in fullscreen mode (in theory).
- * Possible return values listed in the SDK suggest that this method fails
- * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
- * the display mode in DDSCL_NORMAL mode without an hwnd specified.
- * It seems to be valid to pass 0 for With and Height, this has to be tested
- * It could mean that the current video mode should be left as-is. (But why
- * call it then?)
+ * Helper function for SetDisplayMode and RestoreDisplayMode
  *
- * Params:
- *  Height, Width: Screen dimension
- *  BPP: Color depth in Bits per pixel
- *  Refreshrate: Screen refresh rate
- *  Flags: Other stuff
- *
- * Returns
- *  DD_OK on success
+ * Implements DirectDraw's SetDisplayMode, but ignores the value of
+ * ForceRefreshRate, since it is already handled by
+ * IDirectDrawImpl_SetDisplayMode.  RestoreDisplayMode can use this function
+ * without worrying that ForceRefreshRate will override the refresh rate.  For
+ * argument and return value documentation, see
+ * IDirectDrawImpl_SetDisplayMode.
  *
  *****************************************************************************/
-static HRESULT WINAPI
-IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
-                               DWORD Width,
-                               DWORD Height,
-                               DWORD BPP,
-                               DWORD RefreshRate,
-                               DWORD Flags)
+static HRESULT
+IDirectDrawImpl_SetDisplayModeNoOverride(IDirectDraw7 *iface,
+                                         DWORD Width,
+                                         DWORD Height,
+                                         DWORD BPP,
+                                         DWORD RefreshRate,
+                                         DWORD Flags)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
     WINED3DDISPLAYMODE Mode;
     HRESULT hr;
     TRACE("(%p)->(%d,%d,%d,%d,%x: Relay!\n", This, Width, Height, BPP, RefreshRate, Flags);
 
+    EnterCriticalSection(&ddraw_cs);
     if( !Width || !Height )
     {
         ERR("Width=%d, Height=%d, what to do?\n", Width, Height);
         /* It looks like Need for Speed Porsche Unleashed expects DD_OK here */
+        LeaveCriticalSection(&ddraw_cs);
         return DD_OK;
     }
 
@@ -593,7 +586,7 @@ IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
         case 15: Mode.Format = WINED3DFMT_X1R5G5B5; break;
         case 16: Mode.Format = WINED3DFMT_R5G6B5;   break;
         case 24: Mode.Format = WINED3DFMT_R8G8B8;   break;
-        case 32: Mode.Format = WINED3DFMT_A8R8G8B8; break;
+        case 32: Mode.Format = WINED3DFMT_X8R8G8B8; break;
     }
 
     /* TODO: The possible return values from msdn suggest that
@@ -605,13 +598,54 @@ IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
     hr = IWineD3DDevice_SetDisplayMode(This->wineD3DDevice,
                                        0, /* First swapchain */
                                        &Mode);
+    LeaveCriticalSection(&ddraw_cs);
     switch(hr)
     {
-        case WINED3DERR_NOTAVAILABLE:       return DDERR_INVALIDMODE;
+        case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
         default:                            return hr;
     };
 }
 
+/*****************************************************************************
+ * IDirectDraw7::SetDisplayMode
+ *
+ * Sets the display screen resolution, color depth and refresh frequency
+ * when in fullscreen mode (in theory).
+ * Possible return values listed in the SDK suggest that this method fails
+ * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
+ * the display mode in DDSCL_NORMAL mode without an hwnd specified.
+ * It seems to be valid to pass 0 for With and Height, this has to be tested
+ * It could mean that the current video mode should be left as-is. (But why
+ * call it then?)
+ *
+ * Params:
+ *  Height, Width: Screen dimension
+ *  BPP: Color depth in Bits per pixel
+ *  Refreshrate: Screen refresh rate
+ *  Flags: Other stuff
+ *
+ * Returns
+ *  DD_OK on success
+ *
+ *****************************************************************************/
+static HRESULT WINAPI
+IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
+                               DWORD Width,
+                               DWORD Height,
+                               DWORD BPP,
+                               DWORD RefreshRate,
+                               DWORD Flags)
+{
+    if (force_refresh_rate != 0)
+    {
+        TRACE("ForceRefreshRate overriding passed-in refresh rate (%d Hz) to %d Hz\n", RefreshRate, force_refresh_rate);
+        RefreshRate = force_refresh_rate;
+    }
+
+    return IDirectDrawImpl_SetDisplayModeNoOverride(iface, Width, Height, BPP,
+                                                    RefreshRate, Flags);
+}
+
 /*****************************************************************************
  * IDirectDraw7::RestoreDisplayMode
  *
@@ -639,12 +673,12 @@ IDirectDrawImpl_RestoreDisplayMode(IDirectDraw7 *iface)
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
     TRACE("(%p)\n", This);
 
-    return IDirectDraw7_SetDisplayMode(ICOM_INTERFACE(This, IDirectDraw7),
-                                       This->orig_width,
-                                       This->orig_height,
-                                       This->orig_bpp,
-                                       0,
-                                       0);
+    return IDirectDrawImpl_SetDisplayModeNoOverride(ICOM_INTERFACE(This, IDirectDraw7),
+                                                    This->orig_width,
+                                                    This->orig_height,
+                                                    This->orig_bpp,
+                                                    0,
+                                                    0);
 }
 
 /*****************************************************************************
@@ -742,9 +776,11 @@ IDirectDrawImpl_GetDisplayMode(IDirectDraw7 *iface,
     DWORD Size;
     TRACE("(%p)->(%p): Relay\n", This, DDSD);
 
+    EnterCriticalSection(&ddraw_cs);
     /* This seems sane */
     if(!DDSD) 
     {
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_INVALIDPARAMS;
     }
 
@@ -757,6 +793,7 @@ IDirectDrawImpl_GetDisplayMode(IDirectDraw7 *iface,
     if( hr != D3D_OK )
     {
         ERR(" (%p) IWineD3DDevice::GetDisplayMode returned %08x\n", This, hr);
+        LeaveCriticalSection(&ddraw_cs);
         return hr;
     }
 
@@ -779,6 +816,7 @@ IDirectDrawImpl_GetDisplayMode(IDirectDraw7 *iface,
         DDRAW_dump_surface_desc(DDSD);
     }
 
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -861,10 +899,16 @@ IDirectDrawImpl_GetVerticalBlankStatus(IDirectDraw7 *iface,
     TRACE("(%p)->(%p)\n", This, status);
 
     /* This looks sane, the MSDN suggests it too */
-    if(!status) return DDERR_INVALIDPARAMS;
+    EnterCriticalSection(&ddraw_cs);
+    if(!status)
+    {
+        LeaveCriticalSection(&ddraw_cs);
+        return DDERR_INVALIDPARAMS;
+    }
 
     *status = This->fake_vblank;
     This->fake_vblank = !This->fake_vblank;
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -893,19 +937,24 @@ IDirectDrawImpl_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *Caps, DWORD *t
     {
         TRACE("(%p) Asked for memory with description: ", This);
         DDRAW_dump_DDSCAPS2(Caps);
-        TRACE("\n");
     }
+    EnterCriticalSection(&ddraw_cs);
 
     /* Todo: System memory vs local video memory vs non-local video memory
      * The MSDN also mentions differences between texture memory and other
      * resources, but that's not important
      */
 
-    if( (!total) && (!free) ) return DDERR_INVALIDPARAMS;
+    if( (!total) && (!free) )
+    {
+        LeaveCriticalSection(&ddraw_cs);
+        return DDERR_INVALIDPARAMS;
+    }
 
     if(total) *total = This->total_vidmem;
     if(free) *free = IWineD3DDevice_GetAvailableTextureMem(This->wineD3DDevice);
 
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -1013,6 +1062,7 @@ static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw7 *iface, DWORD *Sc
     WINED3DDISPLAYMODE Mode;
 
     /* This function is called often, so print the fixme only once */
+    EnterCriticalSection(&ddraw_cs);
     if(!hide)
     {
         FIXME("(%p)->(%p): Semi-Stub\n", This, Scanline);
@@ -1030,6 +1080,7 @@ static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw7 *iface, DWORD *Sc
     if (This->cur_scanline >= Mode.Height + 20)
         This->cur_scanline = 0;
 
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -1052,6 +1103,7 @@ IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface)
     HRESULT hr;
     TRACE("(%p)\n", This);
 
+    EnterCriticalSection(&ddraw_cs);
     /* Description from MSDN:
      * For fullscreen apps return DDERR_NOEXCLUSIVEMODE if the user switched
      * away from the app with e.g. alt-tab. Windowed apps receive 
@@ -1070,17 +1122,21 @@ IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface)
         case WINED3DERR_DEVICELOST:
             if(This->cooperative_level & DDSCL_EXCLUSIVE)
             {
+                LeaveCriticalSection(&ddraw_cs);
                 return DDERR_NOEXCLUSIVEMODE;
             }
             else
             {
+                LeaveCriticalSection(&ddraw_cs);
                 return DDERR_EXCLUSIVEMODEALREADYSET;
             }
 
         case WINED3DERR_DEVICENOTRESET:
+            LeaveCriticalSection(&ddraw_cs);
             return DD_OK;
 
         case WINED3D_OK:
+            LeaveCriticalSection(&ddraw_cs);
             return DD_OK;
 
         case WINED3DERR_DRIVERINTERNALERROR:
@@ -1089,6 +1145,7 @@ IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface)
                 " returning DD_OK\n", This, hr);
     }
 
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -1120,6 +1177,7 @@ IDirectDrawImpl_GetGDISurface(IDirectDraw7 *iface,
     /* Get the back buffer from the wineD3DDevice and search its
      * attached surfaces for the front buffer
      */
+    EnterCriticalSection(&ddraw_cs);
     hr = IWineD3DDevice_GetBackBuffer(This->wineD3DDevice,
                                       0, /* SwapChain */
                                       0, /* first back buffer*/
@@ -1130,6 +1188,7 @@ IDirectDrawImpl_GetGDISurface(IDirectDraw7 *iface,
         (!Surf) )
     {
         ERR("IWineD3DDevice::GetBackBuffer failed\n");
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_NOTFOUND;
     }
 
@@ -1151,6 +1210,7 @@ IDirectDrawImpl_GetGDISurface(IDirectDraw7 *iface,
     }
 
     /* The AddRef is OK this time */
+    LeaveCriticalSection(&ddraw_cs);
     return hr;
 }
 
@@ -1206,8 +1266,13 @@ IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface,
 
     TRACE("(%p)->(%p,%p,%p): Relay\n", This, DDSD, Context, cb);
 
+    EnterCriticalSection(&ddraw_cs);
     /* This looks sane */
-    if(!cb) return DDERR_INVALIDPARAMS;
+    if(!cb)
+    {
+        LeaveCriticalSection(&ddraw_cs);
+        return DDERR_INVALIDPARAMS;
+    }
 
     if(DDSD)
     {
@@ -1251,17 +1316,24 @@ IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface,
 
             PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, mode.Format);
 
-            TRACE("Enumerating %dx%d@%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount);
+            /* Calc pitch and DWORD align like MSDN says */
+            callback_sd.u1.lPitch = (callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8) * mode.Width;
+            callback_sd.u1.lPitch = (callback_sd.u1.lPitch + 3) & ~3;
+
+            TRACE("Enumerating %dx%dx%d @%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
+              callback_sd.u2.dwRefreshRate);
 
             if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
             {
                 TRACE("Application asked to terminate the enumeration\n");
+                LeaveCriticalSection(&ddraw_cs);
                 return DD_OK;
             }
         }
     }
 
     TRACE("End of enumeration\n");
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -1447,6 +1519,7 @@ IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
     IWineD3DSurface *wineD3DSurface;
     HRESULT hr;
     void *tmp;
+    IWineD3DClipper *clipper = NULL;
 
     WINED3DSURFACE_DESC     Desc;
     WINED3DFORMAT           Format;
@@ -1482,6 +1555,8 @@ IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
         IWineD3DSurface_Release(wineD3DSurface);
     }
 
+    /* get the clipper */
+    IWineD3DSurface_GetClipper(wineD3DSurface, &clipper);
 
     /* Get the surface properties */
     Desc.Format = &Format;
@@ -1516,6 +1591,8 @@ IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
     if(hr != D3D_OK)
         return hr;
 
+    IWineD3DSurface_SetClipper(surfImpl->WineD3DSurface, clipper);
+
     /* Update the IParent if it exists */
     if(parImpl)
     {
@@ -1532,6 +1609,10 @@ IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
 
     surfImpl->ImplType = This->ImplType;
 
+    if(clipper)
+    {
+        IWineD3DClipper_Release(clipper);
+    }
     return DDENUMRET_OK;
 }
 
@@ -1580,6 +1661,7 @@ IDirectDrawImpl_RecreateAllSurfaces(IDirectDrawImpl *This)
  *  Format: The requested format
  *  Usage, Pool: D3DUSAGE and D3DPOOL of the surface
  *  level: The mipmap level
+ *  Face: The cube map face type
  *  Surface: Pointer to pass the created surface back at
  *  SharedHandle: NULL
  *
@@ -1593,17 +1675,66 @@ D3D7CB_CreateSurface(IUnknown *device,
                      UINT Width, UINT Height,
                      WINED3DFORMAT Format,
                      DWORD Usage, WINED3DPOOL Pool, UINT level,
+                     WINED3DCUBEMAP_FACES Face,
                      IWineD3DSurface **Surface,
                      HANDLE *SharedHandle)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
-    IDirectDrawSurfaceImpl *surf = This->tex_root;
-    int i;
-    TRACE("(%p) call back. surf=%p\n", device, surf);
+    IDirectDrawSurfaceImpl *surf = NULL;
+    int i = 0;
+    DDSCAPS2 searchcaps = This->tex_root->surface_desc.ddsCaps;
+    TRACE("(%p) call back. surf=%p. Face %d level %d\n", device, This->tex_root, Face, level);
+
+    searchcaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
+    switch(Face)
+    {
+        case WINED3DCUBEMAP_FACE_POSITIVE_X:
+            TRACE("Asked for positive x\n");
+            if(searchcaps.dwCaps2 & DDSCAPS2_CUBEMAP) {
+                searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
+            }
+            surf = This->tex_root; break;
+        case WINED3DCUBEMAP_FACE_NEGATIVE_X:
+            TRACE("Asked for negative x\n");
+            searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX; break;
+        case WINED3DCUBEMAP_FACE_POSITIVE_Y:
+            TRACE("Asked for positive y\n");
+            searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY; break;
+        case WINED3DCUBEMAP_FACE_NEGATIVE_Y:
+            TRACE("Asked for negative y\n");
+            searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY; break;
+        case WINED3DCUBEMAP_FACE_POSITIVE_Z:
+            TRACE("Asked for positive z\n");
+            searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ; break;
+        case WINED3DCUBEMAP_FACE_NEGATIVE_Z:
+            TRACE("Asked for negative z\n");
+            searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
+        default: {ERR("Unexpected cube face\n");} /* Stupid compiler */
+    }
+
+    if(!surf)
+    {
+        IDirectDrawSurface7 *attached;
+        IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->tex_root, IDirectDrawSurface7),
+                                               &searchcaps,
+                                               &attached);
+        surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attached);
+        IDirectDrawSurface7_Release(attached);
+    }
+    if(!surf) ERR("root search surface not found\n");
 
     /* Find the wanted mipmap. There are enough mipmaps in the chain */
-    for(i = 0; i < level; i++)
-        surf = surf->next_complex;
+    while(i < level)
+    {
+        IDirectDrawSurface7 *attached;
+        IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(surf, IDirectDrawSurface7),
+                                               &searchcaps,
+                                               &attached);
+        if(!attached) ERR("Surface not found\n");
+        surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attached);
+        IDirectDrawSurface7_Release(attached);
+        i++;
+    }
 
     /* Return the surface */
     *Surface = surf->WineD3DSurface;
@@ -1625,7 +1756,7 @@ ULONG WINAPI D3D7CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) {
     IUnknown* surfaceParent;
     TRACE("(%p) call back\n", pSurface);
 
-    IWineD3DSurface_GetParent(pSurface, (IUnknown **) &surfaceParent);
+    IWineD3DSurface_GetParent(pSurface, &surfaceParent);
     IUnknown_Release(surfaceParent);
     return IUnknown_Release(surfaceParent);
 }
@@ -1720,7 +1851,7 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
             IDirectDrawImpl_RecreateAllSurfaces(This);
             TRACE("(%p) Done recreating all surfaces\n", This);
         }
-        else if(This->ImplType != SURFACE_OPENGL)
+        else if(This->ImplType != SURFACE_OPENGL && pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
         {
             WARN("The application requests a 3D capable surface, but a non-opengl surface was set in the registry\n");
             /* Do not fail surface creation, only fail 3D device creation */
@@ -1735,14 +1866,13 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
         Usage |= WINED3DUSAGE_RENDERTARGET;
 
         pDDSD->ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY |
-                                 DDSCAPS_VISIBLE     |
-                                 DDSCAPS_LOCALVIDMEM;
+                                 DDSCAPS_VISIBLE;
     }
     if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_OVERLAY))
     {
         Usage |= WINED3DUSAGE_OVERLAY;
     }
-    if(This->depthstencil)
+    if(This->depthstencil || (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) )
     {
         /* The depth stencil creation callback sets this flag.
          * Set the WineD3D usage to let it know that it's a depth
@@ -1757,6 +1887,15 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
     else if(pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
     {
         Pool = WINED3DPOOL_MANAGED;
+        /* Managed textures have the system memory flag set */
+        pDDSD->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
+    }
+    else if(pDDSD->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
+    {
+        /* Videomemory adds localvidmem, this is mutually exclusive with systemmemory
+         * and texturemanage
+         */
+        pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM;
     }
 
     Format = PixelFormat_DD2WineD3D(&pDDSD->u4.ddpfPixelFormat);
@@ -1789,9 +1928,6 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
     (*ppSurf)->next_attached = NULL;
     (*ppSurf)->first_attached = *ppSurf;
 
-    (*ppSurf)->next_complex = NULL;
-    (*ppSurf)->first_complex = *ppSurf;
-
     /* Needed to re-create the surface on an implementation change */
     (*ppSurf)->ImplType = ImplType;
 
@@ -1898,10 +2034,27 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
 
     /* Anno 1602 stores the pitch right after surface creation, so make sure it's there.
      * I can't LockRect() the surface here because if OpenGL surfaces are in use, the
-     * WineD3DDevice might not be useable for 3D yet, so an extra method was created
+     * WineD3DDevice might not be usable for 3D yet, so an extra method was created.
+     * TODO: Test other fourcc formats
      */
-    (*ppSurf)->surface_desc.dwFlags |= DDSD_PITCH;
-    (*ppSurf)->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch((*ppSurf)->WineD3DSurface);
+    if(Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
+       Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5)
+    {
+        (*ppSurf)->surface_desc.dwFlags |= DDSD_LINEARSIZE;
+        if(Format == WINED3DFMT_DXT1)
+        {
+            (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height) / 2;
+        }
+        else
+        {
+            (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height);
+        }
+    }
+    else
+    {
+        (*ppSurf)->surface_desc.dwFlags |= DDSD_PITCH;
+        (*ppSurf)->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch((*ppSurf)->WineD3DSurface);
+    }
 
     /* Application passed a color key? Set it! */
     if(pDDSD->dwFlags & DDSD_CKDESTOVERLAY)
@@ -1941,6 +2094,78 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
 
     return DD_OK;
 }
+/*****************************************************************************
+ * CreateAdditionalSurfaces
+ *
+ * Creates a new mipmap chain.
+ *
+ * Params:
+ *  root: Root surface to attach the newly created chain to
+ *  count: number of surfaces to create
+ *  DDSD: Description of the surface. Intentionally not a pointer to avoid side
+ *        effects on the caller
+ *  CubeFaceRoot: Whether the new surface is a root of a cube map face. This
+ *                creates an additional surface without the mipmapping flags
+ *
+ *****************************************************************************/
+static HRESULT
+CreateAdditionalSurfaces(IDirectDrawImpl *This,
+                         IDirectDrawSurfaceImpl *root,
+                         UINT count,
+                         DDSURFACEDESC2 DDSD,
+                         BOOL CubeFaceRoot)
+{
+    UINT i, j, level = 0;
+    HRESULT hr;
+    IDirectDrawSurfaceImpl *last = root;
+
+    for(i = 0; i < count; i++)
+    {
+        IDirectDrawSurfaceImpl *object2 = NULL;
+
+        /* increase the mipmap level, but only if a mipmap is created
+         * In this case, also halve the size
+         */
+        if(DDSD.ddsCaps.dwCaps & DDSCAPS_MIPMAP && !CubeFaceRoot)
+        {
+            level++;
+            if(DDSD.dwWidth > 1) DDSD.dwWidth /= 2;
+            if(DDSD.dwHeight > 1) DDSD.dwHeight /= 2;
+            /* Set the mipmap sublevel flag according to msdn */
+            DDSD.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
+        }
+        else
+        {
+            DDSD.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
+        }
+        CubeFaceRoot = FALSE;
+
+        hr = IDirectDrawImpl_CreateNewSurface(This,
+                                              &DDSD,
+                                              &object2,
+                                              level);
+        if(hr != DD_OK)
+        {
+            return hr;
+        }
+
+        /* Add the new surface to the complex attachment array */
+        for(j = 0; j < MAX_COMPLEX_ATTACHED; j++)
+        {
+            if(last->complex_array[j]) continue;
+            last->complex_array[j] = object2;
+            break;
+        }
+        last = object2;
+
+        /* Remove the (possible) back buffer cap from the new surface description,
+         * because only one surface in the flipping chain is a back buffer, one
+         * is a front buffer, the others are just primary surfaces.
+         */
+        DDSD.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
+    }
+    return DD_OK;
+}
 
 /*****************************************************************************
  * IDirectDraw7::CreateSurface
@@ -1961,12 +2186,12 @@ IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
  * the WineD3DSurface when the ddraw surface is destroyed.
  *
  * However, for all surfaces which can be in a container in WineD3D,
- * we have to do this. These surfaces are ususally complex surfaces,
+ * we have to do this. These surfaces are usually complex surfaces,
  * so this concerns primary surfaces with a front and a back buffer,
  * and textures.
  *
  * |------------------------|               |-----------------|
- * | DDraw surface          |               | Containter      |
+ * | DDraw surface          |               | Container       |
  * |                        |               |                 |
  * |                  Child |<------------->| Parent          |
  * |                Texture |<------------->|                 |
@@ -2028,9 +2253,8 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
     IDirectDrawSurfaceImpl *object = NULL;
     HRESULT hr;
-    LONG extra_surfaces = 0, i;
+    LONG extra_surfaces = 0;
     DDSURFACEDESC2 desc2;
-    UINT level = 0;
     WINED3DDISPLAYMODE Mode;
 
     TRACE("(%p)->(%p,%p,%p)\n", This, DDSD, Surf, UnkOuter);
@@ -2041,13 +2265,22 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         TRACE(" (%p) Requesting surface desc :\n", This);
         DDRAW_dump_surface_desc(DDSD);
     }
+    EnterCriticalSection(&ddraw_cs);
 
     if (UnkOuter != NULL)
     {
         FIXME("(%p) : outer != NULL?\n", This);
+        LeaveCriticalSection(&ddraw_cs);
         return CLASS_E_NOAGGREGATION; /* unchecked */
     }
 
+    if (Surf == NULL)
+    {
+        FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", This);
+        LeaveCriticalSection(&ddraw_cs);
+        return E_POINTER; /* unchecked */
+    }
+
     if (!(DDSD->dwFlags & DDSD_CAPS))
     {
         /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
@@ -2077,13 +2310,39 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
     {
         TRACE("(%p): Attempt to create a flipable primary surface without DDSCL_EXCLUSIVE set\n", This);
         *Surf = NULL;
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_NOEXCLUSIVEMODE;
     }
 
-    if (Surf == NULL)
+    if(DDSD->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER)) {
+        WARN("Application tried to create an explicit front or back buffer\n");
+        LeaveCriticalSection(&ddraw_cs);
+        return DDERR_INVALIDCAPS;
+    }
+    /* Check cube maps but only if the size includes them */
+    if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
     {
-        FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", This);
-        return E_POINTER; /* unchecked */
+        if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES &&
+           !(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
+        {
+            WARN("Cube map faces requested without cube map flag\n");
+            LeaveCriticalSection(&ddraw_cs);
+            return DDERR_INVALIDCAPS;
+        }
+        if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
+           (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) == 0)
+        {
+            WARN("Cube map without faces requested\n");
+            LeaveCriticalSection(&ddraw_cs);
+            return DDERR_INVALIDPARAMS;
+        }
+
+        /* Quick tests confirm those can be created, but we don't do that yet */
+        if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
+           (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) != DDSCAPS2_CUBEMAP_ALLFACES)
+        {
+            FIXME("Partial cube maps not supported yet\n");
+        }
     }
 
     /* According to the msdn this flag is ignored by CreateSurface */
@@ -2163,43 +2422,23 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         }
     }
 
-    /* No Width or no Height? Use the current window size or
-     * the original screen size
+    /* No Width or no Height? Use the original screen size
      */
     if(!(desc2.dwFlags & DDSD_WIDTH) ||
        !(desc2.dwFlags & DDSD_HEIGHT) )
     {
-        HWND window;
+        /* Invalid for non-render targets */
+        if(!(desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
+        {
+            WARN("Creating a non-Primary surface without Width or Height info, returning DDERR_INVALIDPARAMS\n");
+            *Surf = NULL;
+            LeaveCriticalSection(&ddraw_cs);
+            return DDERR_INVALIDPARAMS;
+        }
 
-        /* Fallback: From WineD3D / original mode */
         desc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
         desc2.dwWidth = Mode.Width;
         desc2.dwHeight = Mode.Height;
-
-        hr = IWineD3DDevice_GetHWND(This->wineD3DDevice,
-                                    &window);
-        if( (hr == D3D_OK) && (window != 0) )
-        {
-            RECT rect;
-            if(GetWindowRect(window, &rect) )
-            {
-                /* This is a hack until I find a better solution */
-                if( (rect.right - rect.left) <= 1 ||
-                    (rect.bottom - rect.top) <= 1 )
-                {
-                    FIXME("Wanted to get surface dimensions from window %p, but it has only "
-                           "a size of %dx%d. Using full screen dimensions\n",
-                           window, rect.right - rect.left, rect.bottom - rect.top);
-                }
-                else
-                {
-                    /* Not sure if this is correct */
-                    desc2.dwWidth = rect.right - rect.left;
-                    desc2.dwHeight = rect.bottom - rect.top;
-                    TRACE("Using window %p's dimensions: %dx%d\n", window, desc2.dwWidth, desc2.dwHeight);
-                }
-            }
-        }
     }
 
     /* Mipmap count fixes */
@@ -2209,7 +2448,12 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         {
             if(desc2.dwFlags & DDSD_MIPMAPCOUNT)
             {
-                /* Mipmap count is given, nothing to do */
+                /* Mipmap count is given, should not be 0 */
+                if( desc2.u2.dwMipMapCount == 0 )
+                {
+                    LeaveCriticalSection(&ddraw_cs);
+                    return DDERR_INVALIDPARAMS;
+                }
             }
             else
             {
@@ -2244,13 +2488,22 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER;
     }
 
+    /* The root surface in a cube map is positive x */
+    if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
+    {
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
+    }
+
     /* Create the first surface */
     hr = IDirectDrawImpl_CreateNewSurface(This, &desc2, &object, 0);
     if( hr != DD_OK)
     {
         ERR("IDirectDrawImpl_CreateNewSurface failed with %08x\n", hr);
+        LeaveCriticalSection(&ddraw_cs);
         return hr;
     }
+    object->is_complex_root = TRUE;
 
     *Surf = ICOM_INTERFACE(object, IDirectDrawSurface7);
 
@@ -2265,56 +2518,38 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         desc2.ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER; /* It's not a front buffer */
         desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
     }
-    /* Set the DDSCAPS2_MIPMAPSUBLEVEL flag on mipmap sublevels according to the msdn */
-    if(DDSD->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
-    {
-        desc2.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
-    }
 
-    for(i = 0; i < extra_surfaces; i++)
+    hr = DD_OK;
+    if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
+    {
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEZ;
+        hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEZ;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEZ;
+        hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEZ;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEY;
+        hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEY;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEY;
+        hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEY;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEX;
+        hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
+        desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEX;
+        desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
+    }
+
+    hr |= CreateAdditionalSurfaces(This, object, extra_surfaces, desc2, FALSE);
+    if(hr != DD_OK)
     {
-        IDirectDrawSurfaceImpl *object2 = NULL;
-        IDirectDrawSurfaceImpl *iterator;
-
-        /* increase the mipmap level, but only if a mipmap is created
-         * In this case, also halve the size
-         */
-        if(DDSD->ddsCaps.dwCaps & DDSCAPS_MIPMAP)
-        {
-            level++;
-            if(desc2.dwWidth > 1) desc2.dwWidth /= 2;
-            if(desc2.dwHeight > 1) desc2.dwHeight /= 2;
-        }
-
-        hr = IDirectDrawImpl_CreateNewSurface(This,
-                                              &desc2,
-                                              &object2,
-                                              level);
-        if(hr != DD_OK)
-        {
-            /* This destroys and possibly created surfaces too */
-            IDirectDrawSurface_Release( ICOM_INTERFACE(object, IDirectDrawSurface7) );
-            return hr;
-        }
-
-        /* Add the new surface to the complex attachment list */
-        object2->first_complex = object;
-        object2->next_complex = NULL;
-        iterator = object;
-        while(iterator->next_complex) iterator = iterator->next_complex;
-        iterator->next_complex = object2;
-
-        /* Remove the (possible) back buffer cap from the new surface description,
-         * because only one surface in the flipping chain is a back buffer, one
-         * is a front buffer, the others are just primary surfaces.
-         */
-        desc2.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
+        /* This destroys and possibly created surfaces too */
+        IDirectDrawSurface_Release( ICOM_INTERFACE(object, IDirectDrawSurface7) );
+        LeaveCriticalSection(&ddraw_cs);
+        return hr;
     }
 
-    /* Addref the ddraw interface to keep an reference for each surface */
-    IDirectDraw7_AddRef(iface);
-    object->ifaceToRelease = (IUnknown *) iface;
-
     /* If the implementation is OpenGL and there's no d3ddevice, attach a d3ddevice
      * But attach the d3ddevice only if the currently created surface was
      * a primary surface (2D app in 3D mode) or a 3DDEVICE surface (3D app)
@@ -2333,7 +2568,8 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         LIST_FOR_EACH(entry, &This->surface_list)
         {
             surface = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
-            if(surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
+            if((surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER)) ==
+               (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER))
             {
                 /* found */
                 target = surface;
@@ -2343,15 +2579,37 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         }
 
         TRACE("(%p) Attaching a D3DDevice, rendertarget = %p\n", This, target);
-        hr = IDirectDrawImpl_AttachD3DDevice(This, target->first_complex);
+        hr = IDirectDrawImpl_AttachD3DDevice(This, target);
         if(hr != D3D_OK)
         {
+            IDirectDrawSurfaceImpl *release_surf;
             ERR("IDirectDrawImpl_AttachD3DDevice failed, hr = %x\n", hr);
+            *Surf = NULL;
+
+            /* The before created surface structures are in an incomplete state here.
+             * WineD3D holds the reference on the IParents, and it released them on the failure
+             * already. So the regular release method implementation would fail on the attempt
+             * to destroy either the IParents or the swapchain. So free the surface here.
+             * The surface structure here is a list, not a tree, because onscreen targets
+             * cannot be cube textures
+             */
+            while(object)
+            {
+                release_surf = object;
+                object = object->complex_array[0];
+                IDirectDrawSurfaceImpl_Destroy(release_surf);
+            }
+            LeaveCriticalSection(&ddraw_cs);
+            return hr;
         }
     }
 
+    /* Addref the ddraw interface to keep an reference for each surface */
+    IDirectDraw7_AddRef(iface);
+    object->ifaceToRelease = (IUnknown *) iface;
+
     /* Create a WineD3DTexture if a texture was requested */
-    if(DDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
+    if(desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
     {
         UINT levels;
         WINED3DFORMAT Format;
@@ -2375,7 +2633,7 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         {
             Pool = WINED3DPOOL_SYSTEMMEM;
         }
-        /* Should I forward the MANEGED cap to the managed pool ? */
+        /* Should I forward the MANAGED cap to the managed pool ? */
 
         /* Get the format. It's set already by CreateNewSurface */
         Format = PixelFormat_DD2WineD3D(&object->surface_desc.u4.ddpfPixelFormat);
@@ -2383,19 +2641,36 @@ IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
         /* The surfaces are already created, the callback only
          * passes the IWineD3DSurface to WineD3D
          */
-        hr = IWineD3DDevice_CreateTexture( This->wineD3DDevice,
-                                           DDSD->dwWidth, DDSD->dwHeight,
-                                           levels, /* MipMapCount = Levels */
-                                           0, /* usage */
-                                           Format,
-                                           Pool,
-                                           &object->wineD3DTexture,
-                                           0, /* SharedHandle */
-                                           (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
-                                           D3D7CB_CreateSurface );
+        if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
+        {
+            hr = IWineD3DDevice_CreateCubeTexture(This->wineD3DDevice,
+                                                  DDSD->dwWidth, /* Edgelength */
+                                                  levels,
+                                                  0, /* usage */
+                                                  Format,
+                                                  Pool,
+                                                  (IWineD3DCubeTexture **) &object->wineD3DTexture,
+                                                  0, /* SharedHandle */
+                                                  (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
+                                                  D3D7CB_CreateSurface);
+        }
+        else
+        {
+            hr = IWineD3DDevice_CreateTexture(This->wineD3DDevice,
+                                              DDSD->dwWidth, DDSD->dwHeight,
+                                              levels, /* MipMapCount = Levels */
+                                              0, /* usage */
+                                              Format,
+                                              Pool,
+                                              (IWineD3DTexture **) &object->wineD3DTexture,
+                                              0, /* SharedHandle */
+                                              (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
+                                              D3D7CB_CreateSurface );
+        }
         This->tex_root = NULL;
     }
 
+    LeaveCriticalSection(&ddraw_cs);
     return hr;
 }
 
@@ -2555,9 +2830,13 @@ IDirectDrawImpl_EnumSurfaces(IDirectDraw7 *iface,
     nomatch = Flags & DDENUMSURFACES_NOMATCH;
 
     TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, DDSD, Context, Callback);
+    EnterCriticalSection(&ddraw_cs);
 
     if(!Callback)
+    {
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_INVALIDPARAMS;
+    }
 
     /* Use the _SAFE enumeration, the app may destroy enumerated surfaces */
     LIST_FOR_EACH_SAFE(entry, entry2, &This->surface_list)
@@ -2568,9 +2847,13 @@ IDirectDrawImpl_EnumSurfaces(IDirectDraw7 *iface,
             desc = surf->surface_desc;
             IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
             if(Callback( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, Context) != DDENUMRET_OK)
+            {
+                LeaveCriticalSection(&ddraw_cs);
                 return DD_OK;
+            }
         }
     }
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -2628,7 +2911,7 @@ D3D7CB_CreateRenderTarget(IUnknown *device, IUnknown *pSuperior,
                           HANDLE* pSharedHandle)
 {
     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
-    IDirectDrawSurfaceImpl *d3dSurface = This->d3d_target->first_complex, *target = NULL;
+    IDirectDrawSurfaceImpl *d3dSurface = This->d3d_target, *target = NULL;
     TRACE("(%p) call back\n", device);
 
     if(d3dSurface->isRenderTarget)
@@ -2825,7 +3108,7 @@ IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This,
     localParameters.SwapEffect                      = WINED3DSWAPEFFECT_COPY;
     localParameters.hDeviceWindow                   = window;
     localParameters.Windowed                        = !(This->cooperative_level & DDSCL_FULLSCREEN);
-    localParameters.EnableAutoDepthStencil          = FALSE;
+    localParameters.EnableAutoDepthStencil          = TRUE;
     localParameters.AutoDepthStencilFormat          = WINED3DFMT_D16;
     localParameters.Flags                           = 0;
     localParameters.FullScreen_RefreshRateInHz      = WINED3DPRESENT_RATE_DEFAULT; /* Default rate: It's already set */
@@ -2843,10 +3126,25 @@ IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This,
                                D3D7CB_CreateAdditionalSwapChain);
     if(FAILED(hr))
     {
-        This->wineD3DDevice = NULL;
+        This->d3d_target = NULL;
+        This->d3d_initialized = FALSE;
         return hr;
     }
 
+    This->declArraySize = 2;
+    This->decls = HeapAlloc(GetProcessHeap(),
+                            HEAP_ZERO_MEMORY,
+                            sizeof(*This->decls) * This->declArraySize);
+    if(!This->decls)
+    {
+        ERR("Error allocating an array for the converted vertex decls\n");
+        This->declArraySize = 0;
+        hr = IWineD3DDevice_Uninit3D(This->wineD3DDevice,
+                                     D3D7CB_DestroyDepthStencilSurface,
+                                     D3D7CB_DestroySwapChain);
+        return E_OUTOFMEMORY;
+    }
+
     /* Create an Index Buffer parent */
     TRACE("(%p) Successfully initialized 3D\n", This);
     return DD_OK;
@@ -2869,24 +3167,39 @@ IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This,
  *****************************************************************************/
 HRESULT WINAPI
 DirectDrawCreateClipper(DWORD Flags,
-                        IDirectDrawClipper **Clipper,
+                        LPDIRECTDRAWCLIPPER *Clipper,
                         IUnknown *UnkOuter)
 {
     IDirectDrawClipperImpl* object;
     TRACE("(%08x,%p,%p)\n", Flags, Clipper, UnkOuter);
 
-    if (UnkOuter != NULL) return CLASS_E_NOAGGREGATION;
+    EnterCriticalSection(&ddraw_cs);
+    if (UnkOuter != NULL)
+    {
+        LeaveCriticalSection(&ddraw_cs);
+        return CLASS_E_NOAGGREGATION;
+    }
 
     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
                      sizeof(IDirectDrawClipperImpl));
-    if (object == NULL) return E_OUTOFMEMORY;
+    if (object == NULL)
+    {
+        LeaveCriticalSection(&ddraw_cs);
+        return E_OUTOFMEMORY;
+    }
 
     ICOM_INIT_INTERFACE(object, IDirectDrawClipper, IDirectDrawClipper_Vtbl);
     object->ref = 1;
-    object->hWnd = 0;
-    object->ddraw_owner = NULL;
+    object->wineD3DClipper = pWineDirect3DCreateClipper((IUnknown *) object);
+    if(!object->wineD3DClipper)
+    {
+        HeapFree(GetProcessHeap(), 0, object);
+        LeaveCriticalSection(&ddraw_cs);
+        return E_OUTOFMEMORY;
+    }
 
     *Clipper = (IDirectDrawClipper *) object;
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -2936,9 +3249,11 @@ IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
     HRESULT hr = DDERR_GENERIC;
     TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, ColorTable, Palette, pUnkOuter);
 
+    EnterCriticalSection(&ddraw_cs);
     if(pUnkOuter != NULL)
     {
         WARN("pUnkOuter is %p, returning CLASS_E_NOAGGREGATION\n", pUnkOuter);
+        LeaveCriticalSection(&ddraw_cs);
         return CLASS_E_NOAGGREGATION;
     }
 
@@ -2946,6 +3261,7 @@ IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
     if(!This->cooperative_level)
     {
         WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
+        LeaveCriticalSection(&ddraw_cs);
         return DDERR_NOCOOPERATIVELEVELSET;
     }
 
@@ -2953,6 +3269,7 @@ IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
     if(!object)
     {
         ERR("Out of memory when allocating memory for a palette implementation\n");
+        LeaveCriticalSection(&ddraw_cs);
         return E_OUTOFMEMORY;
     }
 
@@ -2964,12 +3281,14 @@ IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
     if(hr != DD_OK)
     {
         HeapFree(GetProcessHeap(), 0, object);
+        LeaveCriticalSection(&ddraw_cs);
         return hr;
     }
 
     IDirectDraw7_AddRef(iface);
     object->ifaceToRelease = (IUnknown *) iface;
     *Palette = ICOM_INTERFACE(object, IDirectDrawPalette);
+    LeaveCriticalSection(&ddraw_cs);
     return DD_OK;
 }
 
@@ -3057,7 +3376,7 @@ const IDirectDraw7Vtbl IDirectDraw7_Vtbl =
  *
  * This function is in ddraw.c and the DDraw object space because D3D7
  * vertex buffers are created using the IDirect3D interface to the ddraw
- * object, so they can be valid accross D3D devices(theoretically. The ddraw
+ * object, so they can be valid across D3D devices(theoretically. The ddraw
  * object also owns the wined3d device
  *
  * Parameters: