~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ddraw/surface.c

Version: ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /* DirectDraw Surface Implementation
  2  *
  3  * Copyright (c) 1997-2000 Marcus Meissner
  4  * Copyright (c) 1998-2000 Lionel Ulmer
  5  * Copyright (c) 2000-2001 TransGaming Technologies Inc.
  6  * Copyright (c) 2006 Stefan Dösinger
  7  *
  8  * This file contains the (internal) driver registration functions,
  9  * driver enumeration APIs and DirectDraw creation functions.
 10  *
 11  * This library is free software; you can redistribute it and/or
 12  * modify it under the terms of the GNU Lesser General Public
 13  * License as published by the Free Software Foundation; either
 14  * version 2.1 of the License, or (at your option) any later version.
 15  *
 16  * This library is distributed in the hope that it will be useful,
 17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 19  * Lesser General Public License for more details.
 20  *
 21  * You should have received a copy of the GNU Lesser General Public
 22  * License along with this library; if not, write to the Free Software
 23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 24  */
 25 
 26 #include "config.h"
 27 #include "wine/port.h"
 28 
 29 #include <assert.h>
 30 #include <stdarg.h>
 31 #include <string.h>
 32 #include <stdlib.h>
 33 
 34 #define COBJMACROS
 35 #define NONAMELESSUNION
 36 
 37 #include "windef.h"
 38 #include "winbase.h"
 39 #include "winerror.h"
 40 #include "wingdi.h"
 41 #include "wine/exception.h"
 42 
 43 #include "ddraw.h"
 44 #include "d3d.h"
 45 
 46 #include "ddraw_private.h"
 47 #include "wine/debug.h"
 48 
 49 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
 50 
 51 /*****************************************************************************
 52  * IUnknown parts follow
 53  *****************************************************************************/
 54 
 55 /*****************************************************************************
 56  * IDirectDrawSurface7::QueryInterface
 57  *
 58  * A normal QueryInterface implementation. For QueryInterface rules
 59  * see ddraw.c, IDirectDraw7::QueryInterface. This method
 60  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
 61  * in all versions, the IDirectDrawGammaControl interface and it can
 62  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
 63  *
 64  * Params:
 65  *  riid: The interface id queried for
 66  *  obj: Address to write the pointer to
 67  *
 68  * Returns:
 69  *  S_OK on success
 70  *  E_NOINTERFACE if the requested interface wasn't found
 71  *
 72  *****************************************************************************/
 73 static HRESULT WINAPI
 74 IDirectDrawSurfaceImpl_QueryInterface(IDirectDrawSurface7 *iface,
 75                                       REFIID riid,
 76                                       void **obj)
 77 {
 78     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
 79 
 80     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
 81     *obj = NULL;
 82 
 83     if(!riid)
 84         return DDERR_INVALIDPARAMS;
 85 
 86     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),obj);
 87     if (IsEqualGUID(riid, &IID_IUnknown)
 88      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
 89      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
 90     {
 91         IUnknown_AddRef(iface);
 92         *obj = ICOM_INTERFACE(This, IDirectDrawSurface7);
 93         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
 94         return S_OK;
 95     }
 96     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
 97           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
 98           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
 99     {
100         IUnknown_AddRef(iface);
101         *obj = ICOM_INTERFACE(This, IDirectDrawSurface3);
102         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
103         return S_OK;
104     }
105     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
106     {
107         IUnknown_AddRef(iface);
108         *obj = ICOM_INTERFACE(This, IDirectDrawGammaControl);
109         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
110         return S_OK;
111     }
112     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
113              IsEqualGUID(riid, &IID_IDirect3DHALDevice)||
114              IsEqualGUID(riid, &IID_IDirect3DRGBDevice) )
115     {
116         IDirect3DDevice7 *d3d;
117 
118         /* Call into IDirect3D7 for creation */
119         IDirect3D7_CreateDevice(ICOM_INTERFACE(This->ddraw, IDirect3D7),
120                                 riid,
121                                 ICOM_INTERFACE(This, IDirectDrawSurface7),
122                                 &d3d);
123 
124         *obj = COM_INTERFACE_CAST(IDirect3DDeviceImpl, IDirect3DDevice7, IDirect3DDevice, d3d);
125         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
126 
127         return S_OK;
128     }
129     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
130              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
131     {
132         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
133         {
134             *obj = ICOM_INTERFACE(This, IDirect3DTexture);
135             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
136         }
137         else
138         {
139             *obj = ICOM_INTERFACE(This, IDirect3DTexture2);
140             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
141         }
142         IUnknown_AddRef( (IUnknown *) *obj);
143         return S_OK;
144     }
145 
146     ERR("No interface\n");
147     return E_NOINTERFACE;
148 }
149 
150 /*****************************************************************************
151  * IDirectDrawSurface7::AddRef
152  *
153  * A normal addref implementation
154  *
155  * Returns:
156  *  The new refcount
157  *
158  *****************************************************************************/
159 static ULONG WINAPI
160 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
161 {
162     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
163     ULONG refCount = InterlockedIncrement(&This->ref);
164 
165     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
166     return refCount;
167 }
168 
169 /*****************************************************************************
170  * IDirectDrawSurfaceImpl_Destroy
171  *
172  * A helper function for IDirectDrawSurface7::Release
173  *
174  * Frees the surface, regardless of its refcount.
175  *  See IDirectDrawSurface7::Release for more information
176  *
177  * Params:
178  *  This: Surface to free
179  *
180  *****************************************************************************/
181 void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
182 {
183     TRACE("(%p)\n", This);
184 
185     /* Check the refcount and give a warning */
186     if(This->ref > 1)
187     {
188         /* This can happen when a complex surface is destroyed,
189          * because the 2nd surface was addref()ed when the app
190          * called GetAttachedSurface
191          */
192         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
193     }
194 
195     /* Check for attached surfaces and detach them */
196     if(This->first_attached != This)
197     {
198         /* Well, this shouldn't happen: The surface being attached is addref()ed
199           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
200           * is called, because the refcount is held. It looks like the app released()
201           * it often enough to force this
202           */
203         IDirectDrawSurface7 *root = ICOM_INTERFACE(This->first_attached, IDirectDrawSurface7);
204         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This, IDirectDrawSurface7);
205 
206         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
207 
208         /* The refcount will drop to -1 here */
209         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
210         {
211             ERR("(%p) DeleteAttachedSurface failed!\n", This);
212         }
213     }
214 
215     while(This->next_attached != NULL)
216     {
217         IDirectDrawSurface7 *root = ICOM_INTERFACE(This, IDirectDrawSurface7);
218         IDirectDrawSurface7 *detach = ICOM_INTERFACE(This->next_attached, IDirectDrawSurface7);
219 
220         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
221         {
222             ERR("(%p) DeleteAttachedSurface failed!\n", This);
223             assert(0);
224         }
225     }
226 
227     /* Now destroy the surface. Wait: It could have been released if we are a texture */
228     if(This->WineD3DSurface)
229         IWineD3DSurface_Release(This->WineD3DSurface);
230 
231     /* Having a texture handle set implies that the device still exists */
232     if(This->Handle)
233     {
234         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
235         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
236     }
237 
238     /* Reduce the ddraw surface count */
239     InterlockedDecrement(&This->ddraw->surfaces);
240     list_remove(&This->surface_list_entry);
241 
242     HeapFree(GetProcessHeap(), 0, This);
243 }
244 
245 /*****************************************************************************
246  * IDirectDrawSurface7::Release
247  *
248  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
249  * surface is destroyed.
250  *
251  * Destroying the surface is a bit tricky. For the connection between
252  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
253  * It has a nice graph explaining the connection.
254  *
255  * What happens here is basically this:
256  * When a surface is destroyed, its WineD3DSurface is released,
257  * and the refcount of the DirectDraw interface is reduced by 1. If it has
258  * complex surfaces attached to it, then these surfaces are destroyed too,
259  * regardless of their refcount. If any surface being destroyed has another
260  * surface attached to it (with a "soft" attachment, not complex), then
261  * this surface is detached with DeleteAttachedSurface.
262  *
263  * When the surface is a texture, the WineD3DTexture is released.
264  * If the surface is the Direct3D render target, then the D3D
265  * capabilities of the WineD3DDevice are uninitialized, which causes the
266  * swapchain to be released.
267  *
268  * When a complex sublevel falls to ref zero, then this is ignored.
269  *
270  * Returns:
271  *  The new refcount
272  *
273  *****************************************************************************/
274 static ULONG WINAPI
275 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
276 {
277     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
278     ULONG ref;
279     TRACE("(%p) : Releasing from %d\n", This, This->ref);
280     ref = InterlockedDecrement(&This->ref);
281 
282     if (ref == 0)
283     {
284 
285         IDirectDrawSurfaceImpl *surf;
286         IDirectDrawImpl *ddraw;
287         IUnknown *ifaceToRelease = This->ifaceToRelease;
288         UINT i;
289 
290         /* Complex attached surfaces are destroyed implicitly when the root is released */
291         EnterCriticalSection(&ddraw_cs);
292         if(!This->is_complex_root)
293         {
294             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
295             LeaveCriticalSection(&ddraw_cs);
296             return ref;
297         }
298         ddraw = This->ddraw;
299 
300         /* If it's a texture, destroy the WineD3DTexture.
301          * WineD3D will destroy the IParent interfaces
302          * of the sublevels, which destroys the WineD3DSurfaces.
303          * Set the surfaces to NULL to avoid destroying them again later
304          */
305         if(This->wineD3DTexture)
306         {
307             IWineD3DBaseTexture_Release(This->wineD3DTexture);
308         }
309         /* If it's the RenderTarget, destroy the d3ddevice */
310         else if(This->wineD3DSwapChain)
311         {
312             if((ddraw->d3d_initialized) && (This == ddraw->d3d_target)) {
313                 TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
314 
315                 /* Unset any index buffer, just to be sure */
316                 IWineD3DDevice_SetIndices(ddraw->wineD3DDevice, NULL);
317                 IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
318                 IWineD3DDevice_SetVertexDeclaration(ddraw->wineD3DDevice, NULL);
319                 for(i = 0; i < ddraw->numConvertedDecls; i++)
320                 {
321                     IWineD3DVertexDeclaration_Release(ddraw->decls[i].decl);
322                 }
323                 HeapFree(GetProcessHeap(), 0, ddraw->decls);
324                 ddraw->numConvertedDecls = 0;
325 
326                 if(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroyDepthStencilSurface, D3D7CB_DestroySwapChain) != D3D_OK)
327                 {
328                     /* Not good */
329                     ERR("(%p) Failed to uninit 3D\n", This);
330                 }
331                 else
332                 {
333                     /* Free the d3d window if one was created */
334                     if(ddraw->d3d_window != 0 && ddraw->d3d_window != ddraw->dest_window)
335                     {
336                         TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
337                         DestroyWindow(ddraw->d3d_window);
338                         ddraw->d3d_window = 0;
339                     }
340                     /* Unset the pointers */
341                 }
342 
343                 This->wineD3DSwapChain = NULL; /* Uninit3D releases the swapchain */
344                 ddraw->d3d_initialized = FALSE;
345                 ddraw->d3d_target = NULL;
346             } else {
347                 IWineD3DDevice_UninitGDI(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain);
348                 This->wineD3DSwapChain = NULL;
349             }
350 
351             /* Reset to the default surface implementation type. This is needed if apps use
352              * non render target surfaces and expect blits to work after destroying the render
353              * target.
354              *
355              * TODO: Recreate existing offscreen surfaces
356              */
357             ddraw->ImplType = DefaultSurfaceType;
358 
359             /* Write a trace because D3D unloading was the reason for many
360              * crashes during development.
361              */
362             TRACE("(%p) D3D unloaded\n", This);
363         }
364         else if(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
365                                                      DDSCAPS_3DDEVICE       |
366                                                      DDSCAPS_TEXTURE        ) )
367         {
368             /* It's a render target, but no swapchain was created.
369              * The IParent interfaces have to be released manually.
370              * The same applies for textures without an
371              * IWineD3DTexture object attached
372              */
373             IParent *Parent;
374 
375             for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
376             {
377                 if(This->complex_array[i])
378                 {
379                     /* Only the topmost level can have more than 1 surfaces in the complex
380                      * attachment array(Cube texture roots), for all others there is only
381                      * one
382                      */
383                     surf = This->complex_array[i];
384                     while(surf)
385                     {
386                         IWineD3DSurface_GetParent(surf->WineD3DSurface,
387                                                   (IUnknown **) &Parent);
388                         IParent_Release(Parent);  /* For the getParent */
389                         IParent_Release(Parent);  /* To release it */
390                         surf = surf->complex_array[0];
391                     }
392                 }
393             }
394 
395             /* Now the top-level surface */
396             IWineD3DSurface_GetParent(This->WineD3DSurface,
397                                       (IUnknown **) &Parent);
398             IParent_Release(Parent);  /* For the getParent */
399             IParent_Release(Parent);  /* To release it */
400         }
401 
402         /* The refcount test shows that the palette is detached when the surface is destroyed */
403         IDirectDrawSurface7_SetPalette(ICOM_INTERFACE(This, IDirectDrawSurface7),
404                                                       NULL);
405 
406         /* Loop through all complex attached surfaces,
407          * and destroy them.
408          *
409          * Yet again, only the root can have more than one complexly attached surface, all the others
410          * have a total of one;
411          */
412         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
413         {
414             if(!This->complex_array[i]) break;
415 
416             surf = This->complex_array[i];
417             This->complex_array[i] = NULL;
418             while(surf)
419             {
420                 IDirectDrawSurfaceImpl *destroy = surf;
421                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
422                 IDirectDrawSurfaceImpl_Destroy(destroy);    /* Destroy it */
423             }
424         }
425 
426         /* Destroy the root surface.
427          */
428         IDirectDrawSurfaceImpl_Destroy(This);
429 
430         /* Reduce the ddraw refcount */
431         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
432         LeaveCriticalSection(&ddraw_cs);
433     }
434 
435     return ref;
436 }
437 
438 /*****************************************************************************
439  * IDirectDrawSurface7::GetAttachedSurface
440  *
441  * Returns an attached surface with the requested caps. Surface attachment
442  * and complex surfaces are not clearly described by the MSDN or sdk,
443  * so this method is tricky and likely to contain problems.
444  * This implementation searches the complex list first, then the
445  * attachment chain.
446  *
447  * The chains are searched from This down to the last surface in the chain,
448  * not from the first element in the chain. The first surface found is
449  * returned. The MSDN says that this method fails if more than one surface
450  * matches the caps, but it is not sure if that is right. The attachment
451  * structure may not even allow two matching surfaces.
452  *
453  * The found surface is AddRef-ed before it is returned.
454  *
455  * Params:
456  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
457  *  Surface: Address to store the found surface
458  *
459  * Returns:
460  *  DD_OK on success
461  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
462  *  DDERR_NOTFOUND if no surface was found
463  *
464  *****************************************************************************/
465 static HRESULT WINAPI
466 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
467                                           DDSCAPS2 *Caps,
468                                           IDirectDrawSurface7 **Surface)
469 {
470     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
471     IDirectDrawSurfaceImpl *surf;
472     DDSCAPS2 our_caps;
473     int i;
474 
475     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
476     EnterCriticalSection(&ddraw_cs);
477 
478     our_caps = *Caps;
479 
480     if(This->version < 7)
481     {
482         /* Earlier dx apps put garbage into these members, clear them */
483         our_caps.dwCaps2 = 0;
484         our_caps.dwCaps3 = 0;
485         our_caps.dwCaps4 = 0;
486     }
487 
488     TRACE("(%p): Looking for caps: %x,%x,%x,%x\n", This, our_caps.dwCaps, our_caps.dwCaps2, our_caps.dwCaps3, our_caps.dwCaps4); /* FIXME: Better debugging */
489 
490     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
491     {
492         surf = This->complex_array[i];
493         if(!surf) break;
494 
495         if (TRACE_ON(ddraw))
496         {
497             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
498                    surf->surface_desc.ddsCaps.dwCaps,
499                    surf->surface_desc.ddsCaps.dwCaps2,
500                    surf->surface_desc.ddsCaps.dwCaps3,
501                    surf->surface_desc.ddsCaps.dwCaps4);
502         }
503 
504         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
505             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
506 
507             /* MSDN: "This method fails if more than one surface is attached
508              * that matches the capabilities requested."
509              *
510              * Not sure how to test this.
511              */
512 
513             TRACE("(%p): Returning surface %p\n", This, surf);
514             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
515             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
516             IDirectDrawSurface7_AddRef(*Surface);
517             LeaveCriticalSection(&ddraw_cs);
518             return DD_OK;
519         }
520     }
521 
522     /* Next, look at the attachment chain */
523     surf = This;
524 
525     while( (surf = surf->next_attached) )
526     {
527         if (TRACE_ON(ddraw))
528         {
529             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
530                    surf->surface_desc.ddsCaps.dwCaps,
531                    surf->surface_desc.ddsCaps.dwCaps2,
532                    surf->surface_desc.ddsCaps.dwCaps3,
533                    surf->surface_desc.ddsCaps.dwCaps4);
534         }
535 
536         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
537             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
538 
539             TRACE("(%p): Returning surface %p\n", This, surf);
540             *Surface = ICOM_INTERFACE(surf, IDirectDrawSurface7);
541             IDirectDrawSurface7_AddRef(*Surface);
542             LeaveCriticalSection(&ddraw_cs);
543             return DD_OK;
544         }
545     }
546 
547     TRACE("(%p) Didn't find a valid surface\n", This);
548     LeaveCriticalSection(&ddraw_cs);
549 
550     *Surface = NULL;
551     return DDERR_NOTFOUND;
552 }
553 
554 /*****************************************************************************
555  * IDirectDrawSurface7::Lock
556  *
557  * Locks the surface and returns a pointer to the surface's memory
558  *
559  * Params:
560  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
561  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
562  *  Flags: Locking flags, e.g Read only or write only
563  *  h: An event handle that's not used and must be NULL
564  *
565  * Returns:
566  *  DD_OK on success
567  *  DDERR_INVALIDPARAMS if DDSD is NULL
568  *  For more details, see IWineD3DSurface::LockRect
569  *
570  *****************************************************************************/
571 static HRESULT WINAPI
572 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
573                             RECT *Rect,
574                             DDSURFACEDESC2 *DDSD,
575                             DWORD Flags,
576                             HANDLE h)
577 {
578     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
579     WINED3DLOCKED_RECT LockedRect;
580     HRESULT hr;
581     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
582 
583     if(!DDSD)
584         return DDERR_INVALIDPARAMS;
585 
586     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
587     EnterCriticalSection(&ddraw_cs);
588 
589     /* Should I check for the handle to be NULL?
590      *
591      * The DDLOCK flags and the D3DLOCK flags are equal
592      * for the supported values. The others are ignored by WineD3D
593      */
594 
595     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
596        DDSD->dwSize != sizeof(DDSURFACEDESC2))
597     {
598         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
599         LeaveCriticalSection(&ddraw_cs);
600         return DDERR_INVALIDPARAMS;
601     }
602 
603     /* Windows zeroes this if the rect is invalid */
604     DDSD->lpSurface = 0;
605 
606     if (Rect)
607     {
608         if ((Rect->left < 0)
609                 || (Rect->top < 0)
610                 || (Rect->left > Rect->right)
611                 || (Rect->top > Rect->bottom)
612                 || (Rect->right > This->surface_desc.dwWidth)
613                 || (Rect->bottom > This->surface_desc.dwHeight))
614         {
615             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
616             LeaveCriticalSection(&ddraw_cs);
617             return DDERR_INVALIDPARAMS;
618         }
619     }
620 
621     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
622                                   &LockedRect,
623                                   Rect,
624                                   Flags);
625     if(hr != D3D_OK)
626     {
627         LeaveCriticalSection(&ddraw_cs);
628         switch(hr)
629         {
630             /* D3D8 and D3D9 return the general D3DERR_INVALIDCALL error, but ddraw has a more
631              * specific error. But since IWineD3DSurface::LockRect returns that error in this
632              * only occasion, keep d3d8 and d3d9 free from the return value override. There are
633              * many different places where d3d8/9 would have to catch the DDERR_SURFACEBUSY, it
634              * is much easier to do it in one place in ddraw
635              */
636             case WINED3DERR_INVALIDCALL:    return DDERR_SURFACEBUSY;
637             default:                        return hr;
638         }
639     }
640 
641     /* Override the memory area. The pitch should be set already. Strangely windows
642      * does not set the LPSURFACE flag on locked surfaces !?!.
643      * DDSD->dwFlags |= DDSD_LPSURFACE;
644      */
645     This->surface_desc.lpSurface = LockedRect.pBits;
646     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
647 
648     TRACE("locked surface returning description :\n");
649     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
650 
651     LeaveCriticalSection(&ddraw_cs);
652     return DD_OK;
653 }
654 
655 /*****************************************************************************
656  * IDirectDrawSurface7::Unlock
657  *
658  * Unlocks an locked surface
659  *
660  * Params:
661  *  Rect: Not used by this implementation
662  *
663  * Returns:
664  *  D3D_OK on success
665  *  For more details, see IWineD3DSurface::UnlockRect
666  *
667  *****************************************************************************/
668 static HRESULT WINAPI
669 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
670                               RECT *pRect)
671 {
672     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
673     HRESULT hr;
674     TRACE("(%p)->(%p)\n", This, pRect);
675 
676     EnterCriticalSection(&ddraw_cs);
677     hr = IWineD3DSurface_UnlockRect(This->WineD3DSurface);
678     if(SUCCEEDED(hr))
679     {
680         This->surface_desc.lpSurface = NULL;
681     }
682     LeaveCriticalSection(&ddraw_cs);
683     return hr;
684 }
685 
686 /*****************************************************************************
687  * IDirectDrawSurface7::Flip
688  *
689  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
690  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
691  * the flip target is passed to WineD3D, even if the app didn't specify one
692  *
693  * Params:
694  *  DestOverride: Specifies the surface that will become the new front
695  *                buffer. If NULL, the current back buffer is used
696  *  Flags: some DirectDraw flags, see include/ddraw.h
697  *
698  * Returns:
699  *  DD_OK on success
700  *  DDERR_NOTFLIPPABLE if no flip target could be found
701  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
702  *  For more details, see IWineD3DSurface::Flip
703  *
704  *****************************************************************************/
705 static HRESULT WINAPI
706 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
707                             IDirectDrawSurface7 *DestOverride,
708                             DWORD Flags)
709 {
710     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
711     IDirectDrawSurfaceImpl *Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, DestOverride);
712     IDirectDrawSurface7 *Override7;
713     HRESULT hr;
714     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
715 
716     /* Flip has to be called from a front buffer
717      * What about overlay surfaces, AFAIK they can flip too?
718      */
719     if( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY)) )
720         return DDERR_INVALIDOBJECT; /* Unchecked */
721 
722     EnterCriticalSection(&ddraw_cs);
723 
724     /* WineD3D doesn't keep track of attached surface, so find the target */
725     if(!Override)
726     {
727         DDSCAPS2 Caps;
728 
729         memset(&Caps, 0, sizeof(Caps));
730         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
731         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
732         if(hr != DD_OK)
733         {
734             ERR("Can't find a flip target\n");
735             LeaveCriticalSection(&ddraw_cs);
736             return DDERR_NOTFLIPPABLE; /* Unchecked */
737         }
738         Override = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Override7);
739 
740         /* For the GetAttachedSurface */
741         IDirectDrawSurface7_Release(Override7);
742     }
743 
744     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
745                               Override->WineD3DSurface,
746                               Flags);
747     LeaveCriticalSection(&ddraw_cs);
748     return hr;
749 }
750 
751 /*****************************************************************************
752  * IDirectDrawSurface7::Blt
753  *
754  * Performs a blit on the surface
755  *
756  * Params:
757  *  DestRect: Destination rectangle, can be NULL
758  *  SrcSurface: Source surface, can be NULL
759  *  SrcRect: Source rectangle, can be NULL
760  *  Flags: Blt flags
761  *  DDBltFx: Some extended blt parameters, connected to the flags
762  *
763  * Returns:
764  *  D3D_OK on success
765  *  See IWineD3DSurface::Blt for more details
766  *
767  *****************************************************************************/
768 static HRESULT WINAPI
769 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
770                            RECT *DestRect,
771                            IDirectDrawSurface7 *SrcSurface,
772                            RECT *SrcRect,
773                            DWORD Flags,
774                            DDBLTFX *DDBltFx)
775 {
776     ICOM_THIS_FROM(IDirectDrawSurfaceImpl, IDirectDrawSurface7, iface);
777     HRESULT hr;
778     IDirectDrawSurfaceImpl *Src = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, SrcSurface);
779     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
780 
781     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
782      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
783      */
784     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
785         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
786         return DDERR_INVALIDPARAMS;
787     }
788 
789     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
790         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
791         return DDERR_INVALIDPARAMS;
792     }
793 
794     /* Sizes can change, therefore hold the lock when testing the rectangles */
795     EnterCriticalSection(&ddraw_cs);
796     if(DestRect)
797     {
798         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
799            DestRect->right > This->surface_desc.dwWidth ||
800            DestRect->bottom > This->surface_desc.dwHeight)
801         {
802             WARN("Destination rectangle is invalid, returning DDERR_INVALIDRECT\n");
803             LeaveCriticalSection(&ddraw_cs);
804             return DDERR_INVALIDRECT;
805         }
806     }
807     if(Src && SrcRect)
808     {
809         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
810            SrcRect->right > Src->surface_desc.dwWidth ||
811            SrcRect->bottom > Src->surface_desc.dwHeight)
812         {
813             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
814             LeaveCriticalSection(&ddraw_cs);
815             return DDERR_INVALIDRECT;
816         }
817     }
818 
819     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
820         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
821         LeaveCriticalSection(&ddraw_cs);
822         return DDERR_INVALIDPARAMS;
823     }
824 
825     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
826      * and replace the ddraw surfaces with the wined3d surfaces
827      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
828      */
829     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
830                              DestRect,
831                              Src ? Src->WineD3DSurface : NULL,
832                              SrcRect,
833                              Flags,
834                              (WINEDDBLTFX *) DDBltFx,
835                              WINED3DTEXF_POINT);
836 
837     LeaveCriticalSection(&ddraw_cs);
838     switch(hr)
839     {
840         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
841         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
842         default:                            return hr;
843     }
844 }
845 
846 /*****************************************************************************
847  * IDirectDrawSurface7::AddAttachedSurface
848  *
849  * Attaches a surface to another surface. How the surface attachments work
850  * is not totally understood yet, and this method is prone to problems.
851  * he surface that is attached is AddRef-ed.
852  *
853  * Tests with complex surfaces suggest that the surface attachments form a
854  * tree, but no method to test this has been found yet.
855  *
856  * The attachment list consists of a first surface (first_attached) and
857  * for each surface a pointer to the next attached surface (next_attached).
858  * For the first surface, and a surface that has no attachments
859  * first_attached points to the surface itself. A surface that has
860  * no successors in the chain has next_attached set to NULL.
861  *
862  * Newly attached surfaces are attached right after the root surface.
863  * If a surface is attached to a complex surface compound, it's attached to
864  * the surface that the app requested, not the complex root. See
865  * GetAttachedSurface for a description how surfaces are found.
866  *
867  * This is how the current implementation works, and it was coded by looking
868  * at the needs of the applications.
869  *
870  * So far only Z-Buffer attachments are tested, and they are activated in
871  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
872  * Back buffers should work in 2D mode, but they are not tested(They can be
873  * attached in older iface versions). Rendering to the front buffer and
874  * switching between that and double buffering is not yet implemented in
875  * WineD3D, so for 3D it might have unexpected results.
876  *
877  * IDirectDrawSurfaceImpl_AddAttachedSurface is the real thing,
878  * IDirectDrawSurface7Impl_AddAttachedSurface is a wrapper around it that
879  * performs additional checks. Version 7 of this interface is much more restrictive
880  * than its predecessors.
881  *
882  * Params:
883  *  Attach: Surface to attach to iface
884  *
885  * Returns:
886  *  DD_OK on success
887  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
888  *
889  *****************************************************************************/
890 HRESULT WINAPI
891 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurfaceImpl *This,
892                                           IDirectDrawSurfaceImpl *Surf)
893 {
894     TRACE("(%p)->(%p)\n", This, Surf);
895 
896     if(Surf == This)
897         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
898 
899     EnterCriticalSection(&ddraw_cs);
900 
901     /* Check if the surface is already attached somewhere */
902     if( (Surf->next_attached != NULL) ||
903         (Surf->first_attached != Surf) )
904     {
905         /* TODO: Test for the structure of the manual attachment. Is it a chain or a list?
906          * What happens if one surface is attached to 2 different surfaces?
907          */
908         FIXME("(%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);
909         LeaveCriticalSection(&ddraw_cs);
910         return DDERR_SURFACEALREADYATTACHED;
911     }
912 
913     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
914     Surf->next_attached = This->next_attached;
915     Surf->first_attached = This->first_attached;
916     This->next_attached = Surf;
917 
918     /* Check if the WineD3D depth stencil needs updating */
919     if(This->ddraw->d3ddevice)
920     {
921         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
922     }
923 
924     /* MSDN: 
925      * "This method increments the reference count of the surface being attached."
926      */
927     IDirectDrawSurface7_AddRef(ICOM_INTERFACE(Surf, IDirectDrawSurface7));
928     LeaveCriticalSection(&ddraw_cs);
929     return DD_OK;
930 }
931 
932 static HRESULT WINAPI
933