wined3d: Increment the buffer draw count if the buffer was clean.
[wine] / dlls / ddraw / surface.c
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     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)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 = iface;
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 = &This->IDirectDrawSurface3_vtbl;
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 = &This->IDirectDrawGammaControl_vtbl;
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((IDirect3D7 *)&This->ddraw->IDirect3D7_vtbl, riid, (IDirectDrawSurface7 *)This, &d3d);
120
121         *obj = d3d ? (IDirect3DDevice *)&((IDirect3DDeviceImpl *)d3d)->IDirect3DDevice_vtbl : NULL;
122         TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
123
124         return S_OK;
125     }
126     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
127              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
128     {
129         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
130         {
131             *obj = &This->IDirect3DTexture_vtbl;
132             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
133         }
134         else
135         {
136             *obj = &This->IDirect3DTexture2_vtbl;
137             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
138         }
139         IUnknown_AddRef( (IUnknown *) *obj);
140         return S_OK;
141     }
142
143     ERR("No interface\n");
144     return E_NOINTERFACE;
145 }
146
147 /*****************************************************************************
148  * IDirectDrawSurface7::AddRef
149  *
150  * A normal addref implementation
151  *
152  * Returns:
153  *  The new refcount
154  *
155  *****************************************************************************/
156 static ULONG WINAPI
157 IDirectDrawSurfaceImpl_AddRef(IDirectDrawSurface7 *iface)
158 {
159     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
160     ULONG refCount = InterlockedIncrement(&This->ref);
161
162     if (refCount == 1 && This->WineD3DSurface)
163     {
164         EnterCriticalSection(&ddraw_cs);
165         IWineD3DSurface_AddRef(This->WineD3DSurface);
166         LeaveCriticalSection(&ddraw_cs);
167     }
168
169     TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
170     return refCount;
171 }
172
173 /*****************************************************************************
174  * IDirectDrawSurfaceImpl_Destroy
175  *
176  * A helper function for IDirectDrawSurface7::Release
177  *
178  * Frees the surface, regardless of its refcount.
179  *  See IDirectDrawSurface7::Release for more information
180  *
181  * Params:
182  *  This: Surface to free
183  *
184  *****************************************************************************/
185 void IDirectDrawSurfaceImpl_Destroy(IDirectDrawSurfaceImpl *This)
186 {
187     TRACE("(%p)\n", This);
188
189     /* Check the refcount and give a warning */
190     if(This->ref > 1)
191     {
192         /* This can happen when a complex surface is destroyed,
193          * because the 2nd surface was addref()ed when the app
194          * called GetAttachedSurface
195          */
196         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
197     }
198
199     /* Check for attached surfaces and detach them */
200     if(This->first_attached != This)
201     {
202         /* Well, this shouldn't happen: The surface being attached is addref()ed
203           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
204           * is called, because the refcount is held. It looks like the app released()
205           * it often enough to force this
206           */
207         IDirectDrawSurface7 *root = (IDirectDrawSurface7 *)This->first_attached;
208         IDirectDrawSurface7 *detach = (IDirectDrawSurface7 *)This;
209
210         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
211
212         /* The refcount will drop to -1 here */
213         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
214         {
215             ERR("(%p) DeleteAttachedSurface failed!\n", This);
216         }
217     }
218
219     while(This->next_attached != NULL)
220     {
221         IDirectDrawSurface7 *root = (IDirectDrawSurface7 *)This;
222         IDirectDrawSurface7 *detach = (IDirectDrawSurface7 *)This->next_attached;
223
224         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
225         {
226             ERR("(%p) DeleteAttachedSurface failed!\n", This);
227             assert(0);
228         }
229     }
230
231     /* Now destroy the surface. Wait: It could have been released if we are a texture */
232     if(This->WineD3DSurface)
233         IWineD3DSurface_Release(This->WineD3DSurface);
234
235     /* Having a texture handle set implies that the device still exists */
236     if(This->Handle)
237     {
238         This->ddraw->d3ddevice->Handles[This->Handle - 1].ptr = NULL;
239         This->ddraw->d3ddevice->Handles[This->Handle - 1].type = DDrawHandle_Unknown;
240     }
241
242     /* Reduce the ddraw surface count */
243     InterlockedDecrement(&This->ddraw->surfaces);
244     list_remove(&This->surface_list_entry);
245
246     HeapFree(GetProcessHeap(), 0, This);
247 }
248
249 /*****************************************************************************
250  * IDirectDrawSurface7::Release
251  *
252  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
253  * surface is destroyed.
254  *
255  * Destroying the surface is a bit tricky. For the connection between
256  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
257  * It has a nice graph explaining the connection.
258  *
259  * What happens here is basically this:
260  * When a surface is destroyed, its WineD3DSurface is released,
261  * and the refcount of the DirectDraw interface is reduced by 1. If it has
262  * complex surfaces attached to it, then these surfaces are destroyed too,
263  * regardless of their refcount. If any surface being destroyed has another
264  * surface attached to it (with a "soft" attachment, not complex), then
265  * this surface is detached with DeleteAttachedSurface.
266  *
267  * When the surface is a texture, the WineD3DTexture is released.
268  * If the surface is the Direct3D render target, then the D3D
269  * capabilities of the WineD3DDevice are uninitialized, which causes the
270  * swapchain to be released.
271  *
272  * When a complex sublevel falls to ref zero, then this is ignored.
273  *
274  * Returns:
275  *  The new refcount
276  *
277  *****************************************************************************/
278 static ULONG WINAPI
279 IDirectDrawSurfaceImpl_Release(IDirectDrawSurface7 *iface)
280 {
281     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
282     ULONG ref;
283     TRACE("(%p) : Releasing from %d\n", This, This->ref);
284     ref = InterlockedDecrement(&This->ref);
285
286     if (ref == 0)
287     {
288
289         IDirectDrawSurfaceImpl *surf;
290         IDirectDrawImpl *ddraw;
291         IUnknown *ifaceToRelease = This->ifaceToRelease;
292         UINT i;
293
294         /* Complex attached surfaces are destroyed implicitly when the root is released */
295         EnterCriticalSection(&ddraw_cs);
296         if(!This->is_complex_root)
297         {
298             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
299             LeaveCriticalSection(&ddraw_cs);
300             return ref;
301         }
302         ddraw = This->ddraw;
303
304         /* If it's a texture, destroy the WineD3DTexture.
305          * WineD3D will destroy the IParent interfaces
306          * of the sublevels, which destroys the WineD3DSurfaces.
307          * Set the surfaces to NULL to avoid destroying them again later
308          */
309         if(This->wineD3DTexture)
310         {
311             IWineD3DBaseTexture_Release(This->wineD3DTexture);
312         }
313         /* If it's the RenderTarget, destroy the d3ddevice */
314         else if(This->wineD3DSwapChain)
315         {
316             if((ddraw->d3d_initialized) && (This == ddraw->d3d_target)) {
317                 TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
318
319                 /* Unset any index buffer, just to be sure */
320                 IWineD3DDevice_SetIndexBuffer(ddraw->wineD3DDevice, NULL, WINED3DFMT_UNKNOWN);
321                 IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
322                 IWineD3DDevice_SetVertexDeclaration(ddraw->wineD3DDevice, NULL);
323                 for(i = 0; i < ddraw->numConvertedDecls; i++)
324                 {
325                     IWineD3DVertexDeclaration_Release(ddraw->decls[i].decl);
326                 }
327                 HeapFree(GetProcessHeap(), 0, ddraw->decls);
328                 ddraw->numConvertedDecls = 0;
329
330                 if (FAILED(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain)))
331                 {
332                     /* Not good */
333                     ERR("(%p) Failed to uninit 3D\n", This);
334                 }
335                 else
336                 {
337                     /* Free the d3d window if one was created */
338                     if(ddraw->d3d_window != 0 && ddraw->d3d_window != ddraw->dest_window)
339                     {
340                         TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
341                         DestroyWindow(ddraw->d3d_window);
342                         ddraw->d3d_window = 0;
343                     }
344                     /* Unset the pointers */
345                 }
346
347                 This->wineD3DSwapChain = NULL; /* Uninit3D releases the swapchain */
348                 ddraw->d3d_initialized = FALSE;
349                 ddraw->d3d_target = NULL;
350             } else {
351                 IWineD3DDevice_UninitGDI(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain);
352                 This->wineD3DSwapChain = NULL;
353             }
354
355             /* Reset to the default surface implementation type. This is needed if apps use
356              * non render target surfaces and expect blits to work after destroying the render
357              * target.
358              *
359              * TODO: Recreate existing offscreen surfaces
360              */
361             ddraw->ImplType = DefaultSurfaceType;
362
363             /* Write a trace because D3D unloading was the reason for many
364              * crashes during development.
365              */
366             TRACE("(%p) D3D unloaded\n", This);
367         }
368
369         /* The refcount test shows that the palette is detached when the surface is destroyed */
370         IDirectDrawSurface7_SetPalette((IDirectDrawSurface7 *)This, NULL);
371
372         /* Loop through all complex attached surfaces,
373          * and destroy them.
374          *
375          * Yet again, only the root can have more than one complexly attached surface, all the others
376          * have a total of one;
377          */
378         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
379         {
380             if(!This->complex_array[i]) break;
381
382             surf = This->complex_array[i];
383             This->complex_array[i] = NULL;
384             while(surf)
385             {
386                 IDirectDrawSurfaceImpl *destroy = surf;
387                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
388                 IDirectDrawSurfaceImpl_Destroy(destroy);    /* Destroy it */
389             }
390         }
391
392         /* Destroy the root surface.
393          */
394         IDirectDrawSurfaceImpl_Destroy(This);
395
396         /* Reduce the ddraw refcount */
397         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
398         LeaveCriticalSection(&ddraw_cs);
399     }
400
401     return ref;
402 }
403
404 /*****************************************************************************
405  * IDirectDrawSurface7::GetAttachedSurface
406  *
407  * Returns an attached surface with the requested caps. Surface attachment
408  * and complex surfaces are not clearly described by the MSDN or sdk,
409  * so this method is tricky and likely to contain problems.
410  * This implementation searches the complex list first, then the
411  * attachment chain.
412  *
413  * The chains are searched from This down to the last surface in the chain,
414  * not from the first element in the chain. The first surface found is
415  * returned. The MSDN says that this method fails if more than one surface
416  * matches the caps, but it is not sure if that is right. The attachment
417  * structure may not even allow two matching surfaces.
418  *
419  * The found surface is AddRef-ed before it is returned.
420  *
421  * Params:
422  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
423  *  Surface: Address to store the found surface
424  *
425  * Returns:
426  *  DD_OK on success
427  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
428  *  DDERR_NOTFOUND if no surface was found
429  *
430  *****************************************************************************/
431 static HRESULT WINAPI
432 IDirectDrawSurfaceImpl_GetAttachedSurface(IDirectDrawSurface7 *iface,
433                                           DDSCAPS2 *Caps,
434                                           IDirectDrawSurface7 **Surface)
435 {
436     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
437     IDirectDrawSurfaceImpl *surf;
438     DDSCAPS2 our_caps;
439     int i;
440
441     TRACE("(%p)->(%p,%p)\n", This, Caps, Surface);
442     EnterCriticalSection(&ddraw_cs);
443
444     if(This->version < 7)
445     {
446         /* Earlier dx apps put garbage into these members, clear them */
447         our_caps.dwCaps = Caps->dwCaps;
448         our_caps.dwCaps2 = 0;
449         our_caps.dwCaps3 = 0;
450         our_caps.dwCaps4 = 0;
451     }
452     else
453     {
454         our_caps = *Caps;
455     }
456
457     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 */
458
459     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
460     {
461         surf = This->complex_array[i];
462         if(!surf) break;
463
464         if (TRACE_ON(ddraw))
465         {
466             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
467                    surf->surface_desc.ddsCaps.dwCaps,
468                    surf->surface_desc.ddsCaps.dwCaps2,
469                    surf->surface_desc.ddsCaps.dwCaps3,
470                    surf->surface_desc.ddsCaps.dwCaps4);
471         }
472
473         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
474             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
475
476             /* MSDN: "This method fails if more than one surface is attached
477              * that matches the capabilities requested."
478              *
479              * Not sure how to test this.
480              */
481
482             TRACE("(%p): Returning surface %p\n", This, surf);
483             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
484             *Surface = (IDirectDrawSurface7 *)surf;
485             IDirectDrawSurface7_AddRef(*Surface);
486             LeaveCriticalSection(&ddraw_cs);
487             return DD_OK;
488         }
489     }
490
491     /* Next, look at the attachment chain */
492     surf = This;
493
494     while( (surf = surf->next_attached) )
495     {
496         if (TRACE_ON(ddraw))
497         {
498             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
499                    surf->surface_desc.ddsCaps.dwCaps,
500                    surf->surface_desc.ddsCaps.dwCaps2,
501                    surf->surface_desc.ddsCaps.dwCaps3,
502                    surf->surface_desc.ddsCaps.dwCaps4);
503         }
504
505         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
506             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
507
508             TRACE("(%p): Returning surface %p\n", This, surf);
509             *Surface = (IDirectDrawSurface7 *)surf;
510             IDirectDrawSurface7_AddRef(*Surface);
511             LeaveCriticalSection(&ddraw_cs);
512             return DD_OK;
513         }
514     }
515
516     TRACE("(%p) Didn't find a valid surface\n", This);
517     LeaveCriticalSection(&ddraw_cs);
518
519     *Surface = NULL;
520     return DDERR_NOTFOUND;
521 }
522
523 /*****************************************************************************
524  * IDirectDrawSurface7::Lock
525  *
526  * Locks the surface and returns a pointer to the surface's memory
527  *
528  * Params:
529  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
530  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
531  *  Flags: Locking flags, e.g Read only or write only
532  *  h: An event handle that's not used and must be NULL
533  *
534  * Returns:
535  *  DD_OK on success
536  *  DDERR_INVALIDPARAMS if DDSD is NULL
537  *  For more details, see IWineD3DSurface::LockRect
538  *
539  *****************************************************************************/
540 static HRESULT WINAPI
541 IDirectDrawSurfaceImpl_Lock(IDirectDrawSurface7 *iface,
542                             RECT *Rect,
543                             DDSURFACEDESC2 *DDSD,
544                             DWORD Flags,
545                             HANDLE h)
546 {
547     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
548     WINED3DLOCKED_RECT LockedRect;
549     HRESULT hr;
550     TRACE("(%p)->(%p,%p,%x,%p)\n", This, Rect, DDSD, Flags, h);
551
552     if(!DDSD)
553         return DDERR_INVALIDPARAMS;
554
555     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
556     EnterCriticalSection(&ddraw_cs);
557
558     /* Should I check for the handle to be NULL?
559      *
560      * The DDLOCK flags and the D3DLOCK flags are equal
561      * for the supported values. The others are ignored by WineD3D
562      */
563
564     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
565        DDSD->dwSize != sizeof(DDSURFACEDESC2))
566     {
567         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
568         LeaveCriticalSection(&ddraw_cs);
569         return DDERR_INVALIDPARAMS;
570     }
571
572     /* Windows zeroes this if the rect is invalid */
573     DDSD->lpSurface = 0;
574
575     if (Rect)
576     {
577         if ((Rect->left < 0)
578                 || (Rect->top < 0)
579                 || (Rect->left > Rect->right)
580                 || (Rect->top > Rect->bottom)
581                 || (Rect->right > This->surface_desc.dwWidth)
582                 || (Rect->bottom > This->surface_desc.dwHeight))
583         {
584             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
585             LeaveCriticalSection(&ddraw_cs);
586             return DDERR_INVALIDPARAMS;
587         }
588     }
589
590     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
591                                   &LockedRect,
592                                   Rect,
593                                   Flags);
594     if(hr != D3D_OK)
595     {
596         LeaveCriticalSection(&ddraw_cs);
597         switch(hr)
598         {
599             /* D3D8 and D3D9 return the general D3DERR_INVALIDCALL error, but ddraw has a more
600              * specific error. But since IWineD3DSurface::LockRect returns that error in this
601              * only occasion, keep d3d8 and d3d9 free from the return value override. There are
602              * many different places where d3d8/9 would have to catch the DDERR_SURFACEBUSY, it
603              * is much easier to do it in one place in ddraw
604              */
605             case WINED3DERR_INVALIDCALL:    return DDERR_SURFACEBUSY;
606             default:                        return hr;
607         }
608     }
609
610     /* Override the memory area. The pitch should be set already. Strangely windows
611      * does not set the LPSURFACE flag on locked surfaces !?!.
612      * DDSD->dwFlags |= DDSD_LPSURFACE;
613      */
614     This->surface_desc.lpSurface = LockedRect.pBits;
615     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
616
617     TRACE("locked surface returning description :\n");
618     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
619
620     LeaveCriticalSection(&ddraw_cs);
621     return DD_OK;
622 }
623
624 /*****************************************************************************
625  * IDirectDrawSurface7::Unlock
626  *
627  * Unlocks an locked surface
628  *
629  * Params:
630  *  Rect: Not used by this implementation
631  *
632  * Returns:
633  *  D3D_OK on success
634  *  For more details, see IWineD3DSurface::UnlockRect
635  *
636  *****************************************************************************/
637 static HRESULT WINAPI
638 IDirectDrawSurfaceImpl_Unlock(IDirectDrawSurface7 *iface,
639                               RECT *pRect)
640 {
641     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
642     HRESULT hr;
643     TRACE("(%p)->(%p)\n", This, pRect);
644
645     EnterCriticalSection(&ddraw_cs);
646     hr = IWineD3DSurface_UnlockRect(This->WineD3DSurface);
647     if(SUCCEEDED(hr))
648     {
649         This->surface_desc.lpSurface = NULL;
650     }
651     LeaveCriticalSection(&ddraw_cs);
652     return hr;
653 }
654
655 /*****************************************************************************
656  * IDirectDrawSurface7::Flip
657  *
658  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
659  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
660  * the flip target is passed to WineD3D, even if the app didn't specify one
661  *
662  * Params:
663  *  DestOverride: Specifies the surface that will become the new front
664  *                buffer. If NULL, the current back buffer is used
665  *  Flags: some DirectDraw flags, see include/ddraw.h
666  *
667  * Returns:
668  *  DD_OK on success
669  *  DDERR_NOTFLIPPABLE if no flip target could be found
670  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
671  *  For more details, see IWineD3DSurface::Flip
672  *
673  *****************************************************************************/
674 static HRESULT WINAPI
675 IDirectDrawSurfaceImpl_Flip(IDirectDrawSurface7 *iface,
676                             IDirectDrawSurface7 *DestOverride,
677                             DWORD Flags)
678 {
679     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
680     IDirectDrawSurfaceImpl *Override = (IDirectDrawSurfaceImpl *)DestOverride;
681     IDirectDrawSurface7 *Override7;
682     HRESULT hr;
683     TRACE("(%p)->(%p,%x)\n", This, DestOverride, Flags);
684
685     /* Flip has to be called from a front buffer
686      * What about overlay surfaces, AFAIK they can flip too?
687      */
688     if( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY)) )
689         return DDERR_INVALIDOBJECT; /* Unchecked */
690
691     EnterCriticalSection(&ddraw_cs);
692
693     /* WineD3D doesn't keep track of attached surface, so find the target */
694     if(!Override)
695     {
696         DDSCAPS2 Caps;
697
698         memset(&Caps, 0, sizeof(Caps));
699         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
700         hr = IDirectDrawSurface7_GetAttachedSurface(iface, &Caps, &Override7);
701         if(hr != DD_OK)
702         {
703             ERR("Can't find a flip target\n");
704             LeaveCriticalSection(&ddraw_cs);
705             return DDERR_NOTFLIPPABLE; /* Unchecked */
706         }
707         Override = (IDirectDrawSurfaceImpl *)Override7;
708
709         /* For the GetAttachedSurface */
710         IDirectDrawSurface7_Release(Override7);
711     }
712
713     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
714                               Override->WineD3DSurface,
715                               Flags);
716     LeaveCriticalSection(&ddraw_cs);
717     return hr;
718 }
719
720 /*****************************************************************************
721  * IDirectDrawSurface7::Blt
722  *
723  * Performs a blit on the surface
724  *
725  * Params:
726  *  DestRect: Destination rectangle, can be NULL
727  *  SrcSurface: Source surface, can be NULL
728  *  SrcRect: Source rectangle, can be NULL
729  *  Flags: Blt flags
730  *  DDBltFx: Some extended blt parameters, connected to the flags
731  *
732  * Returns:
733  *  D3D_OK on success
734  *  See IWineD3DSurface::Blt for more details
735  *
736  *****************************************************************************/
737 static HRESULT WINAPI
738 IDirectDrawSurfaceImpl_Blt(IDirectDrawSurface7 *iface,
739                            RECT *DestRect,
740                            IDirectDrawSurface7 *SrcSurface,
741                            RECT *SrcRect,
742                            DWORD Flags,
743                            DDBLTFX *DDBltFx)
744 {
745     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
746     IDirectDrawSurfaceImpl *Src = (IDirectDrawSurfaceImpl *)SrcSurface;
747     HRESULT hr;
748     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, Src, SrcRect, Flags, DDBltFx);
749
750     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
751      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
752      */
753     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
754         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
755         return DDERR_INVALIDPARAMS;
756     }
757
758     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
759         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
760         return DDERR_INVALIDPARAMS;
761     }
762
763     /* Sizes can change, therefore hold the lock when testing the rectangles */
764     EnterCriticalSection(&ddraw_cs);
765     if(DestRect)
766     {
767         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
768            DestRect->right > This->surface_desc.dwWidth ||
769            DestRect->bottom > This->surface_desc.dwHeight)
770         {
771             WARN("Destination rectangle is invalid, returning DDERR_INVALIDRECT\n");
772             LeaveCriticalSection(&ddraw_cs);
773             return DDERR_INVALIDRECT;
774         }
775     }
776     if(Src && SrcRect)
777     {
778         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
779            SrcRect->right > Src->surface_desc.dwWidth ||
780            SrcRect->bottom > Src->surface_desc.dwHeight)
781         {
782             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
783             LeaveCriticalSection(&ddraw_cs);
784             return DDERR_INVALIDRECT;
785         }
786     }
787
788     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
789         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
790         LeaveCriticalSection(&ddraw_cs);
791         return DDERR_INVALIDPARAMS;
792     }
793
794     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
795      * and replace the ddraw surfaces with the wined3d surfaces
796      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
797      */
798     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
799                              DestRect,
800                              Src ? Src->WineD3DSurface : NULL,
801                              SrcRect,
802                              Flags,
803                              (WINEDDBLTFX *) DDBltFx,
804                              WINED3DTEXF_POINT);
805
806     LeaveCriticalSection(&ddraw_cs);
807     switch(hr)
808     {
809         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
810         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
811         default:                            return hr;
812     }
813 }
814
815 /*****************************************************************************
816  * IDirectDrawSurface7::AddAttachedSurface
817  *
818  * Attaches a surface to another surface. How the surface attachments work
819  * is not totally understood yet, and this method is prone to problems.
820  * he surface that is attached is AddRef-ed.
821  *
822  * Tests with complex surfaces suggest that the surface attachments form a
823  * tree, but no method to test this has been found yet.
824  *
825  * The attachment list consists of a first surface (first_attached) and
826  * for each surface a pointer to the next attached surface (next_attached).
827  * For the first surface, and a surface that has no attachments
828  * first_attached points to the surface itself. A surface that has
829  * no successors in the chain has next_attached set to NULL.
830  *
831  * Newly attached surfaces are attached right after the root surface.
832  * If a surface is attached to a complex surface compound, it's attached to
833  * the surface that the app requested, not the complex root. See
834  * GetAttachedSurface for a description how surfaces are found.
835  *
836  * This is how the current implementation works, and it was coded by looking
837  * at the needs of the applications.
838  *
839  * So far only Z-Buffer attachments are tested, and they are activated in
840  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
841  * Back buffers should work in 2D mode, but they are not tested(They can be
842  * attached in older iface versions). Rendering to the front buffer and
843  * switching between that and double buffering is not yet implemented in
844  * WineD3D, so for 3D it might have unexpected results.
845  *
846  * IDirectDrawSurfaceImpl_AddAttachedSurface is the real thing,
847  * IDirectDrawSurface7Impl_AddAttachedSurface is a wrapper around it that
848  * performs additional checks. Version 7 of this interface is much more restrictive
849  * than its predecessors.
850  *
851  * Params:
852  *  Attach: Surface to attach to iface
853  *
854  * Returns:
855  *  DD_OK on success
856  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
857  *
858  *****************************************************************************/
859 HRESULT WINAPI
860 IDirectDrawSurfaceImpl_AddAttachedSurface(IDirectDrawSurfaceImpl *This,
861                                           IDirectDrawSurfaceImpl *Surf)
862 {
863     TRACE("(%p)->(%p)\n", This, Surf);
864
865     if(Surf == This)
866         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
867
868     EnterCriticalSection(&ddraw_cs);
869
870     /* Check if the surface is already attached somewhere */
871     if( (Surf->next_attached != NULL) ||
872         (Surf->first_attached != Surf) )
873     {
874         /* TODO: Test for the structure of the manual attachment. Is it a chain or a list?
875          * What happens if one surface is attached to 2 different surfaces?
876          */
877         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);
878         LeaveCriticalSection(&ddraw_cs);
879         return DDERR_SURFACEALREADYATTACHED;
880     }
881
882     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
883     Surf->next_attached = This->next_attached;
884     Surf->first_attached = This->first_attached;
885     This->next_attached = Surf;
886
887     /* Check if the WineD3D depth stencil needs updating */
888     if(This->ddraw->d3ddevice)
889     {
890         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
891     }
892
893     IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)Surf);
894     LeaveCriticalSection(&ddraw_cs);
895     return DD_OK;
896 }
897
898 static HRESULT WINAPI
899 IDirectDrawSurface7Impl_AddAttachedSurface(IDirectDrawSurface7 *iface,
900                                            IDirectDrawSurface7 *Attach)
901 {
902     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
903     IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Attach;
904
905     /* Version 7 of this interface seems to refuse everything except z buffers, as per msdn */
906     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
907     {
908
909         WARN("Application tries to attach a non Z buffer surface. caps %08x\n",
910               Surf->surface_desc.ddsCaps.dwCaps);
911         return DDERR_CANNOTATTACHSURFACE;
912     }
913
914     return IDirectDrawSurfaceImpl_AddAttachedSurface(This,
915                                                      Surf);
916 }
917 /*****************************************************************************
918  * IDirectDrawSurface7::DeleteAttachedSurface
919  *
920  * Removes a surface from the attachment chain. The surface's refcount
921  * is decreased by one after it has been removed
922  *
923  * Params:
924  *  Flags: Some flags, not used by this implementation
925  *  Attach: Surface to detach
926  *
927  * Returns:
928  *  DD_OK on success
929  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
930  *
931  *****************************************************************************/
932 static HRESULT WINAPI
933 IDirectDrawSurfaceImpl_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
934                                              DWORD Flags,
935                                              IDirectDrawSurface7 *Attach)
936 {
937     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
938     IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Attach;
939     IDirectDrawSurfaceImpl *Prev = This;
940     TRACE("(%p)->(%08x,%p)\n", This, Flags, Surf);
941
942     EnterCriticalSection(&ddraw_cs);
943     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
944     {
945         LeaveCriticalSection(&ddraw_cs);
946         return DDERR_CANNOTDETACHSURFACE;
947     }
948
949     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
950     if (This->surface_desc.ddsCaps.dwCaps &
951         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
952     {
953         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
954         /* FIXME: we should probably also subtract from dwMipMapCount of this
955          * and all parent surfaces */
956     }
957
958     /* Find the predecessor of the detached surface */
959     while(Prev)
960     {
961         if(Prev->next_attached == Surf) break;
962         Prev = Prev->next_attached;
963     }
964
965     /* There must be a surface, otherwise there's a bug */
966     assert(Prev != NULL);
967
968     /* Unchain the surface */
969     Prev->next_attached = Surf->next_attached;
970     Surf->next_attached = NULL;
971     Surf->first_attached = Surf;
972
973     /* Check if the WineD3D depth stencil needs updating */
974     if(This->ddraw->d3ddevice)
975     {
976         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
977     }
978
979     IDirectDrawSurface7_Release(Attach);
980     LeaveCriticalSection(&ddraw_cs);
981     return DD_OK;
982 }
983
984 /*****************************************************************************
985  * IDirectDrawSurface7::AddOverlayDirtyRect
986  *
987  * "This method is not currently implemented"
988  *
989  * Params:
990  *  Rect: ?
991  *
992  * Returns:
993  *  DDERR_UNSUPPORTED
994  *
995  *****************************************************************************/
996 static HRESULT WINAPI
997 IDirectDrawSurfaceImpl_AddOverlayDirtyRect(IDirectDrawSurface7 *iface,
998                                            LPRECT Rect)
999 {
1000     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1001     TRACE("(%p)->(%p)\n",This,Rect);
1002
1003     /* MSDN says it's not implemented. I could forward it to WineD3D,
1004      * then we'd implement it, but I don't think that's a good idea
1005      * (Stefan Dösinger)
1006      */
1007 #if 0
1008     return IWineD3DSurface_AddOverlayDirtyRect(This->WineD3DSurface, pRect);
1009 #endif
1010     return DDERR_UNSUPPORTED; /* unchecked */
1011 }
1012
1013 /*****************************************************************************
1014  * IDirectDrawSurface7::GetDC
1015  *
1016  * Returns a GDI device context for the surface
1017  *
1018  * Params:
1019  *  hdc: Address of a HDC variable to store the dc to
1020  *
1021  * Returns:
1022  *  DD_OK on success
1023  *  DDERR_INVALIDPARAMS if hdc is NULL
1024  *  For details, see IWineD3DSurface::GetDC
1025  *
1026  *****************************************************************************/
1027 static HRESULT WINAPI
1028 IDirectDrawSurfaceImpl_GetDC(IDirectDrawSurface7 *iface,
1029                              HDC *hdc)
1030 {
1031     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1032     HRESULT hr;
1033     TRACE("(%p)->(%p): Relay\n", This, hdc);
1034
1035     if(!hdc)
1036         return DDERR_INVALIDPARAMS;
1037
1038     EnterCriticalSection(&ddraw_cs);
1039     hr = IWineD3DSurface_GetDC(This->WineD3DSurface,
1040                                hdc);
1041     LeaveCriticalSection(&ddraw_cs);
1042     switch(hr)
1043     {
1044         /* Some, but not all errors set *hdc to NULL. E.g. DCALREADYCREATED does not
1045          * touch *hdc
1046          */
1047         case WINED3DERR_INVALIDCALL:
1048             if(hdc) *hdc = NULL;
1049             return DDERR_INVALIDPARAMS;
1050
1051         default: return hr;
1052     }
1053 }
1054
1055 /*****************************************************************************
1056  * IDirectDrawSurface7::ReleaseDC
1057  *
1058  * Releases the DC that was constructed with GetDC
1059  *
1060  * Params:
1061  *  hdc: HDC to release
1062  *
1063  * Returns:
1064  *  DD_OK on success
1065  *  For more details, see IWineD3DSurface::ReleaseDC
1066  *
1067  *****************************************************************************/
1068 static HRESULT WINAPI
1069 IDirectDrawSurfaceImpl_ReleaseDC(IDirectDrawSurface7 *iface,
1070                                  HDC hdc)
1071 {
1072     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1073     HRESULT hr;
1074     TRACE("(%p)->(%p): Relay\n", This, hdc);
1075
1076     EnterCriticalSection(&ddraw_cs);
1077     hr = IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
1078     LeaveCriticalSection(&ddraw_cs);
1079     return hr;
1080 }
1081
1082 /*****************************************************************************
1083  * IDirectDrawSurface7::GetCaps
1084  *
1085  * Returns the surface's caps
1086  *
1087  * Params:
1088  *  Caps: Address to write the caps to
1089  *
1090  * Returns:
1091  *  DD_OK on success
1092  *  DDERR_INVALIDPARAMS if Caps is NULL
1093  *
1094  *****************************************************************************/
1095 static HRESULT WINAPI
1096 IDirectDrawSurfaceImpl_GetCaps(IDirectDrawSurface7 *iface,
1097                                DDSCAPS2 *Caps)
1098 {
1099     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1100     TRACE("(%p)->(%p)\n",This,Caps);
1101
1102     if(!Caps)
1103         return DDERR_INVALIDPARAMS;
1104
1105     *Caps = This->surface_desc.ddsCaps;
1106     return DD_OK;
1107 }
1108
1109 /*****************************************************************************
1110  * IDirectDrawSurface7::SetPriority
1111  *
1112  * Sets a texture priority for managed textures.
1113  *
1114  * Params:
1115  *  Priority: The new priority
1116  *
1117  * Returns:
1118  *  DD_OK on success
1119  *  For more details, see IWineD3DSurface::SetPriority
1120  *
1121  *****************************************************************************/
1122 static HRESULT WINAPI
1123 IDirectDrawSurfaceImpl_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1124 {
1125     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1126     HRESULT hr;
1127     TRACE("(%p)->(%d): Relay!\n",This,Priority);
1128
1129     EnterCriticalSection(&ddraw_cs);
1130     hr = IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1131     LeaveCriticalSection(&ddraw_cs);
1132     return hr;
1133 }
1134
1135 /*****************************************************************************
1136  * IDirectDrawSurface7::GetPriority
1137  *
1138  * Returns the surface's priority
1139  *
1140  * Params:
1141  *  Priority: Address of a variable to write the priority to
1142  *
1143  * Returns:
1144  *  D3D_OK on success
1145  *  DDERR_INVALIDPARAMS if Priority == NULL
1146  *  For more details, see IWineD3DSurface::GetPriority
1147  *
1148  *****************************************************************************/
1149 static HRESULT WINAPI
1150 IDirectDrawSurfaceImpl_GetPriority(IDirectDrawSurface7 *iface,
1151                                    DWORD *Priority)
1152 {
1153     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1154     TRACE("(%p)->(%p): Relay\n",This,Priority);
1155
1156     if(!Priority)
1157     {
1158         return DDERR_INVALIDPARAMS;
1159     }
1160
1161     EnterCriticalSection(&ddraw_cs);
1162     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1163     LeaveCriticalSection(&ddraw_cs);
1164     return DD_OK;
1165 }
1166
1167 /*****************************************************************************
1168  * IDirectDrawSurface7::SetPrivateData
1169  *
1170  * Stores some data in the surface that is intended for the application's
1171  * use.
1172  *
1173  * Params:
1174  *  tag: GUID that identifies the data
1175  *  Data: Pointer to the private data
1176  *  Size: Size of the private data
1177  *  Flags: Some flags
1178  *
1179  * Returns:
1180  *  D3D_OK on success
1181  *  For more details, see IWineD3DSurface::SetPrivateData
1182  *
1183  *****************************************************************************/
1184 static HRESULT WINAPI
1185 IDirectDrawSurfaceImpl_SetPrivateData(IDirectDrawSurface7 *iface,
1186                                       REFGUID tag,
1187                                       void *Data,
1188                                       DWORD Size,
1189                                       DWORD Flags)
1190 {
1191     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1192     HRESULT hr;
1193     TRACE("(%p)->(%s,%p,%d,%x): Relay\n", This, debugstr_guid(tag), Data, Size, Flags);
1194
1195     EnterCriticalSection(&ddraw_cs);
1196     hr = IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1197                                         tag,
1198                                         Data,
1199                                         Size,
1200                                         Flags);
1201     LeaveCriticalSection(&ddraw_cs);
1202     switch(hr)
1203     {
1204         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1205         default:                            return hr;
1206     }
1207 }
1208
1209 /*****************************************************************************
1210  * IDirectDrawSurface7::GetPrivateData
1211  *
1212  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1213  *
1214  * Params:
1215  *  tag: GUID of the data to return
1216  *  Data: Address where to write the data to
1217  *  Size: Size of the buffer at Data
1218  *
1219  * Returns:
1220  *  DD_OK on success
1221  *  DDERR_INVALIDPARAMS if Data is NULL
1222  *  For more details, see IWineD3DSurface::GetPrivateData
1223  *
1224  *****************************************************************************/
1225 static HRESULT WINAPI
1226 IDirectDrawSurfaceImpl_GetPrivateData(IDirectDrawSurface7 *iface,
1227                                       REFGUID tag,
1228                                       void *Data,
1229                                       DWORD *Size)
1230 {
1231     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1232     HRESULT hr;
1233     TRACE("(%p)->(%s,%p,%p): Relay\n", This, debugstr_guid(tag), Data, Size);
1234
1235     if(!Data)
1236         return DDERR_INVALIDPARAMS;
1237
1238     EnterCriticalSection(&ddraw_cs);
1239     hr = IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1240                                         tag,
1241                                         Data,
1242                                         Size);
1243     LeaveCriticalSection(&ddraw_cs);
1244     return hr;
1245 }
1246
1247 /*****************************************************************************
1248  * IDirectDrawSurface7::FreePrivateData
1249  *
1250  * Frees private data stored in the surface
1251  *
1252  * Params:
1253  *  tag: Tag of the data to free
1254  *
1255  * Returns:
1256  *  D3D_OK on success
1257  *  For more details, see IWineD3DSurface::FreePrivateData
1258  *
1259  *****************************************************************************/
1260 static HRESULT WINAPI
1261 IDirectDrawSurfaceImpl_FreePrivateData(IDirectDrawSurface7 *iface,
1262                                        REFGUID tag)
1263 {
1264     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1265     HRESULT hr;
1266     TRACE("(%p)->(%s): Relay\n", This, debugstr_guid(tag));
1267
1268     EnterCriticalSection(&ddraw_cs);
1269     hr = IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1270     LeaveCriticalSection(&ddraw_cs);
1271     return hr;
1272 }
1273
1274 /*****************************************************************************
1275  * IDirectDrawSurface7::PageLock
1276  *
1277  * Prevents a sysmem surface from being paged out
1278  *
1279  * Params:
1280  *  Flags: Not used, must be 0(unchecked)
1281  *
1282  * Returns:
1283  *  DD_OK, because it's a stub
1284  *
1285  *****************************************************************************/
1286 static HRESULT WINAPI
1287 IDirectDrawSurfaceImpl_PageLock(IDirectDrawSurface7 *iface,
1288                                 DWORD Flags)
1289 {
1290     TRACE("(%p)->(%x)\n", iface, Flags);
1291
1292     /* This is Windows memory management related - we don't need this */
1293     return DD_OK;
1294 }
1295
1296 /*****************************************************************************
1297  * IDirectDrawSurface7::PageUnlock
1298  *
1299  * Allows a sysmem surface to be paged out
1300  *
1301  * Params:
1302  *  Flags: Not used, must be 0(unchecked)
1303  *
1304  * Returns:
1305  *  DD_OK, because it's a stub
1306  *
1307  *****************************************************************************/
1308 static HRESULT WINAPI
1309 IDirectDrawSurfaceImpl_PageUnlock(IDirectDrawSurface7 *iface,
1310                                   DWORD Flags)
1311 {
1312     TRACE("(%p)->(%x)\n", iface, Flags);
1313
1314     return DD_OK;
1315 }
1316
1317 /*****************************************************************************
1318  * IDirectDrawSurface7::BltBatch
1319  *
1320  * An unimplemented function
1321  *
1322  * Params:
1323  *  ?
1324  *
1325  * Returns:
1326  *  DDERR_UNSUPPORTED
1327  *
1328  *****************************************************************************/
1329 static HRESULT WINAPI IDirectDrawSurfaceImpl_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1330 {
1331     TRACE("(%p)->(%p,%d,%08x)\n",iface,Batch,Count,Flags);
1332
1333     /* MSDN: "not currently implemented" */
1334     return DDERR_UNSUPPORTED;
1335 }
1336
1337 /*****************************************************************************
1338  * IDirectDrawSurface7::EnumAttachedSurfaces
1339  *
1340  * Enumerates all surfaces attached to this surface
1341  *
1342  * Params:
1343  *  context: Pointer to pass unmodified to the callback
1344  *  cb: Callback function to call for each surface
1345  *
1346  * Returns:
1347  *  DD_OK on success
1348  *  DDERR_INVALIDPARAMS if cb is NULL
1349  *
1350  *****************************************************************************/
1351 static HRESULT WINAPI
1352 IDirectDrawSurfaceImpl_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1353                                             void *context,
1354                                             LPDDENUMSURFACESCALLBACK7 cb)
1355 {
1356     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1357     IDirectDrawSurfaceImpl *surf;
1358     DDSURFACEDESC2 desc;
1359     int i;
1360
1361     /* Attached surfaces aren't handled in WineD3D */
1362     TRACE("(%p)->(%p,%p)\n",This,context,cb);
1363
1364     if(!cb)
1365         return DDERR_INVALIDPARAMS;
1366
1367     EnterCriticalSection(&ddraw_cs);
1368     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1369     {
1370         surf = This->complex_array[i];
1371         if(!surf) break;
1372
1373         IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)surf);
1374         desc = surf->surface_desc;
1375         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1376         if (cb((IDirectDrawSurface7 *)surf, &desc, context) == DDENUMRET_CANCEL)
1377         {
1378             LeaveCriticalSection(&ddraw_cs);
1379             return DD_OK;
1380         }
1381     }
1382
1383     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1384     {
1385         IDirectDrawSurface7_AddRef((IDirectDrawSurface7 *)surf);
1386         desc = surf->surface_desc;
1387         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1388         if (cb((IDirectDrawSurface7 *)surf, &desc, context) == DDENUMRET_CANCEL)
1389         {
1390             LeaveCriticalSection(&ddraw_cs);
1391             return DD_OK;
1392         }
1393     }
1394
1395     TRACE(" end of enumeration.\n");
1396
1397     LeaveCriticalSection(&ddraw_cs);
1398     return DD_OK;
1399 }
1400
1401 /*****************************************************************************
1402  * IDirectDrawSurface7::EnumOverlayZOrders
1403  *
1404  * "Enumerates the overlay surfaces on the specified destination"
1405  *
1406  * Params:
1407  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1408  *  context: context to pass back to the callback
1409  *  cb: callback function to call for each enumerated surface
1410  *
1411  * Returns:
1412  *  DD_OK, because it's a stub
1413  *
1414  *****************************************************************************/
1415 static HRESULT WINAPI
1416 IDirectDrawSurfaceImpl_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1417                                           DWORD Flags,
1418                                           void *context,
1419                                           LPDDENUMSURFACESCALLBACK7 cb)
1420 {
1421      FIXME("(%p)->(%x,%p,%p): Stub!\n", iface, Flags, context, cb);
1422
1423     return DD_OK;
1424 }
1425
1426 /*****************************************************************************
1427  * IDirectDrawSurface7::GetBltStatus
1428  *
1429  * Returns the blitting status
1430  *
1431  * Params:
1432  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1433  *
1434  * Returns:
1435  *  See IWineD3DSurface::Blt
1436  *
1437  *****************************************************************************/
1438 static HRESULT WINAPI
1439 IDirectDrawSurfaceImpl_GetBltStatus(IDirectDrawSurface7 *iface,
1440                                     DWORD Flags)
1441 {
1442     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1443     HRESULT hr;
1444     TRACE("(%p)->(%x): Relay\n", This, Flags);
1445
1446     EnterCriticalSection(&ddraw_cs);
1447     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1448     LeaveCriticalSection(&ddraw_cs);
1449     switch(hr)
1450     {
1451         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1452         default:                            return hr;
1453     }
1454 }
1455
1456 /*****************************************************************************
1457  * IDirectDrawSurface7::GetColorKey
1458  *
1459  * Returns the color key assigned to the surface
1460  *
1461  * Params:
1462  *  Flags: Some flags
1463  *  CKey: Address to store the key to
1464  *
1465  * Returns:
1466  *  DD_OK on success
1467  *  DDERR_INVALIDPARAMS if CKey is NULL
1468  *
1469  *****************************************************************************/
1470 static HRESULT WINAPI
1471 IDirectDrawSurfaceImpl_GetColorKey(IDirectDrawSurface7 *iface,
1472                                    DWORD Flags,
1473                                    DDCOLORKEY *CKey)
1474 {
1475     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1476     TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
1477
1478     if(!CKey)
1479         return DDERR_INVALIDPARAMS;
1480
1481     EnterCriticalSection(&ddraw_cs);
1482
1483     switch (Flags)
1484     {
1485     case DDCKEY_DESTBLT:
1486         if (!(This->surface_desc.dwFlags & DDSD_CKDESTBLT))
1487         {
1488             LeaveCriticalSection(&ddraw_cs);
1489             return DDERR_NOCOLORKEY;
1490         }
1491         *CKey = This->surface_desc.ddckCKDestBlt;
1492         break;
1493
1494     case DDCKEY_DESTOVERLAY:
1495         if (!(This->surface_desc.dwFlags & DDSD_CKDESTOVERLAY))
1496             {
1497             LeaveCriticalSection(&ddraw_cs);
1498             return DDERR_NOCOLORKEY;
1499             }
1500         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1501         break;
1502
1503     case DDCKEY_SRCBLT:
1504         if (!(This->surface_desc.dwFlags & DDSD_CKSRCBLT))
1505         {
1506             LeaveCriticalSection(&ddraw_cs);
1507             return DDERR_NOCOLORKEY;
1508         }
1509         *CKey = This->surface_desc.ddckCKSrcBlt;
1510         break;
1511
1512     case DDCKEY_SRCOVERLAY:
1513         if (!(This->surface_desc.dwFlags & DDSD_CKSRCOVERLAY))
1514         {
1515             LeaveCriticalSection(&ddraw_cs);
1516             return DDERR_NOCOLORKEY;
1517         }
1518         *CKey = This->surface_desc.ddckCKSrcOverlay;
1519         break;
1520
1521     default:
1522         LeaveCriticalSection(&ddraw_cs);
1523         return DDERR_INVALIDPARAMS;
1524     }
1525
1526     LeaveCriticalSection(&ddraw_cs);
1527     return DD_OK;
1528 }
1529
1530 /*****************************************************************************
1531  * IDirectDrawSurface7::GetFlipStatus
1532  *
1533  * Returns the flipping status of the surface
1534  *
1535  * Params:
1536  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1537  *
1538  * Returns:
1539  *  See IWineD3DSurface::GetFlipStatus
1540  *
1541  *****************************************************************************/
1542 static HRESULT WINAPI
1543 IDirectDrawSurfaceImpl_GetFlipStatus(IDirectDrawSurface7 *iface,
1544                                      DWORD Flags)
1545 {
1546     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1547     HRESULT hr;
1548     TRACE("(%p)->(%x): Relay\n", This, Flags);
1549
1550     EnterCriticalSection(&ddraw_cs);
1551     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1552     LeaveCriticalSection(&ddraw_cs);
1553     switch(hr)
1554     {
1555         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1556         default:                            return hr;
1557     }
1558 }
1559
1560 /*****************************************************************************
1561  * IDirectDrawSurface7::GetOverlayPosition
1562  *
1563  * Returns the display coordinates of a visible and active overlay surface
1564  *
1565  * Params:
1566  *  X
1567  *  Y
1568  *
1569  * Returns:
1570  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1571  *****************************************************************************/
1572 static HRESULT WINAPI
1573 IDirectDrawSurfaceImpl_GetOverlayPosition(IDirectDrawSurface7 *iface,
1574                                           LONG *X,
1575                                           LONG *Y) {
1576     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1577     HRESULT hr;
1578     TRACE("(%p)->(%p,%p): Relay\n", This, X, Y);
1579
1580     EnterCriticalSection(&ddraw_cs);
1581     hr = IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1582                                             X,
1583                                             Y);
1584     LeaveCriticalSection(&ddraw_cs);
1585     return hr;
1586 }
1587
1588 /*****************************************************************************
1589  * IDirectDrawSurface7::GetPixelFormat
1590  *
1591  * Returns the pixel format of the Surface
1592  *
1593  * Params:
1594  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1595  *               format should be written
1596  *
1597  * Returns:
1598  *  DD_OK on success
1599  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1600  *
1601  *****************************************************************************/
1602 static HRESULT WINAPI
1603 IDirectDrawSurfaceImpl_GetPixelFormat(IDirectDrawSurface7 *iface,
1604                                       DDPIXELFORMAT *PixelFormat)
1605 {
1606     /* What is DDERR_INVALIDSURFACETYPE for here? */
1607     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1608     TRACE("(%p)->(%p)\n",This,PixelFormat);
1609
1610     if(!PixelFormat)
1611         return DDERR_INVALIDPARAMS;
1612
1613     EnterCriticalSection(&ddraw_cs);
1614     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1615     LeaveCriticalSection(&ddraw_cs);
1616
1617     return DD_OK;
1618 }
1619
1620
1621 /*****************************************************************************
1622  * IDirectDrawSurface7::GetSurfaceDesc
1623  *
1624  * Returns the description of this surface
1625  *
1626  * Params:
1627  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1628  *        surface desc
1629  *
1630  * Returns:
1631  *  DD_OK on success
1632  *  DDERR_INVALIDPARAMS if DDSD is NULL
1633  *
1634  *****************************************************************************/
1635 static HRESULT WINAPI
1636 IDirectDrawSurfaceImpl_GetSurfaceDesc(IDirectDrawSurface7 *iface,
1637                                       DDSURFACEDESC2 *DDSD)
1638 {
1639     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1640
1641     TRACE("(%p)->(%p)\n",This,DDSD);
1642
1643     if(!DDSD)
1644         return DDERR_INVALIDPARAMS;
1645
1646     if (DDSD->dwSize != sizeof(DDSURFACEDESC2))
1647     {
1648         WARN("Incorrect struct size %d, returning DDERR_INVALIDPARAMS\n",DDSD->dwSize);
1649         return DDERR_INVALIDPARAMS;
1650     }
1651
1652     EnterCriticalSection(&ddraw_cs);
1653     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1654     TRACE("Returning surface desc:\n");
1655     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1656
1657     LeaveCriticalSection(&ddraw_cs);
1658     return DD_OK;
1659 }
1660
1661 /*****************************************************************************
1662  * IDirectDrawSurface7::Initialize
1663  *
1664  * Initializes the surface. This is a no-op in Wine
1665  *
1666  * Params:
1667  *  DD: Pointer to an DirectDraw interface
1668  *  DDSD: Surface description for initialization
1669  *
1670  * Returns:
1671  *  DDERR_ALREADYINITIALIZED
1672  *
1673  *****************************************************************************/
1674 static HRESULT WINAPI
1675 IDirectDrawSurfaceImpl_Initialize(IDirectDrawSurface7 *iface,
1676                                   IDirectDraw *DD,
1677                                   DDSURFACEDESC2 *DDSD)
1678 {
1679     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1680     IDirectDrawImpl *ddimpl = DD ? ddraw_from_ddraw1(DD) : NULL;
1681     TRACE("(%p)->(%p,%p)\n",This,ddimpl,DDSD);
1682
1683     return DDERR_ALREADYINITIALIZED;
1684 }
1685
1686 /*****************************************************************************
1687  * IDirectDrawSurface7::IsLost
1688  *
1689  * Checks if the surface is lost
1690  *
1691  * Returns:
1692  *  DD_OK, if the surface is usable
1693  *  DDERR_ISLOST if the surface is lost
1694  *  See IWineD3DSurface::IsLost for more details
1695  *
1696  *****************************************************************************/
1697 static HRESULT WINAPI
1698 IDirectDrawSurfaceImpl_IsLost(IDirectDrawSurface7 *iface)
1699 {
1700     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1701     HRESULT hr;
1702     TRACE("(%p)\n", This);
1703
1704     EnterCriticalSection(&ddraw_cs);
1705     /* We lose the surface if the implementation was changed */
1706     if(This->ImplType != This->ddraw->ImplType)
1707     {
1708         /* But this shouldn't happen. When we change the implementation,
1709          * all surfaces are re-created automatically, and their content
1710          * is copied
1711          */
1712         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
1713         LeaveCriticalSection(&ddraw_cs);
1714         return DDERR_SURFACELOST;
1715     }
1716
1717     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
1718     LeaveCriticalSection(&ddraw_cs);
1719     switch(hr)
1720     {
1721         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
1722          * WineD3D uses the same error for surfaces
1723          */
1724         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
1725         default:                            return hr;
1726     }
1727 }
1728
1729 /*****************************************************************************
1730  * IDirectDrawSurface7::Restore
1731  *
1732  * Restores a lost surface. This makes the surface usable again, but
1733  * doesn't reload its old contents
1734  *
1735  * Returns:
1736  *  DD_OK on success
1737  *  See IWineD3DSurface::Restore for more details
1738  *
1739  *****************************************************************************/
1740 static HRESULT WINAPI
1741 IDirectDrawSurfaceImpl_Restore(IDirectDrawSurface7 *iface)
1742 {
1743     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1744     HRESULT hr;
1745     TRACE("(%p)\n", This);
1746
1747     EnterCriticalSection(&ddraw_cs);
1748     if(This->ImplType != This->ddraw->ImplType)
1749     {
1750         /* Call the recreation callback. Make sure to AddRef first */
1751         IDirectDrawSurface_AddRef(iface);
1752         IDirectDrawImpl_RecreateSurfacesCallback(iface,
1753                                                  &This->surface_desc,
1754                                                  NULL /* Not needed */);
1755     }
1756     hr = IWineD3DSurface_Restore(This->WineD3DSurface);
1757     LeaveCriticalSection(&ddraw_cs);
1758     return hr;
1759 }
1760
1761 /*****************************************************************************
1762  * IDirectDrawSurface7::SetOverlayPosition
1763  *
1764  * Changes the display coordinates of an overlay surface
1765  *
1766  * Params:
1767  *  X:
1768  *  Y:
1769  *
1770  * Returns:
1771  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
1772  *****************************************************************************/
1773 static HRESULT WINAPI
1774 IDirectDrawSurfaceImpl_SetOverlayPosition(IDirectDrawSurface7 *iface,
1775                                           LONG X,
1776                                           LONG Y)
1777 {
1778     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1779     HRESULT hr;
1780     TRACE("(%p)->(%d,%d): Relay\n", This, X, Y);
1781
1782     EnterCriticalSection(&ddraw_cs);
1783     hr = IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
1784                                             X,
1785                                             Y);
1786     LeaveCriticalSection(&ddraw_cs);
1787     return hr;
1788 }
1789
1790 /*****************************************************************************
1791  * IDirectDrawSurface7::UpdateOverlay
1792  *
1793  * Modifies the attributes of an overlay surface.
1794  *
1795  * Params:
1796  *  SrcRect: The section of the source being used for the overlay
1797  *  DstSurface: Address of the surface that is overlaid
1798  *  DstRect: Place of the overlay
1799  *  Flags: some DDOVER_* flags
1800  *
1801  * Returns:
1802  *  DDERR_UNSUPPORTED, because we don't support overlays
1803  *
1804  *****************************************************************************/
1805 static HRESULT WINAPI
1806 IDirectDrawSurfaceImpl_UpdateOverlay(IDirectDrawSurface7 *iface,
1807                                      LPRECT SrcRect,
1808                                      IDirectDrawSurface7 *DstSurface,
1809                                      LPRECT DstRect,
1810                                      DWORD Flags,
1811                                      LPDDOVERLAYFX FX)
1812 {
1813     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1814     IDirectDrawSurfaceImpl *Dst = (IDirectDrawSurfaceImpl *)DstSurface;
1815     HRESULT hr;
1816     TRACE("(%p)->(%p,%p,%p,%x,%p): Relay\n", This, SrcRect, Dst, DstRect, Flags, FX);
1817
1818     EnterCriticalSection(&ddraw_cs);
1819     hr = IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
1820                                        SrcRect,
1821                                        Dst ? Dst->WineD3DSurface : NULL,
1822                                        DstRect,
1823                                        Flags,
1824                                        (WINEDDOVERLAYFX *) FX);
1825     LeaveCriticalSection(&ddraw_cs);
1826     switch(hr) {
1827         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1828         case WINEDDERR_NOTAOVERLAYSURFACE:  return DDERR_NOTAOVERLAYSURFACE;
1829         case WINEDDERR_OVERLAYNOTVISIBLE:   return DDERR_OVERLAYNOTVISIBLE;
1830         default:
1831             return hr;
1832     }
1833 }
1834
1835 /*****************************************************************************
1836  * IDirectDrawSurface7::UpdateOverlayDisplay
1837  *
1838  * The DX7 sdk says that it's not implemented
1839  *
1840  * Params:
1841  *  Flags: ?
1842  *
1843  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
1844  *
1845  *****************************************************************************/
1846 static HRESULT WINAPI
1847 IDirectDrawSurfaceImpl_UpdateOverlayDisplay(IDirectDrawSurface7 *iface,
1848                                             DWORD Flags)
1849 {
1850     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1851     TRACE("(%p)->(%x)\n", This, Flags);
1852     return DDERR_UNSUPPORTED;
1853 }
1854
1855 /*****************************************************************************
1856  * IDirectDrawSurface7::UpdateOverlayZOrder
1857  *
1858  * Sets an overlay's Z order
1859  *
1860  * Params:
1861  *  Flags: DDOVERZ_* flags
1862  *  DDSRef: Defines the relative position in the overlay chain
1863  *
1864  * Returns:
1865  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
1866  *
1867  *****************************************************************************/
1868 static HRESULT WINAPI
1869 IDirectDrawSurfaceImpl_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
1870                                            DWORD Flags,
1871                                            IDirectDrawSurface7 *DDSRef)
1872 {
1873     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1874     IDirectDrawSurfaceImpl *Ref = (IDirectDrawSurfaceImpl *)DDSRef;
1875     HRESULT hr;
1876
1877     TRACE("(%p)->(%x,%p): Relay\n", This, Flags, Ref);
1878     EnterCriticalSection(&ddraw_cs);
1879     hr =  IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
1880                                               Flags,
1881                                               Ref ? Ref->WineD3DSurface : NULL);
1882     LeaveCriticalSection(&ddraw_cs);
1883     return hr;
1884 }
1885
1886 /*****************************************************************************
1887  * IDirectDrawSurface7::GetDDInterface
1888  *
1889  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
1890  * surface belongs to
1891  *
1892  * Params:
1893  *  DD: Address to write the interface pointer to
1894  *
1895  * Returns:
1896  *  DD_OK on success
1897  *  DDERR_INVALIDPARAMS if DD is NULL
1898  *
1899  *****************************************************************************/
1900 static HRESULT WINAPI
1901 IDirectDrawSurfaceImpl_GetDDInterface(IDirectDrawSurface7 *iface,
1902                                       void **DD)
1903 {
1904     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1905
1906     TRACE("(%p)->(%p)\n",This,DD);
1907
1908     if(!DD)
1909         return DDERR_INVALIDPARAMS;
1910
1911     switch(This->version)
1912     {
1913         case 7:
1914             *DD = This->ddraw;
1915             break;
1916
1917         case 4:
1918             *DD = &This->ddraw->IDirectDraw4_vtbl;
1919             break;
1920
1921         case 2:
1922             *DD = &This->ddraw->IDirectDraw2_vtbl;
1923             break;
1924
1925         case 1:
1926             *DD = &This->ddraw->IDirectDraw_vtbl;
1927             break;
1928
1929     }
1930     IUnknown_AddRef((IUnknown *)*DD);
1931
1932     return DD_OK;
1933 }
1934
1935 /* This seems also windows implementation specific - I don't think WineD3D needs this */
1936 static HRESULT WINAPI IDirectDrawSurfaceImpl_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
1937 {
1938     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1939     volatile IDirectDrawSurfaceImpl* vThis = This;
1940
1941     TRACE("(%p)\n",This);
1942     EnterCriticalSection(&ddraw_cs);
1943     /* A uniqueness value of 0 is apparently special.
1944      * This needs to be checked.
1945      * TODO: Write tests for this code and check if the volatile, interlocked stuff is really needed
1946      */
1947     while (1) {
1948         DWORD old_uniqueness_value = vThis->uniqueness_value;
1949         DWORD new_uniqueness_value = old_uniqueness_value+1;
1950
1951         if (old_uniqueness_value == 0) break;
1952         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
1953
1954         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
1955                                       old_uniqueness_value,
1956                                       new_uniqueness_value)
1957             == old_uniqueness_value)
1958             break;
1959     }
1960
1961     LeaveCriticalSection(&ddraw_cs);
1962     return DD_OK;
1963 }
1964
1965 static HRESULT WINAPI IDirectDrawSurfaceImpl_GetUniquenessValue(IDirectDrawSurface7 *iface, LPDWORD pValue)
1966 {
1967     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1968
1969     TRACE("(%p)->(%p)\n",This,pValue);
1970     EnterCriticalSection(&ddraw_cs);
1971     *pValue = This->uniqueness_value;
1972     LeaveCriticalSection(&ddraw_cs);
1973     return DD_OK;
1974 }
1975
1976 /*****************************************************************************
1977  * IDirectDrawSurface7::SetLOD
1978  *
1979  * Sets the level of detail of a texture
1980  *
1981  * Params:
1982  *  MaxLOD: LOD to set
1983  *
1984  * Returns:
1985  *  DD_OK on success
1986  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
1987  *
1988  *****************************************************************************/
1989 static HRESULT WINAPI
1990 IDirectDrawSurfaceImpl_SetLOD(IDirectDrawSurface7 *iface,
1991                               DWORD MaxLOD)
1992 {
1993     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1994     HRESULT hr;
1995     TRACE("(%p)->(%d)\n", This, MaxLOD);
1996
1997     EnterCriticalSection(&ddraw_cs);
1998     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
1999     {
2000         LeaveCriticalSection(&ddraw_cs);
2001         return DDERR_INVALIDOBJECT;
2002     }
2003
2004     if(!This->wineD3DTexture)
2005     {
2006         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
2007         LeaveCriticalSection(&ddraw_cs);
2008         return DDERR_INVALIDOBJECT;
2009     }
2010
2011     hr = IWineD3DBaseTexture_SetLOD(This->wineD3DTexture,
2012                                     MaxLOD);
2013     LeaveCriticalSection(&ddraw_cs);
2014     return hr;
2015 }
2016
2017 /*****************************************************************************
2018  * IDirectDrawSurface7::GetLOD
2019  *
2020  * Returns the level of detail of a Direct3D texture
2021  *
2022  * Params:
2023  *  MaxLOD: Address to write the LOD to
2024  *
2025  * Returns:
2026  *  DD_OK on success
2027  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
2028  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2029  *
2030  *****************************************************************************/
2031 static HRESULT WINAPI
2032 IDirectDrawSurfaceImpl_GetLOD(IDirectDrawSurface7 *iface,
2033                               DWORD *MaxLOD)
2034 {
2035     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2036     TRACE("(%p)->(%p)\n", This, MaxLOD);
2037
2038     if(!MaxLOD)
2039         return DDERR_INVALIDPARAMS;
2040
2041     EnterCriticalSection(&ddraw_cs);
2042     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2043     {
2044         LeaveCriticalSection(&ddraw_cs);
2045         return DDERR_INVALIDOBJECT;
2046     }
2047
2048     *MaxLOD = IWineD3DBaseTexture_GetLOD(This->wineD3DTexture);
2049     LeaveCriticalSection(&ddraw_cs);
2050     return DD_OK;
2051 }
2052
2053 /*****************************************************************************
2054  * IDirectDrawSurface7::BltFast
2055  *
2056  * Performs a fast Blit.
2057  *
2058  * Params:
2059  *  dstx: The x coordinate to blit to on the destination
2060  *  dsty: The y coordinate to blit to on the destination
2061  *  Source: The source surface
2062  *  rsrc: The source rectangle
2063  *  trans: Type of transfer. Some DDBLTFAST_* flags
2064  *
2065  * Returns:
2066  *  DD_OK on success
2067  *  For more details, see IWineD3DSurface::BltFast
2068  *
2069  *****************************************************************************/
2070 static HRESULT WINAPI
2071 IDirectDrawSurfaceImpl_BltFast(IDirectDrawSurface7 *iface,
2072                                DWORD dstx,
2073                                DWORD dsty,
2074                                IDirectDrawSurface7 *Source,
2075                                RECT *rsrc,
2076                                DWORD trans)
2077 {
2078     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2079     IDirectDrawSurfaceImpl *src = (IDirectDrawSurfaceImpl *)Source;
2080     HRESULT hr;
2081     TRACE("(%p)->(%d,%d,%p,%p,%d): Relay\n", This, dstx, dsty, Source, rsrc, trans);
2082
2083     /* Source must be != NULL, This is not checked by windows. Windows happily throws a 0xc0000005
2084      * in that case
2085      */
2086     if(rsrc)
2087     {
2088         if(rsrc->top > rsrc->bottom || rsrc->left > rsrc->right ||
2089            rsrc->right > src->surface_desc.dwWidth ||
2090            rsrc->bottom > src->surface_desc.dwHeight)
2091         {
2092             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
2093             return DDERR_INVALIDRECT;
2094         }
2095         if(dstx + rsrc->right - rsrc->left > This->surface_desc.dwWidth ||
2096            dsty + rsrc->bottom - rsrc->top > This->surface_desc.dwHeight)
2097         {
2098             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2099             return DDERR_INVALIDRECT;
2100         }
2101     }
2102     else
2103     {
2104         if(dstx + src->surface_desc.dwWidth > This->surface_desc.dwWidth ||
2105            dsty + src->surface_desc.dwHeight > This->surface_desc.dwHeight)
2106         {
2107             WARN("Destination area out of bounds, returning DDERR_INVALIDRECT\n");
2108             return DDERR_INVALIDRECT;
2109         }
2110     }
2111
2112     EnterCriticalSection(&ddraw_cs);
2113     hr = IWineD3DSurface_BltFast(This->WineD3DSurface,
2114                                  dstx, dsty,
2115                                  src ? src->WineD3DSurface : NULL,
2116                                  rsrc,
2117                                  trans);
2118     LeaveCriticalSection(&ddraw_cs);
2119     switch(hr)
2120     {
2121         case WINED3DERR_NOTAVAILABLE:           return DDERR_UNSUPPORTED;
2122         case WINED3DERR_WRONGTEXTUREFORMAT:     return DDERR_INVALIDPIXELFORMAT;
2123         default:                                return hr;
2124     }
2125 }
2126
2127 /*****************************************************************************
2128  * IDirectDrawSurface7::GetClipper
2129  *
2130  * Returns the IDirectDrawClipper interface of the clipper assigned to this
2131  * surface
2132  *
2133  * Params:
2134  *  Clipper: Address to store the interface pointer at
2135  *
2136  * Returns:
2137  *  DD_OK on success
2138  *  DDERR_INVALIDPARAMS if Clipper is NULL
2139  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
2140  *
2141  *****************************************************************************/
2142 static HRESULT WINAPI
2143 IDirectDrawSurfaceImpl_GetClipper(IDirectDrawSurface7 *iface,
2144                                   IDirectDrawClipper **Clipper)
2145 {
2146     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2147     TRACE("(%p)->(%p)\n", This, Clipper);
2148
2149     if(!Clipper)
2150     {
2151         LeaveCriticalSection(&ddraw_cs);
2152         return DDERR_INVALIDPARAMS;
2153     }
2154
2155     EnterCriticalSection(&ddraw_cs);
2156     if(This->clipper == NULL)
2157     {
2158         LeaveCriticalSection(&ddraw_cs);
2159         return DDERR_NOCLIPPERATTACHED;
2160     }
2161
2162     *Clipper = (IDirectDrawClipper *)This->clipper;
2163     IDirectDrawClipper_AddRef(*Clipper);
2164     LeaveCriticalSection(&ddraw_cs);
2165     return DD_OK;
2166 }
2167
2168 /*****************************************************************************
2169  * IDirectDrawSurface7::SetClipper
2170  *
2171  * Sets a clipper for the surface
2172  *
2173  * Params:
2174  *  Clipper: IDirectDrawClipper interface of the clipper to set
2175  *
2176  * Returns:
2177  *  DD_OK on success
2178  *
2179  *****************************************************************************/
2180 static HRESULT WINAPI
2181 IDirectDrawSurfaceImpl_SetClipper(IDirectDrawSurface7 *iface,
2182                                   IDirectDrawClipper *Clipper)
2183 {
2184     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2185     IDirectDrawClipperImpl *oldClipper = This->clipper;
2186     HWND clipWindow;
2187     HRESULT hr;
2188     TRACE("(%p)->(%p)\n",This,Clipper);
2189
2190     EnterCriticalSection(&ddraw_cs);
2191     if ((IDirectDrawClipperImpl *)Clipper == This->clipper)
2192     {
2193         LeaveCriticalSection(&ddraw_cs);
2194         return DD_OK;
2195     }
2196
2197     This->clipper = (IDirectDrawClipperImpl *)Clipper;
2198
2199     if (Clipper != NULL)
2200         IDirectDrawClipper_AddRef(Clipper);
2201     if(oldClipper)
2202         IDirectDrawClipper_Release((IDirectDrawClipper *)oldClipper);
2203
2204     hr = IWineD3DSurface_SetClipper(This->WineD3DSurface, This->clipper ? This->clipper->wineD3DClipper : NULL);
2205
2206     if(This->wineD3DSwapChain) {
2207         clipWindow = NULL;
2208         if(Clipper) {
2209             IDirectDrawClipper_GetHWnd(Clipper, &clipWindow);
2210         }
2211
2212         if(clipWindow) {
2213             IWineD3DSwapChain_SetDestWindowOverride(This->wineD3DSwapChain,
2214                                                     clipWindow);
2215         } else {
2216             IWineD3DSwapChain_SetDestWindowOverride(This->wineD3DSwapChain,
2217                                                     This->ddraw->d3d_window);
2218         }
2219     }
2220
2221     LeaveCriticalSection(&ddraw_cs);
2222     return hr;
2223 }
2224
2225 /*****************************************************************************
2226  * IDirectDrawSurface7::SetSurfaceDesc
2227  *
2228  * Sets the surface description. It can override the pixel format, the surface
2229  * memory, ...
2230  * It's not really tested.
2231  *
2232  * Params:
2233  * DDSD: Pointer to the new surface description to set
2234  * Flags: Some flags
2235  *
2236  * Returns:
2237  *  DD_OK on success
2238  *  DDERR_INVALIDPARAMS if DDSD is NULL
2239  *
2240  *****************************************************************************/
2241 static HRESULT WINAPI
2242 IDirectDrawSurfaceImpl_SetSurfaceDesc(IDirectDrawSurface7 *iface,
2243                                       DDSURFACEDESC2 *DDSD,
2244                                       DWORD Flags)
2245 {
2246     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2247     WINED3DFORMAT newFormat = WINED3DFMT_UNKNOWN;
2248     HRESULT hr;
2249     TRACE("(%p)->(%p,%x)\n", This, DDSD, Flags);
2250
2251     if(!DDSD)
2252         return DDERR_INVALIDPARAMS;
2253
2254     EnterCriticalSection(&ddraw_cs);
2255     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
2256     {
2257         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
2258
2259         if(newFormat == WINED3DFMT_UNKNOWN)
2260         {
2261             ERR("Requested to set an unknown pixelformat\n");
2262             LeaveCriticalSection(&ddraw_cs);
2263             return DDERR_INVALIDPARAMS;
2264         }
2265         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
2266         {
2267             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
2268                                            newFormat);
2269             if(hr != DD_OK)
2270             {
2271                 LeaveCriticalSection(&ddraw_cs);
2272                 return hr;
2273             }
2274         }
2275     }
2276     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
2277     {
2278         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2279                                     DDCKEY_DESTOVERLAY,
2280                                     (WINEDDCOLORKEY *) &DDSD->u3.ddckCKDestOverlay);
2281     }
2282     if (DDSD->dwFlags & DDSD_CKDESTBLT)
2283     {
2284         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2285                                     DDCKEY_DESTBLT,
2286                                     (WINEDDCOLORKEY *) &DDSD->ddckCKDestBlt);
2287     }
2288     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
2289     {
2290         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2291                                     DDCKEY_SRCOVERLAY,
2292                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcOverlay);
2293     }
2294     if (DDSD->dwFlags & DDSD_CKSRCBLT)
2295     {
2296         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2297                                     DDCKEY_SRCBLT,
2298                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcBlt);
2299     }
2300     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
2301     {
2302         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
2303         if(hr != WINED3D_OK)
2304         {
2305             /* No need for a trace here, wined3d does that for us */
2306             switch(hr)
2307             {
2308                 case WINED3DERR_INVALIDCALL:
2309                     LeaveCriticalSection(&ddraw_cs);
2310                     return DDERR_INVALIDPARAMS;
2311                 default:
2312                     break; /* Go on */
2313             }
2314         }
2315     }
2316
2317     This->surface_desc = *DDSD;
2318
2319     LeaveCriticalSection(&ddraw_cs);
2320     return DD_OK;
2321 }
2322
2323 /*****************************************************************************
2324  * IDirectDrawSurface7::GetPalette
2325  *
2326  * Returns the IDirectDrawPalette interface of the palette currently assigned
2327  * to the surface
2328  *
2329  * Params:
2330  *  Pal: Address to write the interface pointer to
2331  *
2332  * Returns:
2333  *  DD_OK on success
2334  *  DDERR_INVALIDPARAMS if Pal is NULL
2335  *
2336  *****************************************************************************/
2337 static HRESULT WINAPI
2338 IDirectDrawSurfaceImpl_GetPalette(IDirectDrawSurface7 *iface,
2339                                   IDirectDrawPalette **Pal)
2340 {
2341     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2342     IWineD3DPalette *wPal;
2343     HRESULT hr;
2344     TRACE("(%p)->(%p): Relay\n", This, Pal);
2345
2346     if(!Pal)
2347         return DDERR_INVALIDPARAMS;
2348
2349     EnterCriticalSection(&ddraw_cs);
2350     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
2351     if(hr != DD_OK)
2352     {
2353         LeaveCriticalSection(&ddraw_cs);
2354         return hr;
2355     }
2356
2357     if(wPal)
2358     {
2359         hr = IWineD3DPalette_GetParent(wPal, (IUnknown **) Pal);
2360     }
2361     else
2362     {
2363         *Pal = NULL;
2364         hr = DDERR_NOPALETTEATTACHED;
2365     }
2366
2367     LeaveCriticalSection(&ddraw_cs);
2368     return hr;
2369 }
2370
2371 /*****************************************************************************
2372  * SetColorKeyEnum
2373  *
2374  * EnumAttachedSurface callback for SetColorKey. Used to set color keys
2375  * recursively in the surface tree
2376  *
2377  *****************************************************************************/
2378 struct SCKContext
2379 {
2380     HRESULT ret;
2381     WINEDDCOLORKEY *CKey;
2382     DWORD Flags;
2383 };
2384
2385 static HRESULT WINAPI
2386 SetColorKeyEnum(IDirectDrawSurface7 *surface,
2387                 DDSURFACEDESC2 *desc,
2388                 void *context)
2389 {
2390     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)surface;
2391     struct SCKContext *ctx = context;
2392     HRESULT hr;
2393
2394     hr = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2395                                      ctx->Flags,
2396                                      ctx->CKey);
2397     if(hr != DD_OK)
2398     {
2399         WARN("IWineD3DSurface_SetColorKey failed, hr = %08x\n", hr);
2400         ctx->ret = hr;
2401     }
2402
2403     IDirectDrawSurface7_EnumAttachedSurfaces(surface,
2404                                              context,
2405                                              SetColorKeyEnum);
2406     IDirectDrawSurface7_Release(surface);
2407     return DDENUMRET_OK;
2408 }
2409
2410 /*****************************************************************************
2411  * IDirectDrawSurface7::SetColorKey
2412  *
2413  * Sets the color keying options for the surface. Observations showed that
2414  * in case of complex surfaces the color key has to be assigned to all
2415  * sublevels.
2416  *
2417  * Params:
2418  *  Flags: DDCKEY_*
2419  *  CKey: The new color key
2420  *
2421  * Returns:
2422  *  DD_OK on success
2423  *  See IWineD3DSurface::SetColorKey for details
2424  *
2425  *****************************************************************************/
2426 static HRESULT WINAPI
2427 IDirectDrawSurfaceImpl_SetColorKey(IDirectDrawSurface7 *iface,
2428                                    DWORD Flags,
2429                                    DDCOLORKEY *CKey)
2430 {
2431     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2432     DDCOLORKEY FixedCKey;
2433     struct SCKContext ctx = { DD_OK, (WINEDDCOLORKEY *) (CKey ? &FixedCKey : NULL), Flags };
2434     TRACE("(%p)->(%x,%p)\n", This, Flags, CKey);
2435
2436     EnterCriticalSection(&ddraw_cs);
2437     if (CKey)
2438     {
2439         FixedCKey = *CKey;
2440         /* Handle case where dwColorSpaceHighValue < dwColorSpaceLowValue */
2441         if (FixedCKey.dwColorSpaceHighValue < FixedCKey.dwColorSpaceLowValue)
2442             FixedCKey.dwColorSpaceHighValue = FixedCKey.dwColorSpaceLowValue;
2443
2444         switch (Flags & ~DDCKEY_COLORSPACE)
2445         {
2446         case DDCKEY_DESTBLT:
2447             This->surface_desc.ddckCKDestBlt = FixedCKey;
2448             This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
2449             break;
2450
2451         case DDCKEY_DESTOVERLAY:
2452             This->surface_desc.u3.ddckCKDestOverlay = FixedCKey;
2453             This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
2454             break;
2455
2456         case DDCKEY_SRCOVERLAY:
2457             This->surface_desc.ddckCKSrcOverlay = FixedCKey;
2458             This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
2459             break;
2460
2461         case DDCKEY_SRCBLT:
2462             This->surface_desc.ddckCKSrcBlt = FixedCKey;
2463             This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
2464             break;
2465
2466         default:
2467             LeaveCriticalSection(&ddraw_cs);
2468             return DDERR_INVALIDPARAMS;
2469         }
2470     }
2471     else
2472     {
2473         switch (Flags & ~DDCKEY_COLORSPACE)
2474         {
2475         case DDCKEY_DESTBLT:
2476             This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
2477             break;
2478
2479         case DDCKEY_DESTOVERLAY:
2480             This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
2481             break;
2482
2483         case DDCKEY_SRCOVERLAY:
2484             This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
2485             break;
2486
2487         case DDCKEY_SRCBLT:
2488             This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
2489             break;
2490
2491         default:
2492             LeaveCriticalSection(&ddraw_cs);
2493             return DDERR_INVALIDPARAMS;
2494         }
2495     }
2496     ctx.ret = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2497                                           Flags,
2498                                           ctx.CKey);
2499     IDirectDrawSurface7_EnumAttachedSurfaces(iface,
2500                                              &ctx,
2501                                              SetColorKeyEnum);
2502     LeaveCriticalSection(&ddraw_cs);
2503     switch(ctx.ret)
2504     {
2505         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2506         default:                            return ctx.ret;
2507     }
2508 }
2509
2510 /*****************************************************************************
2511  * IDirectDrawSurface7::SetPalette
2512  *
2513  * Assigns a DirectDrawPalette object to the surface
2514  *
2515  * Params:
2516  *  Pal: Interface to the palette to set
2517  *
2518  * Returns:
2519  *  DD_OK on success
2520  *
2521  *****************************************************************************/
2522 static HRESULT WINAPI
2523 IDirectDrawSurfaceImpl_SetPalette(IDirectDrawSurface7 *iface,
2524                                   IDirectDrawPalette *Pal)
2525 {
2526     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2527     IDirectDrawPalette *oldPal;
2528     IDirectDrawSurfaceImpl *surf;
2529     IDirectDrawPaletteImpl *PalImpl = (IDirectDrawPaletteImpl *)Pal;
2530     HRESULT hr;
2531     TRACE("(%p)->(%p)\n", This, Pal);
2532
2533     if (!(This->surface_desc.u4.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
2534             DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8))) {
2535         return DDERR_INVALIDPIXELFORMAT;
2536     }
2537
2538     /* Find the old palette */
2539     EnterCriticalSection(&ddraw_cs);
2540     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2541     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED)
2542     {
2543         LeaveCriticalSection(&ddraw_cs);
2544         return hr;
2545     }
2546     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2547
2548     /* Set the new Palette */
2549     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2550                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2551     /* AddRef the Palette */
2552     if(Pal) IDirectDrawPalette_AddRef(Pal);
2553
2554     /* Release the old palette */
2555     if(oldPal) IDirectDrawPalette_Release(oldPal);
2556
2557     /* If this is a front buffer, also update the back buffers
2558      * TODO: How do things work for palettized cube textures?
2559      */
2560     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2561     {
2562         /* For primary surfaces the tree is just a list, so the simpler scheme fits too */
2563         DDSCAPS2 caps2 = { DDSCAPS_PRIMARYSURFACE, 0, 0, 0 };
2564
2565         surf = This;
2566         while(1)
2567         {
2568             IDirectDrawSurface7 *attach;
2569             HRESULT hr;
2570             hr = IDirectDrawSurface7_GetAttachedSurface((IDirectDrawSurface7 *)surf, &caps2, &attach);
2571             if(hr != DD_OK)
2572             {
2573                 break;
2574             }
2575
2576             TRACE("Setting palette on %p\n", attach);
2577             IDirectDrawSurface7_SetPalette(attach,
2578                                            Pal);
2579             surf = (IDirectDrawSurfaceImpl *)attach;
2580             IDirectDrawSurface7_Release(attach);
2581         }
2582     }
2583
2584     LeaveCriticalSection(&ddraw_cs);
2585     return DD_OK;
2586 }
2587
2588 /*****************************************************************************
2589  * The VTable
2590  *****************************************************************************/
2591
2592 const IDirectDrawSurface7Vtbl IDirectDrawSurface7_Vtbl =
2593 {
2594     /*** IUnknown ***/
2595     IDirectDrawSurfaceImpl_QueryInterface,
2596     IDirectDrawSurfaceImpl_AddRef,
2597     IDirectDrawSurfaceImpl_Release,
2598     /*** IDirectDrawSurface ***/
2599     IDirectDrawSurface7Impl_AddAttachedSurface,
2600     IDirectDrawSurfaceImpl_AddOverlayDirtyRect,
2601     IDirectDrawSurfaceImpl_Blt,
2602     IDirectDrawSurfaceImpl_BltBatch,
2603     IDirectDrawSurfaceImpl_BltFast,
2604     IDirectDrawSurfaceImpl_DeleteAttachedSurface,
2605     IDirectDrawSurfaceImpl_EnumAttachedSurfaces,
2606     IDirectDrawSurfaceImpl_EnumOverlayZOrders,
2607     IDirectDrawSurfaceImpl_Flip,
2608     IDirectDrawSurfaceImpl_GetAttachedSurface,
2609     IDirectDrawSurfaceImpl_GetBltStatus,
2610     IDirectDrawSurfaceImpl_GetCaps,
2611     IDirectDrawSurfaceImpl_GetClipper,
2612     IDirectDrawSurfaceImpl_GetColorKey,
2613     IDirectDrawSurfaceImpl_GetDC,
2614     IDirectDrawSurfaceImpl_GetFlipStatus,
2615     IDirectDrawSurfaceImpl_GetOverlayPosition,
2616     IDirectDrawSurfaceImpl_GetPalette,
2617     IDirectDrawSurfaceImpl_GetPixelFormat,
2618     IDirectDrawSurfaceImpl_GetSurfaceDesc,
2619     IDirectDrawSurfaceImpl_Initialize,
2620     IDirectDrawSurfaceImpl_IsLost,
2621     IDirectDrawSurfaceImpl_Lock,
2622     IDirectDrawSurfaceImpl_ReleaseDC,
2623     IDirectDrawSurfaceImpl_Restore,
2624     IDirectDrawSurfaceImpl_SetClipper,
2625     IDirectDrawSurfaceImpl_SetColorKey,
2626     IDirectDrawSurfaceImpl_SetOverlayPosition,
2627     IDirectDrawSurfaceImpl_SetPalette,
2628     IDirectDrawSurfaceImpl_Unlock,
2629     IDirectDrawSurfaceImpl_UpdateOverlay,
2630     IDirectDrawSurfaceImpl_UpdateOverlayDisplay,
2631     IDirectDrawSurfaceImpl_UpdateOverlayZOrder,
2632     /*** IDirectDrawSurface2 ***/
2633     IDirectDrawSurfaceImpl_GetDDInterface,
2634     IDirectDrawSurfaceImpl_PageLock,
2635     IDirectDrawSurfaceImpl_PageUnlock,
2636     /*** IDirectDrawSurface3 ***/
2637     IDirectDrawSurfaceImpl_SetSurfaceDesc,
2638     /*** IDirectDrawSurface4 ***/
2639     IDirectDrawSurfaceImpl_SetPrivateData,
2640     IDirectDrawSurfaceImpl_GetPrivateData,
2641     IDirectDrawSurfaceImpl_FreePrivateData,
2642     IDirectDrawSurfaceImpl_GetUniquenessValue,
2643     IDirectDrawSurfaceImpl_ChangeUniquenessValue,
2644     /*** IDirectDrawSurface7 ***/
2645     IDirectDrawSurfaceImpl_SetPriority,
2646     IDirectDrawSurfaceImpl_GetPriority,
2647     IDirectDrawSurfaceImpl_SetLOD,
2648     IDirectDrawSurfaceImpl_GetLOD
2649 };