wined3d: Don't require wined3d object parents to be COM objects.
[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 "ddraw_private.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
32
33 static inline IDirectDrawSurfaceImpl *surface_from_gamma_control(IDirectDrawGammaControl *iface)
34 {
35     return (IDirectDrawSurfaceImpl *)((char*)iface
36             - FIELD_OFFSET(IDirectDrawSurfaceImpl, IDirectDrawGammaControl_vtbl));
37 }
38
39 /*****************************************************************************
40  * IUnknown parts follow
41  *****************************************************************************/
42
43 /*****************************************************************************
44  * IDirectDrawSurface7::QueryInterface
45  *
46  * A normal QueryInterface implementation. For QueryInterface rules
47  * see ddraw.c, IDirectDraw7::QueryInterface. This method
48  * can Query IDirectDrawSurface interfaces in all version, IDirect3DTexture
49  * in all versions, the IDirectDrawGammaControl interface and it can
50  * create an IDirect3DDevice. (Uses IDirect3D7::CreateDevice)
51  *
52  * Params:
53  *  riid: The interface id queried for
54  *  obj: Address to write the pointer to
55  *
56  * Returns:
57  *  S_OK on success
58  *  E_NOINTERFACE if the requested interface wasn't found
59  *
60  *****************************************************************************/
61 static HRESULT WINAPI ddraw_surface7_QueryInterface(IDirectDrawSurface7 *iface, REFIID riid, void **obj)
62 {
63     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
64
65     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), obj);
66
67     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
68     *obj = NULL;
69
70     if(!riid)
71         return DDERR_INVALIDPARAMS;
72
73     if (IsEqualGUID(riid, &IID_IUnknown)
74      || IsEqualGUID(riid, &IID_IDirectDrawSurface7)
75      || IsEqualGUID(riid, &IID_IDirectDrawSurface4) )
76     {
77         IUnknown_AddRef(iface);
78         *obj = iface;
79         TRACE("(%p) returning IDirectDrawSurface7 interface at %p\n", This, *obj);
80         return S_OK;
81     }
82     else if( IsEqualGUID(riid, &IID_IDirectDrawSurface3)
83           || IsEqualGUID(riid, &IID_IDirectDrawSurface2)
84           || IsEqualGUID(riid, &IID_IDirectDrawSurface) )
85     {
86         IUnknown_AddRef(iface);
87         *obj = &This->IDirectDrawSurface3_vtbl;
88         TRACE("(%p) returning IDirectDrawSurface3 interface at %p\n", This, *obj);
89         return S_OK;
90     }
91     else if( IsEqualGUID(riid, &IID_IDirectDrawGammaControl) )
92     {
93         IUnknown_AddRef(iface);
94         *obj = &This->IDirectDrawGammaControl_vtbl;
95         TRACE("(%p) returning IDirectDrawGammaControl interface at %p\n", This, *obj);
96         return S_OK;
97     }
98     else if( IsEqualGUID(riid, &IID_D3DDEVICE_WineD3D) ||
99              IsEqualGUID(riid, &IID_IDirect3DHALDevice)||
100              IsEqualGUID(riid, &IID_IDirect3DRGBDevice) )
101     {
102         IDirect3DDevice7 *d3d;
103
104         /* Call into IDirect3D7 for creation */
105         IDirect3D7_CreateDevice((IDirect3D7 *)&This->ddraw->IDirect3D7_vtbl, riid, (IDirectDrawSurface7 *)This, &d3d);
106
107         if (d3d)
108         {
109             *obj = (IDirect3DDevice *)&((IDirect3DDeviceImpl *)d3d)->IDirect3DDevice_vtbl;
110             TRACE("(%p) Returning IDirect3DDevice interface at %p\n", This, *obj);
111             return S_OK;
112         }
113
114         WARN("Unable to create a IDirect3DDevice instance, returning E_NOINTERFACE\n");
115         return E_NOINTERFACE;
116     }
117     else if (IsEqualGUID( &IID_IDirect3DTexture, riid ) ||
118              IsEqualGUID( &IID_IDirect3DTexture2, riid ))
119     {
120         if (IsEqualGUID( &IID_IDirect3DTexture, riid ))
121         {
122             *obj = &This->IDirect3DTexture_vtbl;
123             TRACE(" returning Direct3DTexture interface at %p.\n", *obj);
124         }
125         else
126         {
127             *obj = &This->IDirect3DTexture2_vtbl;
128             TRACE(" returning Direct3DTexture2 interface at %p.\n", *obj);
129         }
130         IUnknown_AddRef( (IUnknown *) *obj);
131         return S_OK;
132     }
133
134     ERR("No interface\n");
135     return E_NOINTERFACE;
136 }
137
138 static HRESULT WINAPI ddraw_surface3_QueryInterface(IDirectDrawSurface3 *iface, REFIID riid, void **object)
139 {
140     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
141
142     return ddraw_surface7_QueryInterface((IDirectDrawSurface7 *)surface_from_surface3(iface), riid, object);
143 }
144
145 static HRESULT WINAPI ddraw_gamma_control_QueryInterface(IDirectDrawGammaControl *iface, REFIID riid, void **object)
146 {
147     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
148
149     return ddraw_surface7_QueryInterface((IDirectDrawSurface7 *)surface_from_gamma_control(iface), riid, object);
150 }
151
152 static HRESULT WINAPI d3d_texture2_QueryInterface(IDirect3DTexture2 *iface, REFIID riid, void **object)
153 {
154     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
155
156     return ddraw_surface7_QueryInterface((IDirectDrawSurface7 *)surface_from_texture2(iface), riid, object);
157 }
158
159 static HRESULT WINAPI d3d_texture1_QueryInterface(IDirect3DTexture *iface, REFIID riid, void **object)
160 {
161     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
162
163     return ddraw_surface7_QueryInterface((IDirectDrawSurface7 *)surface_from_texture1(iface), riid, object);
164 }
165
166 /*****************************************************************************
167  * IDirectDrawSurface7::AddRef
168  *
169  * A normal addref implementation
170  *
171  * Returns:
172  *  The new refcount
173  *
174  *****************************************************************************/
175 static ULONG WINAPI ddraw_surface7_AddRef(IDirectDrawSurface7 *iface)
176 {
177     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
178     ULONG refCount = InterlockedIncrement(&This->ref);
179
180     TRACE("%p increasing refcount to %u.\n", This, refCount);
181
182     if (refCount == 1 && This->WineD3DSurface)
183     {
184         EnterCriticalSection(&ddraw_cs);
185         IWineD3DSurface_AddRef(This->WineD3DSurface);
186         LeaveCriticalSection(&ddraw_cs);
187     }
188
189     return refCount;
190 }
191
192 static ULONG WINAPI ddraw_surface3_AddRef(IDirectDrawSurface3 *iface)
193 {
194     TRACE("iface %p.\n", iface);
195
196     return ddraw_surface7_AddRef((IDirectDrawSurface7 *)surface_from_surface3(iface));
197 }
198
199 static ULONG WINAPI ddraw_gamma_control_AddRef(IDirectDrawGammaControl *iface)
200 {
201     TRACE("iface %p.\n", iface);
202
203     return ddraw_surface7_AddRef((IDirectDrawSurface7 *)surface_from_gamma_control(iface));
204 }
205
206 static ULONG WINAPI d3d_texture2_AddRef(IDirect3DTexture2 *iface)
207 {
208     TRACE("iface %p.\n", iface);
209
210     return ddraw_surface7_AddRef((IDirectDrawSurface7 *)surface_from_texture2(iface));
211 }
212
213 static ULONG WINAPI d3d_texture1_AddRef(IDirect3DTexture *iface)
214 {
215     TRACE("iface %p.\n", iface);
216
217     return ddraw_surface7_AddRef((IDirectDrawSurface7 *)surface_from_texture1(iface));
218 }
219
220 /*****************************************************************************
221  * ddraw_surface_destroy
222  *
223  * A helper function for IDirectDrawSurface7::Release
224  *
225  * Frees the surface, regardless of its refcount.
226  *  See IDirectDrawSurface7::Release for more information
227  *
228  * Params:
229  *  This: Surface to free
230  *
231  *****************************************************************************/
232 void ddraw_surface_destroy(IDirectDrawSurfaceImpl *This)
233 {
234     TRACE("surface %p.\n", This);
235
236     /* Check the refcount and give a warning */
237     if(This->ref > 1)
238     {
239         /* This can happen when a complex surface is destroyed,
240          * because the 2nd surface was addref()ed when the app
241          * called GetAttachedSurface
242          */
243         WARN("(%p): Destroying surface with refount %d\n", This, This->ref);
244     }
245
246     /* Check for attached surfaces and detach them */
247     if(This->first_attached != This)
248     {
249         /* Well, this shouldn't happen: The surface being attached is addref()ed
250           * in AddAttachedSurface, so it shouldn't be released until DeleteAttachedSurface
251           * is called, because the refcount is held. It looks like the app released()
252           * it often enough to force this
253           */
254         IDirectDrawSurface7 *root = (IDirectDrawSurface7 *)This->first_attached;
255         IDirectDrawSurface7 *detach = (IDirectDrawSurface7 *)This;
256
257         FIXME("(%p) Freeing a surface that is attached to surface %p\n", This, This->first_attached);
258
259         /* The refcount will drop to -1 here */
260         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
261         {
262             ERR("(%p) DeleteAttachedSurface failed!\n", This);
263         }
264     }
265
266     while(This->next_attached != NULL)
267     {
268         IDirectDrawSurface7 *root = (IDirectDrawSurface7 *)This;
269         IDirectDrawSurface7 *detach = (IDirectDrawSurface7 *)This->next_attached;
270
271         if(IDirectDrawSurface7_DeleteAttachedSurface(root, 0, detach) != DD_OK)
272         {
273             ERR("(%p) DeleteAttachedSurface failed!\n", This);
274             assert(0);
275         }
276     }
277
278     /* Now destroy the surface. Wait: It could have been released if we are a texture */
279     if(This->WineD3DSurface)
280         IWineD3DSurface_Release(This->WineD3DSurface);
281
282     /* Having a texture handle set implies that the device still exists */
283     if(This->Handle)
284     {
285         ddraw_free_handle(&This->ddraw->d3ddevice->handle_table, This->Handle - 1, DDRAW_HANDLE_SURFACE);
286     }
287
288     /* Reduce the ddraw surface count */
289     InterlockedDecrement(&This->ddraw->surfaces);
290     list_remove(&This->surface_list_entry);
291
292     HeapFree(GetProcessHeap(), 0, This);
293 }
294
295 /*****************************************************************************
296  * IDirectDrawSurface7::Release
297  *
298  * Reduces the surface's refcount by 1. If the refcount falls to 0, the
299  * surface is destroyed.
300  *
301  * Destroying the surface is a bit tricky. For the connection between
302  * WineD3DSurfaces and DirectDrawSurfaces see IDirectDraw7::CreateSurface
303  * It has a nice graph explaining the connection.
304  *
305  * What happens here is basically this:
306  * When a surface is destroyed, its WineD3DSurface is released,
307  * and the refcount of the DirectDraw interface is reduced by 1. If it has
308  * complex surfaces attached to it, then these surfaces are destroyed too,
309  * regardless of their refcount. If any surface being destroyed has another
310  * surface attached to it (with a "soft" attachment, not complex), then
311  * this surface is detached with DeleteAttachedSurface.
312  *
313  * When the surface is a texture, the WineD3DTexture is released.
314  * If the surface is the Direct3D render target, then the D3D
315  * capabilities of the WineD3DDevice are uninitialized, which causes the
316  * swapchain to be released.
317  *
318  * When a complex sublevel falls to ref zero, then this is ignored.
319  *
320  * Returns:
321  *  The new refcount
322  *
323  *****************************************************************************/
324 static ULONG WINAPI ddraw_surface7_Release(IDirectDrawSurface7 *iface)
325 {
326     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
327     ULONG ref = InterlockedDecrement(&This->ref);
328
329     TRACE("%p decreasing refcount to %u.\n", This, ref);
330
331     if (ref == 0)
332     {
333
334         IDirectDrawSurfaceImpl *surf;
335         IDirectDrawImpl *ddraw;
336         IUnknown *ifaceToRelease = This->ifaceToRelease;
337         UINT i;
338
339         /* Complex attached surfaces are destroyed implicitly when the root is released */
340         EnterCriticalSection(&ddraw_cs);
341         if(!This->is_complex_root)
342         {
343             WARN("(%p) Attempt to destroy a surface that is not a complex root\n", This);
344             LeaveCriticalSection(&ddraw_cs);
345             return ref;
346         }
347         ddraw = This->ddraw;
348
349         /* If it's a texture, destroy the WineD3DTexture.
350          * WineD3D will destroy the IParent interfaces
351          * of the sublevels, which destroys the WineD3DSurfaces.
352          * Set the surfaces to NULL to avoid destroying them again later
353          */
354         if(This->wineD3DTexture)
355         {
356             IWineD3DBaseTexture_Release(This->wineD3DTexture);
357         }
358         /* If it's the RenderTarget, destroy the d3ddevice */
359         else if(This->wineD3DSwapChain)
360         {
361             if((ddraw->d3d_initialized) && (This == ddraw->d3d_target)) {
362                 TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
363
364                 /* Unset any index buffer, just to be sure */
365                 IWineD3DDevice_SetIndexBuffer(ddraw->wineD3DDevice, NULL, WINED3DFMT_UNKNOWN);
366                 IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
367                 IWineD3DDevice_SetVertexDeclaration(ddraw->wineD3DDevice, NULL);
368                 for(i = 0; i < ddraw->numConvertedDecls; i++)
369                 {
370                     IWineD3DVertexDeclaration_Release(ddraw->decls[i].decl);
371                 }
372                 HeapFree(GetProcessHeap(), 0, ddraw->decls);
373                 ddraw->numConvertedDecls = 0;
374
375                 if (FAILED(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain)))
376                 {
377                     /* Not good */
378                     ERR("(%p) Failed to uninit 3D\n", This);
379                 }
380                 else
381                 {
382                     /* Free the d3d window if one was created */
383                     if(ddraw->d3d_window != 0 && ddraw->d3d_window != ddraw->dest_window)
384                     {
385                         TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
386                         DestroyWindow(ddraw->d3d_window);
387                         ddraw->d3d_window = 0;
388                     }
389                     /* Unset the pointers */
390                 }
391
392                 This->wineD3DSwapChain = NULL; /* Uninit3D releases the swapchain */
393                 ddraw->d3d_initialized = FALSE;
394                 ddraw->d3d_target = NULL;
395             } else {
396                 IWineD3DDevice_UninitGDI(ddraw->wineD3DDevice, D3D7CB_DestroySwapChain);
397                 This->wineD3DSwapChain = NULL;
398             }
399
400             /* Reset to the default surface implementation type. This is needed if apps use
401              * non render target surfaces and expect blits to work after destroying the render
402              * target.
403              *
404              * TODO: Recreate existing offscreen surfaces
405              */
406             ddraw->ImplType = DefaultSurfaceType;
407
408             /* Write a trace because D3D unloading was the reason for many
409              * crashes during development.
410              */
411             TRACE("(%p) D3D unloaded\n", This);
412         }
413
414         /* The refcount test shows that the palette is detached when the surface is destroyed */
415         IDirectDrawSurface7_SetPalette((IDirectDrawSurface7 *)This, NULL);
416
417         /* Loop through all complex attached surfaces,
418          * and destroy them.
419          *
420          * Yet again, only the root can have more than one complexly attached surface, all the others
421          * have a total of one;
422          */
423         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
424         {
425             if(!This->complex_array[i]) break;
426
427             surf = This->complex_array[i];
428             This->complex_array[i] = NULL;
429             while(surf)
430             {
431                 IDirectDrawSurfaceImpl *destroy = surf;
432                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
433                 ddraw_surface_destroy(destroy);             /* Destroy it */
434             }
435         }
436
437         /* Destroy the root surface. */
438         ddraw_surface_destroy(This);
439
440         /* Reduce the ddraw refcount */
441         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
442         LeaveCriticalSection(&ddraw_cs);
443     }
444
445     return ref;
446 }
447
448 static ULONG WINAPI ddraw_surface3_Release(IDirectDrawSurface3 *iface)
449 {
450     TRACE("iface %p.\n", iface);
451
452     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_surface3(iface));
453 }
454
455 static ULONG WINAPI ddraw_gamma_control_Release(IDirectDrawGammaControl *iface)
456 {
457     TRACE("iface %p.\n", iface);
458
459     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_gamma_control(iface));
460 }
461
462 static ULONG WINAPI d3d_texture2_Release(IDirect3DTexture2 *iface)
463 {
464     TRACE("iface %p.\n", iface);
465
466     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_texture2(iface));
467 }
468
469 static ULONG WINAPI d3d_texture1_Release(IDirect3DTexture *iface)
470 {
471     TRACE("iface %p.\n", iface);
472
473     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_texture1(iface));
474 }
475
476 /*****************************************************************************
477  * IDirectDrawSurface7::GetAttachedSurface
478  *
479  * Returns an attached surface with the requested caps. Surface attachment
480  * and complex surfaces are not clearly described by the MSDN or sdk,
481  * so this method is tricky and likely to contain problems.
482  * This implementation searches the complex list first, then the
483  * attachment chain.
484  *
485  * The chains are searched from This down to the last surface in the chain,
486  * not from the first element in the chain. The first surface found is
487  * returned. The MSDN says that this method fails if more than one surface
488  * matches the caps, but it is not sure if that is right. The attachment
489  * structure may not even allow two matching surfaces.
490  *
491  * The found surface is AddRef-ed before it is returned.
492  *
493  * Params:
494  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
495  *  Surface: Address to store the found surface
496  *
497  * Returns:
498  *  DD_OK on success
499  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
500  *  DDERR_NOTFOUND if no surface was found
501  *
502  *****************************************************************************/
503 static HRESULT WINAPI ddraw_surface7_GetAttachedSurface(IDirectDrawSurface7 *iface,
504         DDSCAPS2 *Caps, IDirectDrawSurface7 **Surface)
505 {
506     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
507     IDirectDrawSurfaceImpl *surf;
508     DDSCAPS2 our_caps;
509     int i;
510
511     TRACE("iface %p, caps %p, attachment %p.\n", iface, Caps, Surface);
512
513     EnterCriticalSection(&ddraw_cs);
514
515     if(This->version < 7)
516     {
517         /* Earlier dx apps put garbage into these members, clear them */
518         our_caps.dwCaps = Caps->dwCaps;
519         our_caps.dwCaps2 = 0;
520         our_caps.dwCaps3 = 0;
521         our_caps.dwCaps4 = 0;
522     }
523     else
524     {
525         our_caps = *Caps;
526     }
527
528     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 */
529
530     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
531     {
532         surf = This->complex_array[i];
533         if(!surf) break;
534
535         if (TRACE_ON(ddraw))
536         {
537             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
538                    surf->surface_desc.ddsCaps.dwCaps,
539                    surf->surface_desc.ddsCaps.dwCaps2,
540                    surf->surface_desc.ddsCaps.dwCaps3,
541                    surf->surface_desc.ddsCaps.dwCaps4);
542         }
543
544         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
545             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
546
547             /* MSDN: "This method fails if more than one surface is attached
548              * that matches the capabilities requested."
549              *
550              * Not sure how to test this.
551              */
552
553             TRACE("(%p): Returning surface %p\n", This, surf);
554             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
555             *Surface = (IDirectDrawSurface7 *)surf;
556             ddraw_surface7_AddRef(*Surface);
557             LeaveCriticalSection(&ddraw_cs);
558             return DD_OK;
559         }
560     }
561
562     /* Next, look at the attachment chain */
563     surf = This;
564
565     while( (surf = surf->next_attached) )
566     {
567         if (TRACE_ON(ddraw))
568         {
569             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
570                    surf->surface_desc.ddsCaps.dwCaps,
571                    surf->surface_desc.ddsCaps.dwCaps2,
572                    surf->surface_desc.ddsCaps.dwCaps3,
573                    surf->surface_desc.ddsCaps.dwCaps4);
574         }
575
576         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
577             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
578
579             TRACE("(%p): Returning surface %p\n", This, surf);
580             *Surface = (IDirectDrawSurface7 *)surf;
581             ddraw_surface7_AddRef(*Surface);
582             LeaveCriticalSection(&ddraw_cs);
583             return DD_OK;
584         }
585     }
586
587     TRACE("(%p) Didn't find a valid surface\n", This);
588     LeaveCriticalSection(&ddraw_cs);
589
590     *Surface = NULL;
591     return DDERR_NOTFOUND;
592 }
593
594 static HRESULT WINAPI ddraw_surface3_GetAttachedSurface(IDirectDrawSurface3 *iface,
595         DDSCAPS *caps, IDirectDrawSurface3 **attachment)
596 {
597     IDirectDrawSurface7 *attachment7;
598     DDSCAPS2 caps2;
599     HRESULT hr;
600
601     TRACE("iface %p, caps %p, attachment %p.\n", iface, caps, attachment);
602
603     caps2.dwCaps  = caps->dwCaps;
604     caps2.dwCaps2 = 0;
605     caps2.dwCaps3 = 0;
606     caps2.dwCaps4 = 0;
607
608     hr = ddraw_surface7_GetAttachedSurface((IDirectDrawSurface7 *)surface_from_surface3(iface),
609             &caps2, &attachment7);
610     if (FAILED(hr)) *attachment = NULL;
611     else *attachment = attachment7 ?
612             (IDirectDrawSurface3 *)&((IDirectDrawSurfaceImpl *)attachment7)->IDirectDrawSurface3_vtbl : NULL;
613
614     return hr;
615 }
616
617 /*****************************************************************************
618  * IDirectDrawSurface7::Lock
619  *
620  * Locks the surface and returns a pointer to the surface's memory
621  *
622  * Params:
623  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
624  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
625  *  Flags: Locking flags, e.g Read only or write only
626  *  h: An event handle that's not used and must be NULL
627  *
628  * Returns:
629  *  DD_OK on success
630  *  DDERR_INVALIDPARAMS if DDSD is NULL
631  *  For more details, see IWineD3DSurface::LockRect
632  *
633  *****************************************************************************/
634 static HRESULT WINAPI ddraw_surface7_Lock(IDirectDrawSurface7 *iface,
635         RECT *Rect, DDSURFACEDESC2 *DDSD, DWORD Flags, HANDLE h)
636 {
637     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
638     WINED3DLOCKED_RECT LockedRect;
639     HRESULT hr;
640
641     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
642             iface, wine_dbgstr_rect(Rect), DDSD, Flags, h);
643
644     if(!DDSD)
645         return DDERR_INVALIDPARAMS;
646
647     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
648     EnterCriticalSection(&ddraw_cs);
649
650     /* Should I check for the handle to be NULL?
651      *
652      * The DDLOCK flags and the D3DLOCK flags are equal
653      * for the supported values. The others are ignored by WineD3D
654      */
655
656     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
657        DDSD->dwSize != sizeof(DDSURFACEDESC2))
658     {
659         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
660         LeaveCriticalSection(&ddraw_cs);
661         return DDERR_INVALIDPARAMS;
662     }
663
664     /* Windows zeroes this if the rect is invalid */
665     DDSD->lpSurface = 0;
666
667     if (Rect)
668     {
669         if ((Rect->left < 0)
670                 || (Rect->top < 0)
671                 || (Rect->left > Rect->right)
672                 || (Rect->top > Rect->bottom)
673                 || (Rect->right > This->surface_desc.dwWidth)
674                 || (Rect->bottom > This->surface_desc.dwHeight))
675         {
676             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
677             LeaveCriticalSection(&ddraw_cs);
678             return DDERR_INVALIDPARAMS;
679         }
680     }
681
682     hr = IWineD3DSurface_LockRect(This->WineD3DSurface,
683                                   &LockedRect,
684                                   Rect,
685                                   Flags);
686     if(hr != D3D_OK)
687     {
688         LeaveCriticalSection(&ddraw_cs);
689         switch(hr)
690         {
691             /* D3D8 and D3D9 return the general D3DERR_INVALIDCALL error, but ddraw has a more
692              * specific error. But since IWineD3DSurface::LockRect returns that error in this
693              * only occasion, keep d3d8 and d3d9 free from the return value override. There are
694              * many different places where d3d8/9 would have to catch the DDERR_SURFACEBUSY, it
695              * is much easier to do it in one place in ddraw
696              */
697             case WINED3DERR_INVALIDCALL:    return DDERR_SURFACEBUSY;
698             default:                        return hr;
699         }
700     }
701
702     /* Override the memory area. The pitch should be set already. Strangely windows
703      * does not set the LPSURFACE flag on locked surfaces !?!.
704      * DDSD->dwFlags |= DDSD_LPSURFACE;
705      */
706     This->surface_desc.lpSurface = LockedRect.pBits;
707     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
708
709     TRACE("locked surface returning description :\n");
710     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
711
712     LeaveCriticalSection(&ddraw_cs);
713     return DD_OK;
714 }
715
716 static HRESULT WINAPI ddraw_surface3_Lock(IDirectDrawSurface3 *iface, RECT *rect,
717         DDSURFACEDESC *surface_desc, DWORD flags, HANDLE h)
718 {
719     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
720             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
721
722     return ddraw_surface7_Lock((IDirectDrawSurface7 *)surface_from_surface3(iface),
723             rect, (DDSURFACEDESC2 *)surface_desc, flags, h);
724 }
725
726 /*****************************************************************************
727  * IDirectDrawSurface7::Unlock
728  *
729  * Unlocks an locked surface
730  *
731  * Params:
732  *  Rect: Not used by this implementation
733  *
734  * Returns:
735  *  D3D_OK on success
736  *  For more details, see IWineD3DSurface::UnlockRect
737  *
738  *****************************************************************************/
739 static HRESULT WINAPI ddraw_surface7_Unlock(IDirectDrawSurface7 *iface, RECT *pRect)
740 {
741     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
742     HRESULT hr;
743
744     TRACE("iface %p, rect %s.\n", iface, wine_dbgstr_rect(pRect));
745
746     EnterCriticalSection(&ddraw_cs);
747     hr = IWineD3DSurface_UnlockRect(This->WineD3DSurface);
748     if(SUCCEEDED(hr))
749     {
750         This->surface_desc.lpSurface = NULL;
751     }
752     LeaveCriticalSection(&ddraw_cs);
753     return hr;
754 }
755
756 static HRESULT WINAPI ddraw_surface3_Unlock(IDirectDrawSurface3 *iface, void *data)
757 {
758     TRACE("iface %p, data %p.\n", iface, data);
759
760     /* data might not be the LPRECT of later versions, so drop it. */
761     return ddraw_surface7_Unlock((IDirectDrawSurface7 *)surface_from_surface3(iface), NULL);
762 }
763
764 /*****************************************************************************
765  * IDirectDrawSurface7::Flip
766  *
767  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
768  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
769  * the flip target is passed to WineD3D, even if the app didn't specify one
770  *
771  * Params:
772  *  DestOverride: Specifies the surface that will become the new front
773  *                buffer. If NULL, the current back buffer is used
774  *  Flags: some DirectDraw flags, see include/ddraw.h
775  *
776  * Returns:
777  *  DD_OK on success
778  *  DDERR_NOTFLIPPABLE if no flip target could be found
779  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
780  *  For more details, see IWineD3DSurface::Flip
781  *
782  *****************************************************************************/
783 static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDrawSurface7 *DestOverride, DWORD Flags)
784 {
785     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
786     IDirectDrawSurfaceImpl *Override = (IDirectDrawSurfaceImpl *)DestOverride;
787     IDirectDrawSurface7 *Override7;
788     HRESULT hr;
789
790     TRACE("iface %p, dst %p, flags %#x.\n", iface, DestOverride, Flags);
791
792     /* Flip has to be called from a front buffer
793      * What about overlay surfaces, AFAIK they can flip too?
794      */
795     if( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY)) )
796         return DDERR_INVALIDOBJECT; /* Unchecked */
797
798     EnterCriticalSection(&ddraw_cs);
799
800     /* WineD3D doesn't keep track of attached surface, so find the target */
801     if(!Override)
802     {
803         DDSCAPS2 Caps;
804
805         memset(&Caps, 0, sizeof(Caps));
806         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
807         hr = ddraw_surface7_GetAttachedSurface(iface, &Caps, &Override7);
808         if(hr != DD_OK)
809         {
810             ERR("Can't find a flip target\n");
811             LeaveCriticalSection(&ddraw_cs);
812             return DDERR_NOTFLIPPABLE; /* Unchecked */
813         }
814         Override = (IDirectDrawSurfaceImpl *)Override7;
815
816         /* For the GetAttachedSurface */
817         ddraw_surface7_Release(Override7);
818     }
819
820     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
821                               Override->WineD3DSurface,
822                               Flags);
823     LeaveCriticalSection(&ddraw_cs);
824     return hr;
825 }
826
827 static HRESULT WINAPI ddraw_surface3_Flip(IDirectDrawSurface3 *iface, IDirectDrawSurface3 *dst, DWORD flags)
828 {
829     TRACE("iface %p, dst %p, flags %#x.\n", iface, dst, flags);
830
831     return ddraw_surface7_Flip((IDirectDrawSurface7 *)surface_from_surface3(iface),
832             dst ? (IDirectDrawSurface7 *)surface_from_surface3(dst) : NULL, flags);
833 }
834
835 /*****************************************************************************
836  * IDirectDrawSurface7::Blt
837  *
838  * Performs a blit on the surface
839  *
840  * Params:
841  *  DestRect: Destination rectangle, can be NULL
842  *  SrcSurface: Source surface, can be NULL
843  *  SrcRect: Source rectangle, can be NULL
844  *  Flags: Blt flags
845  *  DDBltFx: Some extended blt parameters, connected to the flags
846  *
847  * Returns:
848  *  D3D_OK on success
849  *  See IWineD3DSurface::Blt for more details
850  *
851  *****************************************************************************/
852 static HRESULT WINAPI ddraw_surface7_Blt(IDirectDrawSurface7 *iface, RECT *DestRect,
853         IDirectDrawSurface7 *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx)
854 {
855     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
856     IDirectDrawSurfaceImpl *Src = (IDirectDrawSurfaceImpl *)SrcSurface;
857     HRESULT hr;
858
859     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %p, flags %#x, fx %p.\n",
860             iface, wine_dbgstr_rect(DestRect), SrcSurface, wine_dbgstr_rect(SrcRect), Flags, DDBltFx);
861
862     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
863      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
864      */
865     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
866         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
867         return DDERR_INVALIDPARAMS;
868     }
869
870     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
871         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
872         return DDERR_INVALIDPARAMS;
873     }
874
875     /* Sizes can change, therefore hold the lock when testing the rectangles */
876     EnterCriticalSection(&ddraw_cs);
877     if(DestRect)
878     {
879         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
880            DestRect->right > This->surface_desc.dwWidth ||
881            DestRect->bottom > This->surface_desc.dwHeight)
882         {
883             WARN("Destination rectangle is invalid, returning DDERR_INVALIDRECT\n");
884             LeaveCriticalSection(&ddraw_cs);
885             return DDERR_INVALIDRECT;
886         }
887     }
888     if(Src && SrcRect)
889     {
890         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
891            SrcRect->right > Src->surface_desc.dwWidth ||
892            SrcRect->bottom > Src->surface_desc.dwHeight)
893         {
894             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
895             LeaveCriticalSection(&ddraw_cs);
896             return DDERR_INVALIDRECT;
897         }
898     }
899
900     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
901         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
902         LeaveCriticalSection(&ddraw_cs);
903         return DDERR_INVALIDPARAMS;
904     }
905
906     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
907      * and replace the ddraw surfaces with the wined3d surfaces
908      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
909      */
910     hr = IWineD3DSurface_Blt(This->WineD3DSurface,
911                              DestRect,
912                              Src ? Src->WineD3DSurface : NULL,
913                              SrcRect,
914                              Flags,
915                              (WINEDDBLTFX *) DDBltFx,
916                              WINED3DTEXF_POINT);
917
918     LeaveCriticalSection(&ddraw_cs);
919     switch(hr)
920     {
921         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
922         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
923         default:                            return hr;
924     }
925 }
926
927 static HRESULT WINAPI ddraw_surface3_Blt(IDirectDrawSurface3 *iface, RECT *dst_rect,
928         IDirectDrawSurface3 *src_surface, RECT *src_rect, DWORD flags, DDBLTFX *fx)
929 {
930     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %p, flags %#x, fx %p.\n",
931             iface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect), flags, fx);
932
933     return ddraw_surface7_Blt((IDirectDrawSurface7 *)surface_from_surface3(iface), dst_rect,
934             src_surface ? (IDirectDrawSurface7 *)surface_from_surface3(src_surface) : NULL, src_rect, flags, fx);
935 }
936
937 /*****************************************************************************
938  * IDirectDrawSurface7::AddAttachedSurface
939  *
940  * Attaches a surface to another surface. How the surface attachments work
941  * is not totally understood yet, and this method is prone to problems.
942  * he surface that is attached is AddRef-ed.
943  *
944  * Tests with complex surfaces suggest that the surface attachments form a
945  * tree, but no method to test this has been found yet.
946  *
947  * The attachment list consists of a first surface (first_attached) and
948  * for each surface a pointer to the next attached surface (next_attached).
949  * For the first surface, and a surface that has no attachments
950  * first_attached points to the surface itself. A surface that has
951  * no successors in the chain has next_attached set to NULL.
952  *
953  * Newly attached surfaces are attached right after the root surface.
954  * If a surface is attached to a complex surface compound, it's attached to
955  * the surface that the app requested, not the complex root. See
956  * GetAttachedSurface for a description how surfaces are found.
957  *
958  * This is how the current implementation works, and it was coded by looking
959  * at the needs of the applications.
960  *
961  * So far only Z-Buffer attachments are tested, and they are activated in
962  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
963  * Back buffers should work in 2D mode, but they are not tested(They can be
964  * attached in older iface versions). Rendering to the front buffer and
965  * switching between that and double buffering is not yet implemented in
966  * WineD3D, so for 3D it might have unexpected results.
967  *
968  * ddraw_surface_attach_surface is the real thing,
969  * ddraw_surface7_AddAttachedSurface is a wrapper around it that
970  * performs additional checks. Version 7 of this interface is much more restrictive
971  * than its predecessors.
972  *
973  * Params:
974  *  Attach: Surface to attach to iface
975  *
976  * Returns:
977  *  DD_OK on success
978  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
979  *
980  *****************************************************************************/
981 static HRESULT ddraw_surface_attach_surface(IDirectDrawSurfaceImpl *This, IDirectDrawSurfaceImpl *Surf)
982 {
983     TRACE("surface %p, attachment %p.\n", This, Surf);
984
985     if(Surf == This)
986         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
987
988     EnterCriticalSection(&ddraw_cs);
989
990     /* Check if the surface is already attached somewhere */
991     if (Surf->next_attached || Surf->first_attached != Surf)
992     {
993         /* TODO: Test for the structure of the manual attachment. Is it a
994          * chain or a list? What happens if one surface is attached to 2
995          * different surfaces? */
996         WARN("Surface %p is already attached somewhere. next_attached %p, first_attached %p.\n",
997                 Surf, Surf->next_attached, Surf->first_attached);
998
999         LeaveCriticalSection(&ddraw_cs);
1000         return DDERR_SURFACEALREADYATTACHED;
1001     }
1002
1003     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
1004     Surf->next_attached = This->next_attached;
1005     Surf->first_attached = This->first_attached;
1006     This->next_attached = Surf;
1007
1008     /* Check if the WineD3D depth stencil needs updating */
1009     if(This->ddraw->d3ddevice)
1010     {
1011         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
1012     }
1013
1014     ddraw_surface7_AddRef((IDirectDrawSurface7 *)Surf);
1015     LeaveCriticalSection(&ddraw_cs);
1016     return DD_OK;
1017 }
1018
1019 static HRESULT WINAPI ddraw_surface7_AddAttachedSurface(IDirectDrawSurface7 *iface, IDirectDrawSurface7 *Attach)
1020 {
1021     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1022     IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Attach;
1023
1024     TRACE("iface %p, attachment %p.\n", iface, Attach);
1025
1026     /* Version 7 of this interface seems to refuse everything except z buffers, as per msdn */
1027     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
1028     {
1029
1030         WARN("Application tries to attach a non Z buffer surface. caps %08x\n",
1031               Surf->surface_desc.ddsCaps.dwCaps);
1032         return DDERR_CANNOTATTACHSURFACE;
1033     }
1034
1035     return ddraw_surface_attach_surface(This, Surf);
1036 }
1037
1038 static HRESULT WINAPI ddraw_surface3_AddAttachedSurface(IDirectDrawSurface3 *iface, IDirectDrawSurface3 *attachment)
1039 {
1040     IDirectDrawSurfaceImpl *surface = surface_from_surface3(iface);
1041     IDirectDrawSurfaceImpl *attach_impl = surface_from_surface3(attachment);
1042
1043     TRACE("iface %p, attachment %p.\n", iface, attachment);
1044
1045     /* Tests suggest that
1046      * -> offscreen plain surfaces can be attached to other offscreen plain surfaces
1047      * -> offscreen plain surfaces can be attached to primaries
1048      * -> primaries can be attached to offscreen plain surfaces
1049      * -> z buffers can be attached to primaries */
1050     if (surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_OFFSCREENPLAIN)
1051             && attach_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_OFFSCREENPLAIN))
1052     {
1053         /* Sizes have to match */
1054         if (attach_impl->surface_desc.dwWidth != surface->surface_desc.dwWidth
1055                 || attach_impl->surface_desc.dwHeight != surface->surface_desc.dwHeight)
1056         {
1057             WARN("Surface sizes do not match.\n");
1058             return DDERR_CANNOTATTACHSURFACE;
1059         }
1060         /* OK */
1061     }
1062     else if (surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE)
1063             && attach_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER))
1064     {
1065         /* OK */
1066     }
1067     else
1068     {
1069         WARN("Invalid attachment combination.\n");
1070         return DDERR_CANNOTATTACHSURFACE;
1071     }
1072
1073     return ddraw_surface_attach_surface(surface, attach_impl);
1074 }
1075
1076 /*****************************************************************************
1077  * IDirectDrawSurface7::DeleteAttachedSurface
1078  *
1079  * Removes a surface from the attachment chain. The surface's refcount
1080  * is decreased by one after it has been removed
1081  *
1082  * Params:
1083  *  Flags: Some flags, not used by this implementation
1084  *  Attach: Surface to detach
1085  *
1086  * Returns:
1087  *  DD_OK on success
1088  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
1089  *
1090  *****************************************************************************/
1091 static HRESULT WINAPI ddraw_surface7_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
1092         DWORD Flags, IDirectDrawSurface7 *Attach)
1093 {
1094     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1095     IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Attach;
1096     IDirectDrawSurfaceImpl *Prev = This;
1097
1098     TRACE("iface %p, flags %#x, attachment %p.\n", iface, Flags, Attach);
1099
1100     EnterCriticalSection(&ddraw_cs);
1101     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
1102     {
1103         LeaveCriticalSection(&ddraw_cs);
1104         return DDERR_CANNOTDETACHSURFACE;
1105     }
1106
1107     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
1108     if (This->surface_desc.ddsCaps.dwCaps &
1109         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
1110     {
1111         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
1112         /* FIXME: we should probably also subtract from dwMipMapCount of this
1113          * and all parent surfaces */
1114     }
1115
1116     /* Find the predecessor of the detached surface */
1117     while(Prev)
1118     {
1119         if(Prev->next_attached == Surf) break;
1120         Prev = Prev->next_attached;
1121     }
1122
1123     /* There must be a surface, otherwise there's a bug */
1124     assert(Prev != NULL);
1125
1126     /* Unchain the surface */
1127     Prev->next_attached = Surf->next_attached;
1128     Surf->next_attached = NULL;
1129     Surf->first_attached = Surf;
1130
1131     /* Check if the WineD3D depth stencil needs updating */
1132     if(This->ddraw->d3ddevice)
1133     {
1134         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
1135     }
1136
1137     ddraw_surface7_Release(Attach);
1138     LeaveCriticalSection(&ddraw_cs);
1139     return DD_OK;
1140 }
1141
1142 static HRESULT WINAPI ddraw_surface3_DeleteAttachedSurface(IDirectDrawSurface3 *iface,
1143         DWORD flags, IDirectDrawSurface3 *attachment)
1144 {
1145     TRACE("iface %p, flags %#x, attachment %p.\n", iface, flags, attachment);
1146
1147     return ddraw_surface7_DeleteAttachedSurface((IDirectDrawSurface7 *)surface_from_surface3(iface), flags,
1148             attachment ? (IDirectDrawSurface7 *)surface_from_surface3(attachment) : NULL);
1149 }
1150
1151 /*****************************************************************************
1152  * IDirectDrawSurface7::AddOverlayDirtyRect
1153  *
1154  * "This method is not currently implemented"
1155  *
1156  * Params:
1157  *  Rect: ?
1158  *
1159  * Returns:
1160  *  DDERR_UNSUPPORTED
1161  *
1162  *****************************************************************************/
1163 static HRESULT WINAPI ddraw_surface7_AddOverlayDirtyRect(IDirectDrawSurface7 *iface, RECT *Rect)
1164 {
1165     TRACE("iface %p, rect %s.\n", iface, wine_dbgstr_rect(Rect));
1166
1167     return DDERR_UNSUPPORTED; /* unchecked */
1168 }
1169
1170 static HRESULT WINAPI ddraw_surface3_AddOverlayDirtyRect(IDirectDrawSurface3 *iface, RECT *rect)
1171 {
1172     TRACE("iface %p, rect %s.\n", iface, wine_dbgstr_rect(rect));
1173
1174     return ddraw_surface7_AddOverlayDirtyRect((IDirectDrawSurface7 *)surface_from_surface3(iface), rect);
1175 }
1176
1177 /*****************************************************************************
1178  * IDirectDrawSurface7::GetDC
1179  *
1180  * Returns a GDI device context for the surface
1181  *
1182  * Params:
1183  *  hdc: Address of a HDC variable to store the dc to
1184  *
1185  * Returns:
1186  *  DD_OK on success
1187  *  DDERR_INVALIDPARAMS if hdc is NULL
1188  *  For details, see IWineD3DSurface::GetDC
1189  *
1190  *****************************************************************************/
1191 static HRESULT WINAPI ddraw_surface7_GetDC(IDirectDrawSurface7 *iface, HDC *hdc)
1192 {
1193     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1194     HRESULT hr;
1195
1196     TRACE("iface %p, dc %p.\n", iface, hdc);
1197
1198     if(!hdc)
1199         return DDERR_INVALIDPARAMS;
1200
1201     EnterCriticalSection(&ddraw_cs);
1202     hr = IWineD3DSurface_GetDC(This->WineD3DSurface,
1203                                hdc);
1204     LeaveCriticalSection(&ddraw_cs);
1205     switch(hr)
1206     {
1207         /* Some, but not all errors set *hdc to NULL. E.g. DCALREADYCREATED does not
1208          * touch *hdc
1209          */
1210         case WINED3DERR_INVALIDCALL:
1211             if(hdc) *hdc = NULL;
1212             return DDERR_INVALIDPARAMS;
1213
1214         default: return hr;
1215     }
1216 }
1217
1218 static HRESULT WINAPI ddraw_surface3_GetDC(IDirectDrawSurface3 *iface, HDC *dc)
1219 {
1220     TRACE("iface %p, dc %p.\n", iface, dc);
1221
1222     return ddraw_surface7_GetDC((IDirectDrawSurface7 *)surface_from_surface3(iface), dc);
1223 }
1224
1225 /*****************************************************************************
1226  * IDirectDrawSurface7::ReleaseDC
1227  *
1228  * Releases the DC that was constructed with GetDC
1229  *
1230  * Params:
1231  *  hdc: HDC to release
1232  *
1233  * Returns:
1234  *  DD_OK on success
1235  *  For more details, see IWineD3DSurface::ReleaseDC
1236  *
1237  *****************************************************************************/
1238 static HRESULT WINAPI ddraw_surface7_ReleaseDC(IDirectDrawSurface7 *iface, HDC hdc)
1239 {
1240     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1241     HRESULT hr;
1242
1243     TRACE("iface %p, dc %p.\n", iface, hdc);
1244
1245     EnterCriticalSection(&ddraw_cs);
1246     hr = IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
1247     LeaveCriticalSection(&ddraw_cs);
1248     return hr;
1249 }
1250
1251 static HRESULT WINAPI ddraw_surface3_ReleaseDC(IDirectDrawSurface3 *iface, HDC dc)
1252 {
1253     TRACE("iface %p, dc %p.\n", iface, dc);
1254
1255     return ddraw_surface7_ReleaseDC((IDirectDrawSurface7 *)surface_from_surface3(iface), dc);
1256 }
1257
1258 /*****************************************************************************
1259  * IDirectDrawSurface7::GetCaps
1260  *
1261  * Returns the surface's caps
1262  *
1263  * Params:
1264  *  Caps: Address to write the caps to
1265  *
1266  * Returns:
1267  *  DD_OK on success
1268  *  DDERR_INVALIDPARAMS if Caps is NULL
1269  *
1270  *****************************************************************************/
1271 static HRESULT WINAPI ddraw_surface7_GetCaps(IDirectDrawSurface7 *iface, DDSCAPS2 *Caps)
1272 {
1273     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1274
1275     TRACE("iface %p, caps %p.\n", iface, Caps);
1276
1277     if(!Caps)
1278         return DDERR_INVALIDPARAMS;
1279
1280     *Caps = This->surface_desc.ddsCaps;
1281     return DD_OK;
1282 }
1283
1284 static HRESULT WINAPI ddraw_surface3_GetCaps(IDirectDrawSurface3 *iface, DDSCAPS *caps)
1285 {
1286     DDSCAPS2 caps2;
1287     HRESULT hr;
1288
1289     TRACE("iface %p, caps %p.\n", iface, caps);
1290
1291     hr = ddraw_surface7_GetCaps((IDirectDrawSurface7 *)surface_from_surface3(iface), &caps2);
1292     if (FAILED(hr)) return hr;
1293
1294     caps->dwCaps = caps2.dwCaps;
1295     return hr;
1296 }
1297
1298 /*****************************************************************************
1299  * IDirectDrawSurface7::SetPriority
1300  *
1301  * Sets a texture priority for managed textures.
1302  *
1303  * Params:
1304  *  Priority: The new priority
1305  *
1306  * Returns:
1307  *  DD_OK on success
1308  *  For more details, see IWineD3DSurface::SetPriority
1309  *
1310  *****************************************************************************/
1311 static HRESULT WINAPI ddraw_surface7_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1312 {
1313     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1314     HRESULT hr;
1315
1316     TRACE("iface %p, priority %u.\n", iface, Priority);
1317
1318     EnterCriticalSection(&ddraw_cs);
1319     hr = IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1320     LeaveCriticalSection(&ddraw_cs);
1321     return hr;
1322 }
1323
1324 /*****************************************************************************
1325  * IDirectDrawSurface7::GetPriority
1326  *
1327  * Returns the surface's priority
1328  *
1329  * Params:
1330  *  Priority: Address of a variable to write the priority to
1331  *
1332  * Returns:
1333  *  D3D_OK on success
1334  *  DDERR_INVALIDPARAMS if Priority == NULL
1335  *  For more details, see IWineD3DSurface::GetPriority
1336  *
1337  *****************************************************************************/
1338 static HRESULT WINAPI ddraw_surface7_GetPriority(IDirectDrawSurface7 *iface, DWORD *Priority)
1339 {
1340     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1341
1342     TRACE("iface %p, priority %p.\n", iface, Priority);
1343
1344     if(!Priority)
1345     {
1346         return DDERR_INVALIDPARAMS;
1347     }
1348
1349     EnterCriticalSection(&ddraw_cs);
1350     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1351     LeaveCriticalSection(&ddraw_cs);
1352     return DD_OK;
1353 }
1354
1355 /*****************************************************************************
1356  * IDirectDrawSurface7::SetPrivateData
1357  *
1358  * Stores some data in the surface that is intended for the application's
1359  * use.
1360  *
1361  * Params:
1362  *  tag: GUID that identifies the data
1363  *  Data: Pointer to the private data
1364  *  Size: Size of the private data
1365  *  Flags: Some flags
1366  *
1367  * Returns:
1368  *  D3D_OK on success
1369  *  For more details, see IWineD3DSurface::SetPrivateData
1370  *
1371  *****************************************************************************/
1372 static HRESULT WINAPI ddraw_surface7_SetPrivateData(IDirectDrawSurface7 *iface,
1373         REFGUID tag, void *Data, DWORD Size, DWORD Flags)
1374 {
1375     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1376     HRESULT hr;
1377
1378     TRACE("iface %p, tag %s, data %p, data_size %u, flags %#x.\n",
1379             iface, debugstr_guid(tag), Data, Size, Flags);
1380
1381     EnterCriticalSection(&ddraw_cs);
1382     hr = IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1383                                         tag,
1384                                         Data,
1385                                         Size,
1386                                         Flags);
1387     LeaveCriticalSection(&ddraw_cs);
1388     switch(hr)
1389     {
1390         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1391         default:                            return hr;
1392     }
1393 }
1394
1395 /*****************************************************************************
1396  * IDirectDrawSurface7::GetPrivateData
1397  *
1398  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1399  *
1400  * Params:
1401  *  tag: GUID of the data to return
1402  *  Data: Address where to write the data to
1403  *  Size: Size of the buffer at Data
1404  *
1405  * Returns:
1406  *  DD_OK on success
1407  *  DDERR_INVALIDPARAMS if Data is NULL
1408  *  For more details, see IWineD3DSurface::GetPrivateData
1409  *
1410  *****************************************************************************/
1411 static HRESULT WINAPI ddraw_surface7_GetPrivateData(IDirectDrawSurface7 *iface, REFGUID tag, void *Data, DWORD *Size)
1412 {
1413     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1414     HRESULT hr;
1415
1416     TRACE("iface %p, tag %s, data %p, data_size %p.\n",
1417             iface, debugstr_guid(tag), Data, Size);
1418
1419     if(!Data)
1420         return DDERR_INVALIDPARAMS;
1421
1422     EnterCriticalSection(&ddraw_cs);
1423     hr = IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1424                                         tag,
1425                                         Data,
1426                                         Size);
1427     LeaveCriticalSection(&ddraw_cs);
1428     return hr;
1429 }
1430
1431 /*****************************************************************************
1432  * IDirectDrawSurface7::FreePrivateData
1433  *
1434  * Frees private data stored in the surface
1435  *
1436  * Params:
1437  *  tag: Tag of the data to free
1438  *
1439  * Returns:
1440  *  D3D_OK on success
1441  *  For more details, see IWineD3DSurface::FreePrivateData
1442  *
1443  *****************************************************************************/
1444 static HRESULT WINAPI ddraw_surface7_FreePrivateData(IDirectDrawSurface7 *iface, REFGUID tag)
1445 {
1446     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1447     HRESULT hr;
1448
1449     TRACE("iface %p, tag %s.\n", iface, debugstr_guid(tag));
1450
1451     EnterCriticalSection(&ddraw_cs);
1452     hr = IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1453     LeaveCriticalSection(&ddraw_cs);
1454     return hr;
1455 }
1456
1457 /*****************************************************************************
1458  * IDirectDrawSurface7::PageLock
1459  *
1460  * Prevents a sysmem surface from being paged out
1461  *
1462  * Params:
1463  *  Flags: Not used, must be 0(unchecked)
1464  *
1465  * Returns:
1466  *  DD_OK, because it's a stub
1467  *
1468  *****************************************************************************/
1469 static HRESULT WINAPI ddraw_surface7_PageLock(IDirectDrawSurface7 *iface, DWORD Flags)
1470 {
1471     TRACE("iface %p, flags %#x.\n", iface, Flags);
1472
1473     /* This is Windows memory management related - we don't need this */
1474     return DD_OK;
1475 }
1476
1477 static HRESULT WINAPI ddraw_surface3_PageLock(IDirectDrawSurface3 *iface, DWORD flags)
1478 {
1479     TRACE("iface %p, flags %#x.\n", iface, flags);
1480
1481     return ddraw_surface7_PageLock((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1482 }
1483
1484 /*****************************************************************************
1485  * IDirectDrawSurface7::PageUnlock
1486  *
1487  * Allows a sysmem surface to be paged out
1488  *
1489  * Params:
1490  *  Flags: Not used, must be 0(unchecked)
1491  *
1492  * Returns:
1493  *  DD_OK, because it's a stub
1494  *
1495  *****************************************************************************/
1496 static HRESULT WINAPI ddraw_surface7_PageUnlock(IDirectDrawSurface7 *iface, DWORD Flags)
1497 {
1498     TRACE("iface %p, flags %#x.\n", iface, Flags);
1499
1500     return DD_OK;
1501 }
1502
1503 static HRESULT WINAPI ddraw_surface3_PageUnlock(IDirectDrawSurface3 *iface, DWORD flags)
1504 {
1505     TRACE("iface %p, flags %#x.\n", iface, flags);
1506
1507     return ddraw_surface7_PageUnlock((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1508 }
1509
1510 /*****************************************************************************
1511  * IDirectDrawSurface7::BltBatch
1512  *
1513  * An unimplemented function
1514  *
1515  * Params:
1516  *  ?
1517  *
1518  * Returns:
1519  *  DDERR_UNSUPPORTED
1520  *
1521  *****************************************************************************/
1522 static HRESULT WINAPI ddraw_surface7_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1523 {
1524     TRACE("iface %p, batch %p, count %u, flags %#x.\n", iface, Batch, Count, Flags);
1525
1526     /* MSDN: "not currently implemented" */
1527     return DDERR_UNSUPPORTED;
1528 }
1529
1530 static HRESULT WINAPI ddraw_surface3_BltBatch(IDirectDrawSurface3 *iface, DDBLTBATCH *batch, DWORD count, DWORD flags)
1531 {
1532     TRACE("iface %p, batch %p, count %u, flags %#x.\n", iface, batch, count, flags);
1533
1534     return ddraw_surface7_BltBatch((IDirectDrawSurface7 *)surface_from_surface3(iface), batch, count, flags);
1535 }
1536
1537 /*****************************************************************************
1538  * IDirectDrawSurface7::EnumAttachedSurfaces
1539  *
1540  * Enumerates all surfaces attached to this surface
1541  *
1542  * Params:
1543  *  context: Pointer to pass unmodified to the callback
1544  *  cb: Callback function to call for each surface
1545  *
1546  * Returns:
1547  *  DD_OK on success
1548  *  DDERR_INVALIDPARAMS if cb is NULL
1549  *
1550  *****************************************************************************/
1551 static HRESULT WINAPI ddraw_surface7_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1552         void *context, LPDDENUMSURFACESCALLBACK7 cb)
1553 {
1554     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1555     IDirectDrawSurfaceImpl *surf;
1556     DDSURFACEDESC2 desc;
1557     int i;
1558
1559     /* Attached surfaces aren't handled in WineD3D */
1560     TRACE("iface %p, context %p, callback %p.\n", iface, context, cb);
1561
1562     if(!cb)
1563         return DDERR_INVALIDPARAMS;
1564
1565     EnterCriticalSection(&ddraw_cs);
1566     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1567     {
1568         surf = This->complex_array[i];
1569         if(!surf) break;
1570
1571         ddraw_surface7_AddRef((IDirectDrawSurface7 *)surf);
1572         desc = surf->surface_desc;
1573         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1574         if (cb((IDirectDrawSurface7 *)surf, &desc, context) == DDENUMRET_CANCEL)
1575         {
1576             LeaveCriticalSection(&ddraw_cs);
1577             return DD_OK;
1578         }
1579     }
1580
1581     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1582     {
1583         ddraw_surface7_AddRef((IDirectDrawSurface7 *)surf);
1584         desc = surf->surface_desc;
1585         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1586         if (cb((IDirectDrawSurface7 *)surf, &desc, context) == DDENUMRET_CANCEL)
1587         {
1588             LeaveCriticalSection(&ddraw_cs);
1589             return DD_OK;
1590         }
1591     }
1592
1593     TRACE(" end of enumeration.\n");
1594
1595     LeaveCriticalSection(&ddraw_cs);
1596     return DD_OK;
1597 }
1598
1599 struct callback_info
1600 {
1601     LPDDENUMSURFACESCALLBACK callback;
1602     void *context;
1603 };
1604
1605 static HRESULT CALLBACK EnumCallback(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *surface_desc, void *context)
1606 {
1607     const struct callback_info *info = context;
1608
1609     return info->callback((IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)surface)->IDirectDrawSurface3_vtbl,
1610             (DDSURFACEDESC *)surface_desc, info->context);
1611 }
1612
1613 static HRESULT WINAPI ddraw_surface3_EnumAttachedSurfaces(IDirectDrawSurface3 *iface,
1614         void *context, LPDDENUMSURFACESCALLBACK callback)
1615 {
1616     struct callback_info info;
1617
1618     TRACE("iface %p, context %p, callback %p.\n", iface, context, callback);
1619
1620     info.callback = callback;
1621     info.context  = context;
1622
1623     return ddraw_surface7_EnumAttachedSurfaces((IDirectDrawSurface7 *)surface_from_surface3(iface),
1624             &info, EnumCallback);
1625 }
1626
1627 /*****************************************************************************
1628  * IDirectDrawSurface7::EnumOverlayZOrders
1629  *
1630  * "Enumerates the overlay surfaces on the specified destination"
1631  *
1632  * Params:
1633  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1634  *  context: context to pass back to the callback
1635  *  cb: callback function to call for each enumerated surface
1636  *
1637  * Returns:
1638  *  DD_OK, because it's a stub
1639  *
1640  *****************************************************************************/
1641 static HRESULT WINAPI ddraw_surface7_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1642         DWORD Flags, void *context, LPDDENUMSURFACESCALLBACK7 cb)
1643 {
1644     FIXME("iface %p, flags %#x, context %p, callback %p stub!\n", iface, Flags, context, cb);
1645
1646     return DD_OK;
1647 }
1648
1649 static HRESULT WINAPI ddraw_surface3_EnumOverlayZOrders(IDirectDrawSurface3 *iface,
1650         DWORD flags, void *context, LPDDENUMSURFACESCALLBACK callback)
1651 {
1652     struct callback_info info;
1653
1654     TRACE("iface %p, flags %#x, context %p, callback %p.\n", iface, flags, context, callback);
1655
1656     info.callback = callback;
1657     info.context  = context;
1658
1659     return ddraw_surface7_EnumOverlayZOrders((IDirectDrawSurface7 *)surface_from_surface3(iface),
1660             flags, &info, EnumCallback);
1661 }
1662
1663 /*****************************************************************************
1664  * IDirectDrawSurface7::GetBltStatus
1665  *
1666  * Returns the blitting status
1667  *
1668  * Params:
1669  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1670  *
1671  * Returns:
1672  *  See IWineD3DSurface::Blt
1673  *
1674  *****************************************************************************/
1675 static HRESULT WINAPI ddraw_surface7_GetBltStatus(IDirectDrawSurface7 *iface, DWORD Flags)
1676 {
1677     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1678     HRESULT hr;
1679
1680     TRACE("iface %p, flags %#x.\n", iface, Flags);
1681
1682     EnterCriticalSection(&ddraw_cs);
1683     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1684     LeaveCriticalSection(&ddraw_cs);
1685     switch(hr)
1686     {
1687         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1688         default:                            return hr;
1689     }
1690 }
1691
1692 static HRESULT WINAPI ddraw_surface3_GetBltStatus(IDirectDrawSurface3 *iface, DWORD flags)
1693 {
1694     TRACE("iface %p, flags %#x.\n", iface, flags);
1695
1696     return ddraw_surface7_GetBltStatus((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1697 }
1698
1699 /*****************************************************************************
1700  * IDirectDrawSurface7::GetColorKey
1701  *
1702  * Returns the color key assigned to the surface
1703  *
1704  * Params:
1705  *  Flags: Some flags
1706  *  CKey: Address to store the key to
1707  *
1708  * Returns:
1709  *  DD_OK on success
1710  *  DDERR_INVALIDPARAMS if CKey is NULL
1711  *
1712  *****************************************************************************/
1713 static HRESULT WINAPI ddraw_surface7_GetColorKey(IDirectDrawSurface7 *iface, DWORD Flags, DDCOLORKEY *CKey)
1714 {
1715     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1716
1717     TRACE("iface %p, flags %#x, color_key %p.\n", iface, Flags, CKey);
1718
1719     if(!CKey)
1720         return DDERR_INVALIDPARAMS;
1721
1722     EnterCriticalSection(&ddraw_cs);
1723
1724     switch (Flags)
1725     {
1726     case DDCKEY_DESTBLT:
1727         if (!(This->surface_desc.dwFlags & DDSD_CKDESTBLT))
1728         {
1729             LeaveCriticalSection(&ddraw_cs);
1730             return DDERR_NOCOLORKEY;
1731         }
1732         *CKey = This->surface_desc.ddckCKDestBlt;
1733         break;
1734
1735     case DDCKEY_DESTOVERLAY:
1736         if (!(This->surface_desc.dwFlags & DDSD_CKDESTOVERLAY))
1737             {
1738             LeaveCriticalSection(&ddraw_cs);
1739             return DDERR_NOCOLORKEY;
1740             }
1741         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1742         break;
1743
1744     case DDCKEY_SRCBLT:
1745         if (!(This->surface_desc.dwFlags & DDSD_CKSRCBLT))
1746         {
1747             LeaveCriticalSection(&ddraw_cs);
1748             return DDERR_NOCOLORKEY;
1749         }
1750         *CKey = This->surface_desc.ddckCKSrcBlt;
1751         break;
1752
1753     case DDCKEY_SRCOVERLAY:
1754         if (!(This->surface_desc.dwFlags & DDSD_CKSRCOVERLAY))
1755         {
1756             LeaveCriticalSection(&ddraw_cs);
1757             return DDERR_NOCOLORKEY;
1758         }
1759         *CKey = This->surface_desc.ddckCKSrcOverlay;
1760         break;
1761
1762     default:
1763         LeaveCriticalSection(&ddraw_cs);
1764         return DDERR_INVALIDPARAMS;
1765     }
1766
1767     LeaveCriticalSection(&ddraw_cs);
1768     return DD_OK;
1769 }
1770
1771 static HRESULT WINAPI ddraw_surface3_GetColorKey(IDirectDrawSurface3 *iface, DWORD flags, DDCOLORKEY *color_key)
1772 {
1773     TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, color_key);
1774
1775     return ddraw_surface7_GetColorKey((IDirectDrawSurface7 *)surface_from_surface3(iface), flags, color_key);
1776 }
1777
1778 /*****************************************************************************
1779  * IDirectDrawSurface7::GetFlipStatus
1780  *
1781  * Returns the flipping status of the surface
1782  *
1783  * Params:
1784  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1785  *
1786  * Returns:
1787  *  See IWineD3DSurface::GetFlipStatus
1788  *
1789  *****************************************************************************/
1790 static HRESULT WINAPI ddraw_surface7_GetFlipStatus(IDirectDrawSurface7 *iface, DWORD Flags)
1791 {
1792     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1793     HRESULT hr;
1794
1795     TRACE("iface %p, flags %#x.\n", iface, Flags);
1796
1797     EnterCriticalSection(&ddraw_cs);
1798     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1799     LeaveCriticalSection(&ddraw_cs);
1800     switch(hr)
1801     {
1802         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1803         default:                            return hr;
1804     }
1805 }
1806
1807 static HRESULT WINAPI ddraw_surface3_GetFlipStatus(IDirectDrawSurface3 *iface, DWORD flags)
1808 {
1809     TRACE("iface %p, flags %#x.\n", iface, flags);
1810
1811     return ddraw_surface7_GetFlipStatus((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1812 }
1813
1814 /*****************************************************************************
1815  * IDirectDrawSurface7::GetOverlayPosition
1816  *
1817  * Returns the display coordinates of a visible and active overlay surface
1818  *
1819  * Params:
1820  *  X
1821  *  Y
1822  *
1823  * Returns:
1824  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1825  *****************************************************************************/
1826 static HRESULT WINAPI ddraw_surface7_GetOverlayPosition(IDirectDrawSurface7 *iface, LONG *X, LONG *Y)
1827 {
1828     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1829     HRESULT hr;
1830
1831     TRACE("iface %p, x %p, y %p.\n", iface, X, Y);
1832
1833     EnterCriticalSection(&ddraw_cs);
1834     hr = IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1835                                             X,
1836                                             Y);
1837     LeaveCriticalSection(&ddraw_cs);
1838     return hr;
1839 }
1840
1841 static HRESULT WINAPI ddraw_surface3_GetOverlayPosition(IDirectDrawSurface3 *iface, LONG *x, LONG *y)
1842 {
1843     TRACE("iface %p, x %p, y %p.\n", iface, x, y);
1844
1845     return ddraw_surface7_GetOverlayPosition((IDirectDrawSurface7 *)surface_from_surface3(iface), x, y);
1846 }
1847
1848 /*****************************************************************************
1849  * IDirectDrawSurface7::GetPixelFormat
1850  *
1851  * Returns the pixel format of the Surface
1852  *
1853  * Params:
1854  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1855  *               format should be written
1856  *
1857  * Returns:
1858  *  DD_OK on success
1859  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1860  *
1861  *****************************************************************************/
1862 static HRESULT WINAPI ddraw_surface7_GetPixelFormat(IDirectDrawSurface7 *iface, DDPIXELFORMAT *PixelFormat)
1863 {
1864     /* What is DDERR_INVALIDSURFACETYPE for here? */
1865     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1866
1867     TRACE("iface %p, pixel_format %p.\n", iface, PixelFormat);
1868
1869     if(!PixelFormat)
1870         return DDERR_INVALIDPARAMS;
1871
1872     EnterCriticalSection(&ddraw_cs);
1873     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1874     LeaveCriticalSection(&ddraw_cs);
1875
1876     return DD_OK;
1877 }
1878
1879 static HRESULT WINAPI ddraw_surface3_GetPixelFormat(IDirectDrawSurface3 *iface, DDPIXELFORMAT *pixel_format)
1880 {
1881     TRACE("iface %p, pixel_format %p.\n", iface, pixel_format);
1882
1883     return ddraw_surface7_GetPixelFormat((IDirectDrawSurface7 *)surface_from_surface3(iface), pixel_format);
1884 }
1885
1886 /*****************************************************************************
1887  * IDirectDrawSurface7::GetSurfaceDesc
1888  *
1889  * Returns the description of this surface
1890  *
1891  * Params:
1892  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1893  *        surface desc
1894  *
1895  * Returns:
1896  *  DD_OK on success
1897  *  DDERR_INVALIDPARAMS if DDSD is NULL
1898  *
1899  *****************************************************************************/
1900 static HRESULT WINAPI ddraw_surface7_GetSurfaceDesc(IDirectDrawSurface7 *iface, DDSURFACEDESC2 *DDSD)
1901 {
1902     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1903
1904     TRACE("iface %p, surface_desc %p.\n", iface, DDSD);
1905
1906     if(!DDSD)
1907         return DDERR_INVALIDPARAMS;
1908
1909     if (DDSD->dwSize != sizeof(DDSURFACEDESC2))
1910     {
1911         WARN("Incorrect struct size %d, returning DDERR_INVALIDPARAMS\n",DDSD->dwSize);
1912         return DDERR_INVALIDPARAMS;
1913     }
1914
1915     EnterCriticalSection(&ddraw_cs);
1916     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1917     TRACE("Returning surface desc:\n");
1918     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1919
1920     LeaveCriticalSection(&ddraw_cs);
1921     return DD_OK;
1922 }
1923
1924 static HRESULT WINAPI ddraw_surface3_GetSurfaceDesc(IDirectDrawSurface3 *iface, DDSURFACEDESC *surface_desc)
1925 {
1926     IDirectDrawSurfaceImpl *surface = surface_from_surface3(iface);
1927
1928     TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1929
1930     if (!surface_desc) return DDERR_INVALIDPARAMS;
1931
1932     if (surface_desc->dwSize != sizeof(DDSURFACEDESC))
1933     {
1934         WARN("Incorrect structure size %u, returning DDERR_INVALIDPARAMS.\n", surface_desc->dwSize);
1935         return DDERR_INVALIDPARAMS;
1936     }
1937
1938     EnterCriticalSection(&ddraw_cs);
1939     DD_STRUCT_COPY_BYSIZE(surface_desc, (DDSURFACEDESC *)&surface->surface_desc);
1940     TRACE("Returning surface desc:\n");
1941     if (TRACE_ON(ddraw))
1942     {
1943         /* DDRAW_dump_surface_desc handles the smaller size */
1944         DDRAW_dump_surface_desc((DDSURFACEDESC2 *)surface_desc);
1945     }
1946
1947     LeaveCriticalSection(&ddraw_cs);
1948     return DD_OK;
1949 }
1950
1951 /*****************************************************************************
1952  * IDirectDrawSurface7::Initialize
1953  *
1954  * Initializes the surface. This is a no-op in Wine
1955  *
1956  * Params:
1957  *  DD: Pointer to an DirectDraw interface
1958  *  DDSD: Surface description for initialization
1959  *
1960  * Returns:
1961  *  DDERR_ALREADYINITIALIZED
1962  *
1963  *****************************************************************************/
1964 static HRESULT WINAPI ddraw_surface7_Initialize(IDirectDrawSurface7 *iface,
1965         IDirectDraw *ddraw, DDSURFACEDESC2 *surface_desc)
1966 {
1967     TRACE("iface %p, ddraw %p, surface_desc %p.\n", iface, ddraw, surface_desc);
1968
1969     return DDERR_ALREADYINITIALIZED;
1970 }
1971
1972 static HRESULT WINAPI ddraw_surface3_Initialize(IDirectDrawSurface3 *iface,
1973         IDirectDraw *ddraw, DDSURFACEDESC *surface_desc)
1974 {
1975     TRACE("iface %p, ddraw %p, surface_desc %p.\n", iface, ddraw, surface_desc);
1976
1977     return ddraw_surface7_Initialize((IDirectDrawSurface7 *)surface_from_surface3(iface),
1978             ddraw, (DDSURFACEDESC2 *)surface_desc);
1979 }
1980
1981 /*****************************************************************************
1982  * IDirect3DTexture1::Initialize
1983  *
1984  * The sdk says it's not implemented
1985  *
1986  * Params:
1987  *  ?
1988  *
1989  * Returns
1990  *  DDERR_UNSUPPORTED
1991  *
1992  *****************************************************************************/
1993 static HRESULT WINAPI d3d_texture1_Initialize(IDirect3DTexture *iface,
1994         IDirect3DDevice *device, IDirectDrawSurface *surface)
1995 {
1996     TRACE("iface %p, device %p, surface %p.\n", iface, device, surface);
1997
1998     return DDERR_UNSUPPORTED; /* Unchecked */
1999 }
2000
2001 /*****************************************************************************
2002  * IDirectDrawSurface7::IsLost
2003  *
2004  * Checks if the surface is lost
2005  *
2006  * Returns:
2007  *  DD_OK, if the surface is usable
2008  *  DDERR_ISLOST if the surface is lost
2009  *  See IWineD3DSurface::IsLost for more details
2010  *
2011  *****************************************************************************/
2012 static HRESULT WINAPI ddraw_surface7_IsLost(IDirectDrawSurface7 *iface)
2013 {
2014     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2015     HRESULT hr;
2016
2017     TRACE("iface %p.\n", iface);
2018
2019     EnterCriticalSection(&ddraw_cs);
2020     /* We lose the surface if the implementation was changed */
2021     if(This->ImplType != This->ddraw->ImplType)
2022     {
2023         /* But this shouldn't happen. When we change the implementation,
2024          * all surfaces are re-created automatically, and their content
2025          * is copied
2026          */
2027         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
2028         LeaveCriticalSection(&ddraw_cs);
2029         return DDERR_SURFACELOST;
2030     }
2031
2032     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
2033     LeaveCriticalSection(&ddraw_cs);
2034     switch(hr)
2035     {
2036         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
2037          * WineD3D uses the same error for surfaces
2038          */
2039         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
2040         default:                            return hr;
2041     }
2042 }
2043
2044 static HRESULT WINAPI ddraw_surface3_IsLost(IDirectDrawSurface3 *iface)
2045 {
2046     TRACE("iface %p.\n", iface);
2047
2048     return ddraw_surface7_IsLost((IDirectDrawSurface7 *)surface_from_surface3(iface));
2049 }
2050
2051 /*****************************************************************************
2052  * IDirectDrawSurface7::Restore
2053  *
2054  * Restores a lost surface. This makes the surface usable again, but
2055  * doesn't reload its old contents
2056  *
2057  * Returns:
2058  *  DD_OK on success
2059  *  See IWineD3DSurface::Restore for more details
2060  *
2061  *****************************************************************************/
2062 static HRESULT WINAPI ddraw_surface7_Restore(IDirectDrawSurface7 *iface)
2063 {
2064     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2065     HRESULT hr;
2066
2067     TRACE("iface %p.\n", iface);
2068
2069     EnterCriticalSection(&ddraw_cs);
2070     if(This->ImplType != This->ddraw->ImplType)
2071     {
2072         /* Call the recreation callback. Make sure to AddRef first */
2073         IDirectDrawSurface_AddRef(iface);
2074         ddraw_recreate_surfaces_cb(iface, &This->surface_desc, NULL /* Not needed */);
2075     }
2076     hr = IWineD3DSurface_Restore(This->WineD3DSurface);
2077     LeaveCriticalSection(&ddraw_cs);
2078     return hr;
2079 }
2080
2081 static HRESULT WINAPI ddraw_surface3_Restore(IDirectDrawSurface3 *iface)
2082 {
2083     TRACE("iface %p.\n", iface);
2084
2085     return ddraw_surface7_Restore((IDirectDrawSurface7 *)surface_from_surface3(iface));
2086 }
2087
2088 /*****************************************************************************
2089  * IDirectDrawSurface7::SetOverlayPosition
2090  *
2091  * Changes the display coordinates of an overlay surface
2092  *
2093  * Params:
2094  *  X:
2095  *  Y:
2096  *
2097  * Returns:
2098  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
2099  *****************************************************************************/
2100 static HRESULT WINAPI ddraw_surface7_SetOverlayPosition(IDirectDrawSurface7 *iface, LONG X, LONG Y)
2101 {
2102     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2103     HRESULT hr;
2104
2105     TRACE("iface %p, x %d, y %d.\n", iface, X, Y);
2106
2107     EnterCriticalSection(&ddraw_cs);
2108     hr = IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
2109                                             X,
2110                                             Y);
2111     LeaveCriticalSection(&ddraw_cs);
2112     return hr;
2113 }
2114
2115 static HRESULT WINAPI ddraw_surface3_SetOverlayPosition(IDirectDrawSurface3 *iface, LONG x, LONG y)
2116 {
2117     TRACE("iface %p, x %d, y %d.\n", iface, x, y);
2118
2119     return ddraw_surface7_SetOverlayPosition((IDirectDrawSurface7 *)surface_from_surface3(iface), x, y);
2120 }
2121
2122 /*****************************************************************************
2123  * IDirectDrawSurface7::UpdateOverlay
2124  *
2125  * Modifies the attributes of an overlay surface.
2126  *
2127  * Params:
2128  *  SrcRect: The section of the source being used for the overlay
2129  *  DstSurface: Address of the surface that is overlaid
2130  *  DstRect: Place of the overlay
2131  *  Flags: some DDOVER_* flags
2132  *
2133  * Returns:
2134  *  DDERR_UNSUPPORTED, because we don't support overlays
2135  *
2136  *****************************************************************************/
2137 static HRESULT WINAPI ddraw_surface7_UpdateOverlay(IDirectDrawSurface7 *iface, RECT *SrcRect,
2138         IDirectDrawSurface7 *DstSurface, RECT *DstRect, DWORD Flags, DDOVERLAYFX *FX)
2139 {
2140     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2141     IDirectDrawSurfaceImpl *Dst = (IDirectDrawSurfaceImpl *)DstSurface;
2142     HRESULT hr;
2143
2144     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2145             iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), Flags, FX);
2146
2147     EnterCriticalSection(&ddraw_cs);
2148     hr = IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
2149                                        SrcRect,
2150                                        Dst ? Dst->WineD3DSurface : NULL,
2151                                        DstRect,
2152                                        Flags,
2153                                        (WINEDDOVERLAYFX *) FX);
2154     LeaveCriticalSection(&ddraw_cs);
2155     switch(hr) {
2156         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2157         case WINEDDERR_NOTAOVERLAYSURFACE:  return DDERR_NOTAOVERLAYSURFACE;
2158         case WINEDDERR_OVERLAYNOTVISIBLE:   return DDERR_OVERLAYNOTVISIBLE;
2159         default:
2160             return hr;
2161     }
2162 }
2163
2164 static HRESULT WINAPI ddraw_surface3_UpdateOverlay(IDirectDrawSurface3 *iface, RECT *src_rect,
2165         IDirectDrawSurface3 *dst_surface, RECT *dst_rect, DWORD flags, DDOVERLAYFX *fx)
2166 {
2167     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2168             iface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
2169
2170     return ddraw_surface7_UpdateOverlay((IDirectDrawSurface7 *)surface_from_surface3(iface), src_rect,
2171             dst_surface ? (IDirectDrawSurface7 *)surface_from_surface3(dst_surface) : NULL, dst_rect, flags, fx);
2172 }
2173
2174 /*****************************************************************************
2175  * IDirectDrawSurface7::UpdateOverlayDisplay
2176  *
2177  * The DX7 sdk says that it's not implemented
2178  *
2179  * Params:
2180  *  Flags: ?
2181  *
2182  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
2183  *
2184  *****************************************************************************/
2185 static HRESULT WINAPI ddraw_surface7_UpdateOverlayDisplay(IDirectDrawSurface7 *iface, DWORD Flags)
2186 {
2187     TRACE("iface %p, flags %#x.\n", iface, Flags);
2188
2189     return DDERR_UNSUPPORTED;
2190 }
2191
2192 static HRESULT WINAPI ddraw_surface3_UpdateOverlayDisplay(IDirectDrawSurface3 *iface, DWORD flags)
2193 {
2194     TRACE("iface %p, flags %#x.\n", iface, flags);
2195
2196     return ddraw_surface7_UpdateOverlayDisplay((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
2197 }
2198
2199 /*****************************************************************************
2200  * IDirectDrawSurface7::UpdateOverlayZOrder
2201  *
2202  * Sets an overlay's Z order
2203  *
2204  * Params:
2205  *  Flags: DDOVERZ_* flags
2206  *  DDSRef: Defines the relative position in the overlay chain
2207  *
2208  * Returns:
2209  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
2210  *
2211  *****************************************************************************/
2212 static HRESULT WINAPI ddraw_surface7_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
2213         DWORD Flags, IDirectDrawSurface7 *DDSRef)
2214 {
2215     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2216     IDirectDrawSurfaceImpl *Ref = (IDirectDrawSurfaceImpl *)DDSRef;
2217     HRESULT hr;
2218
2219     TRACE("iface %p, flags %#x, reference %p.\n", iface, Flags, DDSRef);
2220
2221     EnterCriticalSection(&ddraw_cs);
2222     hr =  IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
2223                                               Flags,
2224                                               Ref ? Ref->WineD3DSurface : NULL);
2225     LeaveCriticalSection(&ddraw_cs);
2226     return hr;
2227 }
2228
2229 static HRESULT WINAPI ddraw_surface3_UpdateOverlayZOrder(IDirectDrawSurface3 *iface,
2230         DWORD flags, IDirectDrawSurface3 *reference)
2231 {
2232     TRACE("iface %p, flags %#x, reference %p.\n", iface, flags, reference);
2233
2234     return ddraw_surface7_UpdateOverlayZOrder((IDirectDrawSurface7 *)surface_from_surface3(iface), flags,
2235             reference ? (IDirectDrawSurface7 *)surface_from_surface3(reference) : NULL);
2236 }
2237
2238 /*****************************************************************************
2239  * IDirectDrawSurface7::GetDDInterface
2240  *
2241  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
2242  * surface belongs to
2243  *
2244  * Params:
2245  *  DD: Address to write the interface pointer to
2246  *
2247  * Returns:
2248  *  DD_OK on success
2249  *  DDERR_INVALIDPARAMS if DD is NULL
2250  *
2251  *****************************************************************************/
2252 static HRESULT WINAPI ddraw_surface7_GetDDInterface(IDirectDrawSurface7 *iface, void **DD)
2253 {
2254     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2255
2256     TRACE("iface %p, ddraw %p.\n", iface, DD);
2257
2258     if(!DD)
2259         return DDERR_INVALIDPARAMS;
2260
2261     switch(This->version)
2262     {
2263         case 7:
2264             *DD = This->ddraw;
2265             break;
2266
2267         case 4:
2268             *DD = &This->ddraw->IDirectDraw4_vtbl;
2269             break;
2270
2271         case 2:
2272             *DD = &This->ddraw->IDirectDraw2_vtbl;
2273             break;
2274
2275         case 1:
2276             *DD = &This->ddraw->IDirectDraw_vtbl;
2277             break;
2278
2279     }
2280     IUnknown_AddRef((IUnknown *)*DD);
2281
2282     return DD_OK;
2283 }
2284
2285 static HRESULT WINAPI ddraw_surface3_GetDDInterface(IDirectDrawSurface3 *iface, void **ddraw)
2286 {
2287     TRACE("iface %p, ddraw %p.\n", iface, ddraw);
2288
2289     return ddraw_surface7_GetDDInterface((IDirectDrawSurface7 *)surface_from_surface3(iface), ddraw);
2290 }
2291
2292 /* This seems also windows implementation specific - I don't think WineD3D needs this */
2293 static HRESULT WINAPI ddraw_surface7_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
2294 {
2295     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2296     volatile IDirectDrawSurfaceImpl* vThis = This;
2297
2298     TRACE("iface %p.\n", iface);
2299
2300     EnterCriticalSection(&ddraw_cs);
2301     /* A uniqueness value of 0 is apparently special.
2302      * This needs to be checked.
2303      * TODO: Write tests for this code and check if the volatile, interlocked stuff is really needed
2304      */
2305     while (1) {
2306         DWORD old_uniqueness_value = vThis->uniqueness_value;
2307         DWORD new_uniqueness_value = old_uniqueness_value+1;
2308
2309         if (old_uniqueness_value == 0) break;
2310         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
2311
2312         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
2313                                       old_uniqueness_value,
2314                                       new_uniqueness_value)
2315             == old_uniqueness_value)
2316             break;
2317     }
2318
2319     LeaveCriticalSection(&ddraw_cs);
2320     return DD_OK;
2321 }
2322
2323 static HRESULT WINAPI ddraw_surface7_GetUniquenessValue(IDirectDrawSurface7 *iface, DWORD *pValue)
2324 {
2325     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2326
2327     TRACE("iface %p, value %p.\n", iface, pValue);
2328
2329     EnterCriticalSection(&ddraw_cs);
2330     *pValue = This->uniqueness_value;
2331     LeaveCriticalSection(&ddraw_cs);
2332     return DD_OK;
2333 }
2334
2335 /*****************************************************************************
2336  * IDirectDrawSurface7::SetLOD
2337  *
2338  * Sets the level of detail of a texture
2339  *
2340  * Params:
2341  *  MaxLOD: LOD to set
2342  *
2343  * Returns:
2344  *  DD_OK on success
2345  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2346  *
2347  *****************************************************************************/
2348 static HRESULT WINAPI ddraw_surface7_SetLOD(IDirectDrawSurface7 *iface, DWORD MaxLOD)
2349 {
2350     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2351     HRESULT hr;
2352
2353     TRACE("iface %p, lod %u.\n", iface, MaxLOD);
2354
2355     EnterCriticalSection(&ddraw_cs);
2356     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2357     {
2358         LeaveCriticalSection(&ddraw_cs);
2359         return DDERR_INVALIDOBJECT;
2360     }
2361
2362     if(!This->wineD3DTexture)
2363     {
2364         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
2365         LeaveCriticalSection(&ddraw_cs);
2366         return DDERR_INVALIDOBJECT;
2367     }
2368
2369     hr = IWineD3DBaseTexture_SetLOD(This->wineD3DTexture,
2370                                     MaxLOD);
2371     LeaveCriticalSection(&ddraw_cs);
2372     return hr;
2373 }
2374
2375 /*****************************************************************************
2376  * IDirectDrawSurface7::GetLOD
2377  *
2378  * Returns the level of detail of a Direct3D texture
2379  *
2380  * Params:
2381  *  MaxLOD: Address to write the LOD to
2382  *
2383  * Returns:
2384  *  DD_OK on success
2385  *  DDERR_INVALIDPARAMS if MaxLOD is NULL
2386  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2387  *
2388  *****************************************************************************/
2389 static HRESULT WINAPI ddraw_surface7_GetLOD(IDirectDrawSurface7 *iface, DWORD *MaxLOD)
2390 {
2391     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2392
2393     TRACE("iface %p, lod %p.\n", iface, MaxLOD);
2394
2395     if(!MaxLOD)
2396         return DDERR_INVALIDPARAMS;
2397
2398     EnterCriticalSection(&ddraw_cs);
2399     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2400     {
2401         LeaveCriticalSection(&ddraw_cs);
2402         return DDERR_INVALIDOBJECT;
2403     }
2404
2405     *MaxLOD = IWineD3DBaseTexture_GetLOD(This->wineD3DTexture);
2406     LeaveCriticalSection(&ddraw_cs);
2407     return DD_OK;
2408 }
2409
2410 /*****************************************************************************
2411  * IDirectDrawSurface7::BltFast
2412  *
2413  * Performs a fast Blit.
2414  *
2415  * Params:
2416  *  dstx: The x coordinate to blit to on the destination
2417  *  dsty: The y coordinate to blit to on the destination
2418  *  Source: The source surface
2419  *  rsrc: The source rectangle
2420  *  trans: Type of transfer. Some DDBLTFAST_* flags
2421  *
2422  * Returns:
2423  *  DD_OK on success
2424  *  For more details, see IWineD3DSurface::BltFast
2425  *
2426  *****************************************************************************/
2427 static HRESULT WINAPI ddraw_surface7_BltFast(IDirectDrawSurface7 *iface, DWORD dstx, DWORD dsty,
2428         IDirectDrawSurface7 *Source, RECT *rsrc, DWORD trans)
2429 {
2430     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2431     IDirectDrawSurfaceImpl *src = (IDirectDrawSurfaceImpl *)Source;
2432     DWORD src_w, src_h, dst_w, dst_h;
2433     HRESULT hr;
2434
2435     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
2436             iface, dstx, dsty, Source, wine_dbgstr_rect(rsrc), trans);
2437
2438     dst_w = This->surface_desc.dwWidth;
2439     dst_h = This->surface_desc.dwHeight;
2440
2441     /* Source must be != NULL, This is not checked by windows. Windows happily throws a 0xc0000005
2442      * in that case
2443      */
2444     if(rsrc)
2445     {
2446         if(rsrc->top > rsrc->bottom || rsrc->left > rsrc->right ||
2447            rsrc->right > src->surface_desc.dwWidth ||
2448            rsrc->bottom > src->surface_desc.dwHeight)
2449         {
2450             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
2451             return DDERR_INVALIDRECT;
2452         }
2453
2454         src_w = rsrc->right - rsrc->left;
2455         src_h = rsrc->bottom - rsrc->top;
2456     }
2457     else
2458     {
2459         src_w = src->surface_desc.dwWidth;
2460         src_h = src->surface_desc.dwHeight;
2461     }
2462
2463     if (src_w > dst_w || dstx > dst_w - src_w
2464             || src_h > dst_h || dsty > dst_h - src_h)
2465     {
2466         WARN("Destination area out of bounds, returning DDERR_INVALIDRECT.\n");
2467         return DDERR_INVALIDRECT;
2468     }
2469
2470     EnterCriticalSection(&ddraw_cs);
2471     hr = IWineD3DSurface_BltFast(This->WineD3DSurface,
2472                                  dstx, dsty,
2473                                  src ? src->WineD3DSurface : NULL,
2474                                  rsrc,
2475                                  trans);
2476     LeaveCriticalSection(&ddraw_cs);
2477     switch(hr)
2478     {
2479         case WINED3DERR_NOTAVAILABLE:           return DDERR_UNSUPPORTED;
2480         case WINED3DERR_WRONGTEXTUREFORMAT:     return DDERR_INVALIDPIXELFORMAT;
2481         default:                                return hr;
2482     }
2483 }
2484
2485 static HRESULT WINAPI ddraw_surface3_BltFast(IDirectDrawSurface3 *iface, DWORD dst_x, DWORD dst_y,
2486         IDirectDrawSurface3 *src_surface, RECT *src_rect, DWORD flags)
2487 {
2488     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
2489             iface, dst_x, dst_y, src_surface, wine_dbgstr_rect(src_rect), flags);
2490
2491     return ddraw_surface7_BltFast((IDirectDrawSurface7 *)surface_from_surface3(iface), dst_x, dst_y,
2492             src_surface ? (IDirectDrawSurface7 *)surface_from_surface3(src_surface) : NULL, src_rect, flags);
2493 }
2494
2495 /*****************************************************************************
2496  * IDirectDrawSurface7::GetClipper
2497  *
2498  * Returns the IDirectDrawClipper interface of the clipper assigned to this
2499  * surface
2500  *
2501  * Params:
2502  *  Clipper: Address to store the interface pointer at
2503  *
2504  * Returns:
2505  *  DD_OK on success
2506  *  DDERR_INVALIDPARAMS if Clipper is NULL
2507  *  DDERR_NOCLIPPERATTACHED if there's no clipper attached
2508  *
2509  *****************************************************************************/
2510 static HRESULT WINAPI ddraw_surface7_GetClipper(IDirectDrawSurface7 *iface, IDirectDrawClipper **Clipper)
2511 {
2512     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2513
2514     TRACE("iface %p, clipper %p.\n", iface, Clipper);
2515
2516     if(!Clipper)
2517     {
2518         LeaveCriticalSection(&ddraw_cs);
2519         return DDERR_INVALIDPARAMS;
2520     }
2521
2522     EnterCriticalSection(&ddraw_cs);
2523     if(This->clipper == NULL)
2524     {
2525         LeaveCriticalSection(&ddraw_cs);
2526         return DDERR_NOCLIPPERATTACHED;
2527     }
2528
2529     *Clipper = (IDirectDrawClipper *)This->clipper;
2530     IDirectDrawClipper_AddRef(*Clipper);
2531     LeaveCriticalSection(&ddraw_cs);
2532     return DD_OK;
2533 }
2534
2535 static HRESULT WINAPI ddraw_surface3_GetClipper(IDirectDrawSurface3 *iface, IDirectDrawClipper **clipper)
2536 {
2537     TRACE("iface %p, clipper %p.\n", iface, clipper);
2538
2539     return ddraw_surface7_GetClipper((IDirectDrawSurface7 *)surface_from_surface3(iface), clipper);
2540 }
2541
2542 /*****************************************************************************
2543  * IDirectDrawSurface7::SetClipper
2544  *
2545  * Sets a clipper for the surface
2546  *
2547  * Params:
2548  *  Clipper: IDirectDrawClipper interface of the clipper to set
2549  *
2550  * Returns:
2551  *  DD_OK on success
2552  *
2553  *****************************************************************************/
2554 static HRESULT WINAPI ddraw_surface7_SetClipper(IDirectDrawSurface7 *iface, IDirectDrawClipper *Clipper)
2555 {
2556     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2557     IDirectDrawClipperImpl *oldClipper = This->clipper;
2558     HWND clipWindow;
2559     HRESULT hr;
2560
2561     TRACE("iface %p, clipper %p.\n", iface, Clipper);
2562
2563     EnterCriticalSection(&ddraw_cs);
2564     if ((IDirectDrawClipperImpl *)Clipper == This->clipper)
2565     {
2566         LeaveCriticalSection(&ddraw_cs);
2567         return DD_OK;
2568     }
2569
2570     This->clipper = (IDirectDrawClipperImpl *)Clipper;
2571
2572     if (Clipper != NULL)
2573         IDirectDrawClipper_AddRef(Clipper);
2574     if(oldClipper)
2575         IDirectDrawClipper_Release((IDirectDrawClipper *)oldClipper);
2576
2577     hr = IWineD3DSurface_SetClipper(This->WineD3DSurface, This->clipper ? This->clipper->wineD3DClipper : NULL);
2578
2579     if(This->wineD3DSwapChain) {
2580         clipWindow = NULL;
2581         if(Clipper) {
2582             IDirectDrawClipper_GetHWnd(Clipper, &clipWindow);
2583         }
2584
2585         if(clipWindow) {
2586             IWineD3DSwapChain_SetDestWindowOverride(This->wineD3DSwapChain,
2587                                                     clipWindow);
2588         } else {
2589             IWineD3DSwapChain_SetDestWindowOverride(This->wineD3DSwapChain,
2590                                                     This->ddraw->d3d_window);
2591         }
2592     }
2593
2594     LeaveCriticalSection(&ddraw_cs);
2595     return hr;
2596 }
2597
2598 static HRESULT WINAPI ddraw_surface3_SetClipper(IDirectDrawSurface3 *iface, IDirectDrawClipper *clipper)
2599 {
2600     TRACE("iface %p, clipper %p.\n", iface, clipper);
2601
2602     return ddraw_surface7_SetClipper((IDirectDrawSurface7 *)surface_from_surface3(iface), clipper);
2603 }
2604
2605 /*****************************************************************************
2606  * IDirectDrawSurface7::SetSurfaceDesc
2607  *
2608  * Sets the surface description. It can override the pixel format, the surface
2609  * memory, ...
2610  * It's not really tested.
2611  *
2612  * Params:
2613  * DDSD: Pointer to the new surface description to set
2614  * Flags: Some flags
2615  *
2616  * Returns:
2617  *  DD_OK on success
2618  *  DDERR_INVALIDPARAMS if DDSD is NULL
2619  *
2620  *****************************************************************************/
2621 static HRESULT WINAPI ddraw_surface7_SetSurfaceDesc(IDirectDrawSurface7 *iface, DDSURFACEDESC2 *DDSD, DWORD Flags)
2622 {
2623     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2624     enum wined3d_format_id newFormat = WINED3DFMT_UNKNOWN;
2625     HRESULT hr;
2626
2627     TRACE("iface %p, surface_desc %p, flags %#x.\n", iface, DDSD, Flags);
2628
2629     if(!DDSD)
2630         return DDERR_INVALIDPARAMS;
2631
2632     EnterCriticalSection(&ddraw_cs);
2633     if (DDSD->dwFlags & DDSD_PIXELFORMAT)
2634     {
2635         newFormat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
2636
2637         if(newFormat == WINED3DFMT_UNKNOWN)
2638         {
2639             ERR("Requested to set an unknown pixelformat\n");
2640             LeaveCriticalSection(&ddraw_cs);
2641             return DDERR_INVALIDPARAMS;
2642         }
2643         if(newFormat != PixelFormat_DD2WineD3D(&This->surface_desc.u4.ddpfPixelFormat) )
2644         {
2645             hr = IWineD3DSurface_SetFormat(This->WineD3DSurface,
2646                                            newFormat);
2647             if(hr != DD_OK)
2648             {
2649                 LeaveCriticalSection(&ddraw_cs);
2650                 return hr;
2651             }
2652         }
2653     }
2654     if (DDSD->dwFlags & DDSD_CKDESTOVERLAY)
2655     {
2656         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2657                                     DDCKEY_DESTOVERLAY,
2658                                     (WINEDDCOLORKEY *) &DDSD->u3.ddckCKDestOverlay);
2659     }
2660     if (DDSD->dwFlags & DDSD_CKDESTBLT)
2661     {
2662         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2663                                     DDCKEY_DESTBLT,
2664                                     (WINEDDCOLORKEY *) &DDSD->ddckCKDestBlt);
2665     }
2666     if (DDSD->dwFlags & DDSD_CKSRCOVERLAY)
2667     {
2668         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2669                                     DDCKEY_SRCOVERLAY,
2670                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcOverlay);
2671     }
2672     if (DDSD->dwFlags & DDSD_CKSRCBLT)
2673     {
2674         IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2675                                     DDCKEY_SRCBLT,
2676                                     (WINEDDCOLORKEY *) &DDSD->ddckCKSrcBlt);
2677     }
2678     if (DDSD->dwFlags & DDSD_LPSURFACE && DDSD->lpSurface)
2679     {
2680         hr = IWineD3DSurface_SetMem(This->WineD3DSurface, DDSD->lpSurface);
2681         if(hr != WINED3D_OK)
2682         {
2683             /* No need for a trace here, wined3d does that for us */
2684             switch(hr)
2685             {
2686                 case WINED3DERR_INVALIDCALL:
2687                     LeaveCriticalSection(&ddraw_cs);
2688                     return DDERR_INVALIDPARAMS;
2689                 default:
2690                     break; /* Go on */
2691             }
2692         }
2693     }
2694
2695     This->surface_desc = *DDSD;
2696
2697     LeaveCriticalSection(&ddraw_cs);
2698     return DD_OK;
2699 }
2700
2701 static HRESULT WINAPI ddraw_surface3_SetSurfaceDesc(IDirectDrawSurface3 *iface,
2702         DDSURFACEDESC *surface_desc, DWORD flags)
2703 {
2704     TRACE("iface %p, surface_desc %p, flags %#x.\n", iface, surface_desc, flags);
2705
2706     return ddraw_surface7_SetSurfaceDesc((IDirectDrawSurface7 *)surface_from_surface3(iface),
2707             (DDSURFACEDESC2 *)surface_desc, flags);
2708 }
2709
2710 /*****************************************************************************
2711  * IDirectDrawSurface7::GetPalette
2712  *
2713  * Returns the IDirectDrawPalette interface of the palette currently assigned
2714  * to the surface
2715  *
2716  * Params:
2717  *  Pal: Address to write the interface pointer to
2718  *
2719  * Returns:
2720  *  DD_OK on success
2721  *  DDERR_INVALIDPARAMS if Pal is NULL
2722  *
2723  *****************************************************************************/
2724 static HRESULT WINAPI ddraw_surface7_GetPalette(IDirectDrawSurface7 *iface, IDirectDrawPalette **Pal)
2725 {
2726     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2727     IWineD3DPalette *wPal;
2728     HRESULT hr;
2729
2730     TRACE("iface %p, palette %p.\n", iface, Pal);
2731
2732     if(!Pal)
2733         return DDERR_INVALIDPARAMS;
2734
2735     EnterCriticalSection(&ddraw_cs);
2736     hr = IWineD3DSurface_GetPalette(This->WineD3DSurface, &wPal);
2737     if(hr != DD_OK)
2738     {
2739         LeaveCriticalSection(&ddraw_cs);
2740         return hr;
2741     }
2742
2743     if(wPal)
2744     {
2745         *Pal = IWineD3DPalette_GetParent(wPal);
2746         IDirectDrawPalette_AddRef(*Pal);
2747     }
2748     else
2749     {
2750         *Pal = NULL;
2751         hr = DDERR_NOPALETTEATTACHED;
2752     }
2753
2754     LeaveCriticalSection(&ddraw_cs);
2755     return hr;
2756 }
2757
2758 static HRESULT WINAPI ddraw_surface3_GetPalette(IDirectDrawSurface3 *iface, IDirectDrawPalette **palette)
2759 {
2760     TRACE("iface %p, palette %p.\n", iface, palette);
2761
2762     return ddraw_surface7_GetPalette((IDirectDrawSurface7 *)surface_from_surface3(iface), palette);
2763 }
2764
2765 /*****************************************************************************
2766  * SetColorKeyEnum
2767  *
2768  * EnumAttachedSurface callback for SetColorKey. Used to set color keys
2769  * recursively in the surface tree
2770  *
2771  *****************************************************************************/
2772 struct SCKContext
2773 {
2774     HRESULT ret;
2775     WINEDDCOLORKEY *CKey;
2776     DWORD Flags;
2777 };
2778
2779 static HRESULT WINAPI
2780 SetColorKeyEnum(IDirectDrawSurface7 *surface,
2781                 DDSURFACEDESC2 *desc,
2782                 void *context)
2783 {
2784     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)surface;
2785     struct SCKContext *ctx = context;
2786     HRESULT hr;
2787
2788     hr = IWineD3DSurface_SetColorKey(This->WineD3DSurface,
2789                                      ctx->Flags,
2790                                      ctx->CKey);
2791     if(hr != DD_OK)
2792     {
2793         WARN("IWineD3DSurface_SetColorKey failed, hr = %08x\n", hr);
2794         ctx->ret = hr;
2795     }
2796
2797     ddraw_surface7_EnumAttachedSurfaces(surface, context, SetColorKeyEnum);
2798     ddraw_surface7_Release(surface);
2799
2800     return DDENUMRET_OK;
2801 }
2802
2803 /*****************************************************************************
2804  * IDirectDrawSurface7::SetColorKey
2805  *
2806  * Sets the color keying options for the surface. Observations showed that
2807  * in case of complex surfaces the color key has to be assigned to all
2808  * sublevels.
2809  *
2810  * Params:
2811  *  Flags: DDCKEY_*
2812  *  CKey: The new color key
2813  *
2814  * Returns:
2815  *  DD_OK on success
2816  *  See IWineD3DSurface::SetColorKey for details
2817  *
2818  *****************************************************************************/
2819 static HRESULT WINAPI ddraw_surface7_SetColorKey(IDirectDrawSurface7 *iface, DWORD Flags, DDCOLORKEY *CKey)
2820 {
2821     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2822     DDCOLORKEY FixedCKey;
2823     struct SCKContext ctx = { DD_OK, (WINEDDCOLORKEY *) (CKey ? &FixedCKey : NULL), Flags };
2824
2825     TRACE("iface %p, flags %#x, color_key %p.\n", iface, Flags, CKey);
2826
2827     EnterCriticalSection(&ddraw_cs);
2828     if (CKey)
2829     {
2830         FixedCKey = *CKey;
2831         /* Handle case where dwColorSpaceHighValue < dwColorSpaceLowValue */
2832         if (FixedCKey.dwColorSpaceHighValue < FixedCKey.dwColorSpaceLowValue)
2833             FixedCKey.dwColorSpaceHighValue = FixedCKey.dwColorSpaceLowValue;
2834
2835         switch (Flags & ~DDCKEY_COLORSPACE)
2836         {
2837         case DDCKEY_DESTBLT:
2838             This->surface_desc.ddckCKDestBlt = FixedCKey;
2839             This->surface_desc.dwFlags |= DDSD_CKDESTBLT;
2840             break;
2841
2842         case DDCKEY_DESTOVERLAY:
2843             This->surface_desc.u3.ddckCKDestOverlay = FixedCKey;
2844             This->surface_desc.dwFlags |= DDSD_CKDESTOVERLAY;
2845             break;
2846
2847         case DDCKEY_SRCOVERLAY:
2848             This->surface_desc.ddckCKSrcOverlay = FixedCKey;
2849             This->surface_desc.dwFlags |= DDSD_CKSRCOVERLAY;
2850             break;
2851
2852         case DDCKEY_SRCBLT:
2853             This->surface_desc.ddckCKSrcBlt = FixedCKey;
2854             This->surface_desc.dwFlags |= DDSD_CKSRCBLT;
2855             break;
2856
2857         default:
2858             LeaveCriticalSection(&ddraw_cs);
2859             return DDERR_INVALIDPARAMS;
2860         }
2861     }
2862     else
2863     {
2864         switch (Flags & ~DDCKEY_COLORSPACE)
2865         {
2866         case DDCKEY_DESTBLT:
2867             This->surface_desc.dwFlags &= ~DDSD_CKDESTBLT;
2868             break;
2869
2870         case DDCKEY_DESTOVERLAY:
2871             This->surface_desc.dwFlags &= ~DDSD_CKDESTOVERLAY;
2872             break;
2873
2874         case DDCKEY_SRCOVERLAY:
2875             This->surface_desc.dwFlags &= ~DDSD_CKSRCOVERLAY;
2876             break;
2877
2878         case DDCKEY_SRCBLT:
2879             This->surface_desc.dwFlags &= ~DDSD_CKSRCBLT;
2880             break;
2881
2882         default:
2883             LeaveCriticalSection(&ddraw_cs);
2884             return DDERR_INVALIDPARAMS;
2885         }
2886     }
2887     ctx.ret = IWineD3DSurface_SetColorKey(This->WineD3DSurface, Flags, ctx.CKey);
2888     ddraw_surface7_EnumAttachedSurfaces(iface, &ctx, SetColorKeyEnum);
2889     LeaveCriticalSection(&ddraw_cs);
2890     switch(ctx.ret)
2891     {
2892         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2893         default:                            return ctx.ret;
2894     }
2895 }
2896
2897 static HRESULT WINAPI ddraw_surface3_SetColorKey(IDirectDrawSurface3 *iface, DWORD flags, DDCOLORKEY *color_key)
2898 {
2899     TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, color_key);
2900
2901     return ddraw_surface7_SetColorKey((IDirectDrawSurface7 *)surface_from_surface3(iface), flags, color_key);
2902 }
2903
2904 /*****************************************************************************
2905  * IDirectDrawSurface7::SetPalette
2906  *
2907  * Assigns a DirectDrawPalette object to the surface
2908  *
2909  * Params:
2910  *  Pal: Interface to the palette to set
2911  *
2912  * Returns:
2913  *  DD_OK on success
2914  *
2915  *****************************************************************************/
2916 static HRESULT WINAPI ddraw_surface7_SetPalette(IDirectDrawSurface7 *iface, IDirectDrawPalette *Pal)
2917 {
2918     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2919     IDirectDrawPalette *oldPal;
2920     IDirectDrawSurfaceImpl *surf;
2921     IDirectDrawPaletteImpl *PalImpl = (IDirectDrawPaletteImpl *)Pal;
2922     HRESULT hr;
2923
2924     TRACE("iface %p, palette %p.\n", iface, Pal);
2925
2926     if (!(This->surface_desc.u4.ddpfPixelFormat.dwFlags & (DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2 |
2927             DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_PALETTEINDEXEDTO8))) {
2928         return DDERR_INVALIDPIXELFORMAT;
2929     }
2930
2931     /* Find the old palette */
2932     EnterCriticalSection(&ddraw_cs);
2933     hr = IDirectDrawSurface_GetPalette(iface, &oldPal);
2934     if(hr != DD_OK && hr != DDERR_NOPALETTEATTACHED)
2935     {
2936         LeaveCriticalSection(&ddraw_cs);
2937         return hr;
2938     }
2939     if(oldPal) IDirectDrawPalette_Release(oldPal);  /* For the GetPalette */
2940
2941     /* Set the new Palette */
2942     IWineD3DSurface_SetPalette(This->WineD3DSurface,
2943                                PalImpl ? PalImpl->wineD3DPalette : NULL);
2944     /* AddRef the Palette */
2945     if(Pal) IDirectDrawPalette_AddRef(Pal);
2946
2947     /* Release the old palette */
2948     if(oldPal) IDirectDrawPalette_Release(oldPal);
2949
2950     /* If this is a front buffer, also update the back buffers
2951      * TODO: How do things work for palettized cube textures?
2952      */
2953     if(This->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2954     {
2955         /* For primary surfaces the tree is just a list, so the simpler scheme fits too */
2956         DDSCAPS2 caps2 = { DDSCAPS_PRIMARYSURFACE, 0, 0, 0 };
2957
2958         surf = This;
2959         while(1)
2960         {
2961             IDirectDrawSurface7 *attach;
2962             HRESULT hr;
2963             hr = ddraw_surface7_GetAttachedSurface((IDirectDrawSurface7 *)surf, &caps2, &attach);
2964             if(hr != DD_OK)
2965             {
2966                 break;
2967             }
2968
2969             TRACE("Setting palette on %p\n", attach);
2970             ddraw_surface7_SetPalette(attach, Pal);
2971             surf = (IDirectDrawSurfaceImpl *)attach;
2972             ddraw_surface7_Release(attach);
2973         }
2974     }
2975
2976     LeaveCriticalSection(&ddraw_cs);
2977     return DD_OK;
2978 }
2979
2980 static HRESULT WINAPI ddraw_surface3_SetPalette(IDirectDrawSurface3 *iface, IDirectDrawPalette *palette)
2981 {
2982     TRACE("iface %p, palette %p.\n", iface, palette);
2983
2984     return ddraw_surface7_SetPalette((IDirectDrawSurface7 *)surface_from_surface3(iface), palette);
2985 }
2986
2987 /**********************************************************
2988  * IDirectDrawGammaControl::GetGammaRamp
2989  *
2990  * Returns the current gamma ramp for a surface
2991  *
2992  * Params:
2993  *  flags: Ignored
2994  *  gamma_ramp: Address to write the ramp to
2995  *
2996  * Returns:
2997  *  DD_OK on success
2998  *  DDERR_INVALIDPARAMS if gamma_ramp is NULL
2999  *
3000  **********************************************************/
3001 static HRESULT WINAPI ddraw_gamma_control_GetGammaRamp(IDirectDrawGammaControl *iface,
3002         DWORD flags, DDGAMMARAMP *gamma_ramp)
3003 {
3004     IDirectDrawSurfaceImpl *surface = surface_from_gamma_control(iface);
3005
3006     TRACE("iface %p, flags %#x, gamma_ramp %p.\n", iface, flags, gamma_ramp);
3007
3008     if (!gamma_ramp)
3009     {
3010         WARN("Invalid gamma_ramp passed.\n");
3011         return DDERR_INVALIDPARAMS;
3012     }
3013
3014     EnterCriticalSection(&ddraw_cs);
3015     if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
3016     {
3017         /* Note: DDGAMMARAMP is compatible with WINED3DGAMMARAMP. */
3018         IWineD3DDevice_GetGammaRamp(surface->ddraw->wineD3DDevice, 0, (WINED3DGAMMARAMP *)gamma_ramp);
3019     }
3020     else
3021     {
3022         ERR("Not implemented for non-primary surfaces.\n");
3023     }
3024     LeaveCriticalSection(&ddraw_cs);
3025
3026     return DD_OK;
3027 }
3028
3029 /**********************************************************
3030  * IDirectDrawGammaControl::SetGammaRamp
3031  *
3032  * Sets the red, green and blue gamma ramps for
3033  *
3034  * Params:
3035  *  flags: Can be DDSGR_CALIBRATE to request calibration
3036  *  gamma_ramp: Structure containing the new gamma ramp
3037  *
3038  * Returns:
3039  *  DD_OK on success
3040  *  DDERR_INVALIDPARAMS if gamma_ramp is NULL
3041  *
3042  **********************************************************/
3043 static HRESULT WINAPI ddraw_gamma_control_SetGammaRamp(IDirectDrawGammaControl *iface,
3044         DWORD flags, DDGAMMARAMP *gamma_ramp)
3045 {
3046     IDirectDrawSurfaceImpl *surface = surface_from_gamma_control(iface);
3047
3048     TRACE("iface %p, flags %#x, gamma_ramp %p.\n", iface, flags, gamma_ramp);
3049
3050     if (!gamma_ramp)
3051     {
3052         WARN("Invalid gamma_ramp passed.\n");
3053         return DDERR_INVALIDPARAMS;
3054     }
3055
3056     EnterCriticalSection(&ddraw_cs);
3057     if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
3058     {
3059         /* Note: DDGAMMARAMP is compatible with WINED3DGAMMARAMP */
3060         IWineD3DDevice_SetGammaRamp(surface->ddraw->wineD3DDevice, 0, flags, (WINED3DGAMMARAMP *)gamma_ramp);
3061     }
3062     else
3063     {
3064         ERR("Not implemented for non-primary surfaces.\n");
3065     }
3066     LeaveCriticalSection(&ddraw_cs);
3067
3068     return DD_OK;
3069 }
3070
3071 /*****************************************************************************
3072  * IDirect3DTexture2::PaletteChanged
3073  *
3074  * Informs the texture about a palette change
3075  *
3076  * Params:
3077  *  start: Start index of the change
3078  *  count: The number of changed entries
3079  *
3080  * Returns
3081  *  D3D_OK, because it's a stub
3082  *
3083  *****************************************************************************/
3084 static HRESULT WINAPI d3d_texture2_PaletteChanged(IDirect3DTexture2 *iface, DWORD start, DWORD count)
3085 {
3086     FIXME("iface %p, start %u, count %u stub!\n", iface, start, count);
3087
3088     return D3D_OK;
3089 }
3090
3091 static HRESULT WINAPI d3d_texture1_PaletteChanged(IDirect3DTexture *iface, DWORD start, DWORD count)
3092 {
3093     IDirectDrawSurfaceImpl *surface = surface_from_texture1(iface);
3094
3095     TRACE("iface %p, start %u, count %u.\n", iface, start, count);
3096
3097     return d3d_texture2_PaletteChanged((IDirect3DTexture2 *)&surface->IDirect3DTexture2_vtbl, start, count);
3098 }
3099
3100 /*****************************************************************************
3101  * IDirect3DTexture::Unload
3102  *
3103  * DX5 SDK: "The IDirect3DTexture2::Unload method is not implemented
3104  *
3105  *
3106  * Returns:
3107  *  DDERR_UNSUPPORTED
3108  *
3109  *****************************************************************************/
3110 static HRESULT WINAPI d3d_texture1_Unload(IDirect3DTexture *iface)
3111 {
3112     WARN("iface %p. Not implemented.\n", iface);
3113
3114     return DDERR_UNSUPPORTED;
3115 }
3116
3117 /*****************************************************************************
3118  * IDirect3DTexture2::GetHandle
3119  *
3120  * Returns handle for the texture. At the moment, the interface
3121  * to the IWineD3DTexture is used.
3122  *
3123  * Params:
3124  *  device: Device this handle is assigned to
3125  *  handle: Address to store the handle at.
3126  *
3127  * Returns:
3128  *  D3D_OK
3129  *
3130  *****************************************************************************/
3131 static HRESULT WINAPI d3d_texture2_GetHandle(IDirect3DTexture2 *iface,
3132         IDirect3DDevice2 *device, D3DTEXTUREHANDLE *handle)
3133 {
3134     IDirectDrawSurfaceImpl *surface = surface_from_texture2(iface);
3135
3136     TRACE("iface %p, device %p, handle %p.\n", iface, device, handle);
3137
3138     EnterCriticalSection(&ddraw_cs);
3139
3140     if (!surface->Handle)
3141     {
3142         DWORD h = ddraw_allocate_handle(&device_from_device2(device)->handle_table, surface, DDRAW_HANDLE_SURFACE);
3143         if (h == DDRAW_INVALID_HANDLE)
3144         {
3145             ERR("Failed to allocate a texture handle.\n");
3146             LeaveCriticalSection(&ddraw_cs);
3147             return DDERR_OUTOFMEMORY;
3148         }
3149
3150         surface->Handle = h + 1;
3151     }
3152
3153     TRACE("Returning handle %08x.\n", surface->Handle);
3154     *handle = surface->Handle;
3155
3156     LeaveCriticalSection(&ddraw_cs);
3157
3158     return D3D_OK;
3159 }
3160
3161 static HRESULT WINAPI d3d_texture1_GetHandle(IDirect3DTexture *iface,
3162         IDirect3DDevice *device, D3DTEXTUREHANDLE *handle)
3163 {
3164     IDirect3DTexture2 *texture2 = (IDirect3DTexture2 *)&surface_from_texture1(iface)->IDirect3DTexture2_vtbl;
3165     IDirect3DDevice2 *device2 = (IDirect3DDevice2 *)&device_from_device1(device)->IDirect3DDevice2_vtbl;
3166
3167     TRACE("iface %p, device %p, handle %p.\n", iface, device, handle);
3168
3169     return d3d_texture2_GetHandle(texture2, device2, handle);
3170 }
3171
3172 /*****************************************************************************
3173  * get_sub_mimaplevel
3174  *
3175  * Helper function that returns the next mipmap level
3176  *
3177  * tex_ptr: Surface of which to return the next level
3178  *
3179  *****************************************************************************/
3180 static IDirectDrawSurfaceImpl *get_sub_mimaplevel(IDirectDrawSurfaceImpl *surface)
3181 {
3182     /* Now go down the mipmap chain to the next surface */
3183     static DDSCAPS2 mipmap_caps = { DDSCAPS_MIPMAP | DDSCAPS_TEXTURE, 0, 0, 0 };
3184     IDirectDrawSurface7 *next_level;
3185     HRESULT hr;
3186
3187     hr = ddraw_surface7_GetAttachedSurface((IDirectDrawSurface7 *)surface, &mipmap_caps, &next_level);
3188     if (FAILED(hr)) return NULL;
3189
3190     ddraw_surface7_Release(next_level);
3191
3192     return (IDirectDrawSurfaceImpl *)next_level;
3193 }
3194
3195 /*****************************************************************************
3196  * IDirect3DTexture2::Load
3197  *
3198  * Loads a texture created with the DDSCAPS_ALLOCONLOAD
3199  *
3200  * This function isn't relayed to WineD3D because the whole interface is
3201  * implemented in DDraw only. For speed improvements a implementation which
3202  * takes OpenGL more into account could be placed into WineD3D.
3203  *
3204  * Params:
3205  *  src_texture: Address of the texture to load
3206  *
3207  * Returns:
3208  *  D3D_OK on success
3209  *  D3DERR_TEXTURE_LOAD_FAILED.
3210  *
3211  *****************************************************************************/
3212 static HRESULT WINAPI d3d_texture2_Load(IDirect3DTexture2 *iface, IDirect3DTexture2 *src_texture)
3213 {
3214     IDirectDrawSurfaceImpl *dst_surface = surface_from_texture2(iface);
3215     IDirectDrawSurfaceImpl *src_surface = surface_from_texture2(src_texture);
3216     HRESULT hr;
3217
3218     TRACE("iface %p, src_texture %p.\n", iface, src_texture);
3219
3220     if (src_surface == dst_surface)
3221     {
3222         TRACE("copying surface %p to surface %p, why?\n", src_surface, dst_surface);
3223         return D3D_OK;
3224     }
3225
3226     EnterCriticalSection(&ddraw_cs);
3227
3228     if (((src_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3229             != (dst_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP))
3230             || (src_surface->surface_desc.u2.dwMipMapCount != dst_surface->surface_desc.u2.dwMipMapCount))
3231     {
3232         ERR("Trying to load surfaces with different mip-map counts.\n");
3233     }
3234
3235     for (;;)
3236     {
3237         IWineD3DPalette *wined3d_dst_pal, *wined3d_src_pal;
3238         IDirectDrawPalette *dst_pal = NULL, *src_pal = NULL;
3239         DDSURFACEDESC *src_desc, *dst_desc;
3240
3241         TRACE("Copying surface %p to surface %p (mipmap level %d).\n",
3242                 src_surface, dst_surface, src_surface->mipmap_level);
3243
3244         /* Suppress the ALLOCONLOAD flag */
3245         dst_surface->surface_desc.ddsCaps.dwCaps &= ~DDSCAPS_ALLOCONLOAD;
3246
3247         /* Get the palettes */
3248         hr = IWineD3DSurface_GetPalette(dst_surface->WineD3DSurface, &wined3d_dst_pal);
3249         if (FAILED(hr))
3250         {
3251             ERR("Failed to get destination palette, hr %#x.\n", hr);
3252             LeaveCriticalSection(&ddraw_cs);
3253             return D3DERR_TEXTURE_LOAD_FAILED;
3254         }
3255         if (wined3d_dst_pal) dst_pal = IWineD3DPalette_GetParent(wined3d_dst_pal);
3256
3257         hr = IWineD3DSurface_GetPalette(src_surface->WineD3DSurface, &wined3d_src_pal);
3258         if (FAILED(hr))
3259         {
3260             ERR("Failed to get source palette, hr %#x.\n", hr);
3261             LeaveCriticalSection(&ddraw_cs);
3262             return D3DERR_TEXTURE_LOAD_FAILED;
3263         }
3264         if (wined3d_src_pal) src_pal = IWineD3DPalette_GetParent(wined3d_src_pal);
3265
3266         if (src_pal)
3267         {
3268             PALETTEENTRY palent[256];
3269
3270             if (!dst_pal)
3271             {
3272                 LeaveCriticalSection(&ddraw_cs);
3273                 return DDERR_NOPALETTEATTACHED;
3274             }
3275             IDirectDrawPalette_GetEntries(src_pal, 0, 0, 256, palent);
3276             IDirectDrawPalette_SetEntries(dst_pal, 0, 0, 256, palent);
3277         }
3278
3279         /* Copy one surface on the other */
3280         dst_desc = (DDSURFACEDESC *)&(dst_surface->surface_desc);
3281         src_desc = (DDSURFACEDESC *)&(src_surface->surface_desc);
3282
3283         if ((src_desc->dwWidth != dst_desc->dwWidth) || (src_desc->dwHeight != dst_desc->dwHeight))
3284         {
3285             /* Should also check for same pixel format, u1.lPitch, ... */
3286             ERR("Error in surface sizes.\n");
3287             LeaveCriticalSection(&ddraw_cs);
3288             return D3DERR_TEXTURE_LOAD_FAILED;
3289         }
3290         else
3291         {
3292             WINED3DLOCKED_RECT src_rect, dst_rect;
3293
3294             /* Copy also the ColorKeying stuff */
3295             if (src_desc->dwFlags & DDSD_CKSRCBLT)
3296             {
3297                 dst_desc->dwFlags |= DDSD_CKSRCBLT;
3298                 dst_desc->ddckCKSrcBlt.dwColorSpaceLowValue = src_desc->ddckCKSrcBlt.dwColorSpaceLowValue;
3299                 dst_desc->ddckCKSrcBlt.dwColorSpaceHighValue = src_desc->ddckCKSrcBlt.dwColorSpaceHighValue;
3300             }
3301
3302             /* Copy the main memory texture into the surface that corresponds
3303              * to the OpenGL texture object. */
3304
3305             hr = IWineD3DSurface_LockRect(src_surface->WineD3DSurface, &src_rect, NULL, 0);
3306             if (FAILED(hr))
3307             {
3308                 ERR("Failed to lock source surface, hr %#x.\n", hr);
3309                 LeaveCriticalSection(&ddraw_cs);
3310                 return D3DERR_TEXTURE_LOAD_FAILED;
3311             }
3312
3313             hr = IWineD3DSurface_LockRect(dst_surface->WineD3DSurface, &dst_rect, NULL, 0);
3314             if (FAILED(hr))
3315             {
3316                 ERR("Failed to lock destination surface, hr %#x.\n", hr);
3317                 IWineD3DSurface_UnlockRect(src_surface->WineD3DSurface);
3318                 LeaveCriticalSection(&ddraw_cs);
3319                 return D3DERR_TEXTURE_LOAD_FAILED;
3320             }
3321
3322             if (dst_surface->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
3323                 memcpy(dst_rect.pBits, src_rect.pBits, src_surface->surface_desc.u1.dwLinearSize);
3324             else
3325                 memcpy(dst_rect.pBits, src_rect.pBits, src_rect.Pitch * src_desc->dwHeight);
3326
3327             IWineD3DSurface_UnlockRect(src_surface->WineD3DSurface);
3328             IWineD3DSurface_UnlockRect(dst_surface->WineD3DSurface);
3329         }
3330
3331         if (src_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3332             src_surface = get_sub_mimaplevel(src_surface);
3333         else
3334             src_surface = NULL;
3335
3336         if (dst_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3337             dst_surface = get_sub_mimaplevel(dst_surface);
3338         else
3339             dst_surface = NULL;
3340
3341         if (!src_surface || !dst_surface)
3342         {
3343             if (src_surface != dst_surface)
3344                 ERR("Loading surface with different mipmap structure.\n");
3345             break;
3346         }
3347     }
3348
3349     LeaveCriticalSection(&ddraw_cs);
3350
3351     return hr;
3352 }
3353
3354 static HRESULT WINAPI d3d_texture1_Load(IDirect3DTexture *iface, IDirect3DTexture *src_texture)
3355 {
3356     TRACE("iface %p, src_texture %p.\n", iface, src_texture);
3357
3358     return d3d_texture2_Load((IDirect3DTexture2 *)&surface_from_texture1(iface)->IDirect3DTexture2_vtbl,
3359             src_texture ? (IDirect3DTexture2 *)&surface_from_texture1(src_texture)->IDirect3DTexture2_vtbl : NULL);
3360 }
3361
3362 /*****************************************************************************
3363  * The VTable
3364  *****************************************************************************/
3365
3366 static const struct IDirectDrawSurface7Vtbl ddraw_surface7_vtbl =
3367 {
3368     /* IUnknown */
3369     ddraw_surface7_QueryInterface,
3370     ddraw_surface7_AddRef,
3371     ddraw_surface7_Release,
3372     /* IDirectDrawSurface */
3373     ddraw_surface7_AddAttachedSurface,
3374     ddraw_surface7_AddOverlayDirtyRect,
3375     ddraw_surface7_Blt,
3376     ddraw_surface7_BltBatch,
3377     ddraw_surface7_BltFast,
3378     ddraw_surface7_DeleteAttachedSurface,
3379     ddraw_surface7_EnumAttachedSurfaces,
3380     ddraw_surface7_EnumOverlayZOrders,
3381     ddraw_surface7_Flip,
3382     ddraw_surface7_GetAttachedSurface,
3383     ddraw_surface7_GetBltStatus,
3384     ddraw_surface7_GetCaps,
3385     ddraw_surface7_GetClipper,
3386     ddraw_surface7_GetColorKey,
3387     ddraw_surface7_GetDC,
3388     ddraw_surface7_GetFlipStatus,
3389     ddraw_surface7_GetOverlayPosition,
3390     ddraw_surface7_GetPalette,
3391     ddraw_surface7_GetPixelFormat,
3392     ddraw_surface7_GetSurfaceDesc,
3393     ddraw_surface7_Initialize,
3394     ddraw_surface7_IsLost,
3395     ddraw_surface7_Lock,
3396     ddraw_surface7_ReleaseDC,
3397     ddraw_surface7_Restore,
3398     ddraw_surface7_SetClipper,
3399     ddraw_surface7_SetColorKey,
3400     ddraw_surface7_SetOverlayPosition,
3401     ddraw_surface7_SetPalette,
3402     ddraw_surface7_Unlock,
3403     ddraw_surface7_UpdateOverlay,
3404     ddraw_surface7_UpdateOverlayDisplay,
3405     ddraw_surface7_UpdateOverlayZOrder,
3406     /* IDirectDrawSurface2 */
3407     ddraw_surface7_GetDDInterface,
3408     ddraw_surface7_PageLock,
3409     ddraw_surface7_PageUnlock,
3410     /* IDirectDrawSurface3 */
3411     ddraw_surface7_SetSurfaceDesc,
3412     /* IDirectDrawSurface4 */
3413     ddraw_surface7_SetPrivateData,
3414     ddraw_surface7_GetPrivateData,
3415     ddraw_surface7_FreePrivateData,
3416     ddraw_surface7_GetUniquenessValue,
3417     ddraw_surface7_ChangeUniquenessValue,
3418     /* IDirectDrawSurface7 */
3419     ddraw_surface7_SetPriority,
3420     ddraw_surface7_GetPriority,
3421     ddraw_surface7_SetLOD,
3422     ddraw_surface7_GetLOD,
3423 };
3424
3425 static const struct IDirectDrawSurface3Vtbl ddraw_surface3_vtbl =
3426 {
3427     /* IUnknown */
3428     ddraw_surface3_QueryInterface,
3429     ddraw_surface3_AddRef,
3430     ddraw_surface3_Release,
3431     /* IDirectDrawSurface */
3432     ddraw_surface3_AddAttachedSurface,
3433     ddraw_surface3_AddOverlayDirtyRect,
3434     ddraw_surface3_Blt,
3435     ddraw_surface3_BltBatch,
3436     ddraw_surface3_BltFast,
3437     ddraw_surface3_DeleteAttachedSurface,
3438     ddraw_surface3_EnumAttachedSurfaces,
3439     ddraw_surface3_EnumOverlayZOrders,
3440     ddraw_surface3_Flip,
3441     ddraw_surface3_GetAttachedSurface,
3442     ddraw_surface3_GetBltStatus,
3443     ddraw_surface3_GetCaps,
3444     ddraw_surface3_GetClipper,
3445     ddraw_surface3_GetColorKey,
3446     ddraw_surface3_GetDC,
3447     ddraw_surface3_GetFlipStatus,
3448     ddraw_surface3_GetOverlayPosition,
3449     ddraw_surface3_GetPalette,
3450     ddraw_surface3_GetPixelFormat,
3451     ddraw_surface3_GetSurfaceDesc,
3452     ddraw_surface3_Initialize,
3453     ddraw_surface3_IsLost,
3454     ddraw_surface3_Lock,
3455     ddraw_surface3_ReleaseDC,
3456     ddraw_surface3_Restore,
3457     ddraw_surface3_SetClipper,
3458     ddraw_surface3_SetColorKey,
3459     ddraw_surface3_SetOverlayPosition,
3460     ddraw_surface3_SetPalette,
3461     ddraw_surface3_Unlock,
3462     ddraw_surface3_UpdateOverlay,
3463     ddraw_surface3_UpdateOverlayDisplay,
3464     ddraw_surface3_UpdateOverlayZOrder,
3465     /* IDirectDrawSurface2 */
3466     ddraw_surface3_GetDDInterface,
3467     ddraw_surface3_PageLock,
3468     ddraw_surface3_PageUnlock,
3469     /* IDirectDrawSurface3 */
3470     ddraw_surface3_SetSurfaceDesc,
3471 };
3472
3473 static const struct IDirectDrawGammaControlVtbl ddraw_gamma_control_vtbl =
3474 {
3475     ddraw_gamma_control_QueryInterface,
3476     ddraw_gamma_control_AddRef,
3477     ddraw_gamma_control_Release,
3478     ddraw_gamma_control_GetGammaRamp,
3479     ddraw_gamma_control_SetGammaRamp,
3480 };
3481
3482 static const struct IDirect3DTexture2Vtbl d3d_texture2_vtbl =
3483 {
3484     d3d_texture2_QueryInterface,
3485     d3d_texture2_AddRef,
3486     d3d_texture2_Release,
3487     d3d_texture2_GetHandle,
3488     d3d_texture2_PaletteChanged,
3489     d3d_texture2_Load,
3490 };
3491
3492 static const struct IDirect3DTextureVtbl d3d_texture1_vtbl =
3493 {
3494     d3d_texture1_QueryInterface,
3495     d3d_texture1_AddRef,
3496     d3d_texture1_Release,
3497     d3d_texture1_Initialize,
3498     d3d_texture1_GetHandle,
3499     d3d_texture1_PaletteChanged,
3500     d3d_texture1_Load,
3501     d3d_texture1_Unload,
3502 };
3503
3504 HRESULT ddraw_surface_init(IDirectDrawSurfaceImpl *surface, IDirectDrawImpl *ddraw,
3505         DDSURFACEDESC2 *desc, UINT mip_level, WINED3DSURFTYPE surface_type)
3506 {
3507     WINED3DPOOL pool = WINED3DPOOL_DEFAULT;
3508     WINED3DSURFACE_DESC wined3d_desc;
3509     enum wined3d_format_id format;
3510     DWORD usage = 0;
3511     HRESULT hr;
3512
3513     if (!(desc->ddsCaps.dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY))
3514             && !((desc->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
3515             && (desc->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)))
3516     {
3517         /* Tests show surfaces without memory flags get these flags added
3518          * right after creation. */
3519         desc->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
3520     }
3521
3522     if (desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE))
3523     {
3524         usage |= WINED3DUSAGE_RENDERTARGET;
3525         desc->ddsCaps.dwCaps |= DDSCAPS_VISIBLE;
3526     }
3527
3528     if (desc->ddsCaps.dwCaps & (DDSCAPS_OVERLAY))
3529     {
3530         usage |= WINED3DUSAGE_OVERLAY;
3531     }
3532
3533     if (ddraw->depthstencil || (desc->ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
3534     {
3535         /* The depth stencil creation callback sets this flag. Set the
3536          * wined3d usage to let it know it's a depth/stencil surface. */
3537         usage |= WINED3DUSAGE_DEPTHSTENCIL;
3538     }
3539
3540     if (desc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
3541     {
3542         pool = WINED3DPOOL_SYSTEMMEM;
3543     }
3544     else if (desc->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
3545     {
3546         pool = WINED3DPOOL_MANAGED;
3547         /* Managed textures have the system memory flag set. */
3548         desc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
3549     }
3550     else if (desc->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
3551     {
3552         /* Videomemory adds localvidmem. This is mutually exclusive with
3553          * systemmemory and texturemanage. */
3554         desc->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM;
3555     }
3556
3557     format = PixelFormat_DD2WineD3D(&desc->u4.ddpfPixelFormat);
3558     if (format == WINED3DFMT_UNKNOWN)
3559     {
3560         WARN("Unsupported / unknown pixelformat.\n");
3561         return DDERR_INVALIDPIXELFORMAT;
3562     }
3563
3564     surface->lpVtbl = &ddraw_surface7_vtbl;
3565     surface->IDirectDrawSurface3_vtbl = &ddraw_surface3_vtbl;
3566     surface->IDirectDrawGammaControl_vtbl = &ddraw_gamma_control_vtbl;
3567     surface->IDirect3DTexture2_vtbl = &d3d_texture2_vtbl;
3568     surface->IDirect3DTexture_vtbl = &d3d_texture1_vtbl;
3569     surface->ref = 1;
3570     surface->version = 7;
3571     surface->ddraw = ddraw;
3572
3573     surface->surface_desc.dwSize = sizeof(DDSURFACEDESC2);
3574     surface->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
3575     DD_STRUCT_COPY_BYSIZE(&surface->surface_desc, desc);
3576
3577     surface->first_attached = surface;
3578     surface->ImplType = surface_type;
3579
3580     hr = IWineD3DDevice_CreateSurface(ddraw->wineD3DDevice, desc->dwWidth, desc->dwHeight, format,
3581             TRUE /* Lockable */, FALSE /* Discard */, mip_level, usage, pool,
3582             WINED3DMULTISAMPLE_NONE, 0 /* MultiSampleQuality */, surface_type, surface,
3583             &ddraw_null_wined3d_parent_ops, &surface->WineD3DSurface);
3584     if (FAILED(hr))
3585     {
3586         WARN("Failed to create wined3d surface, hr %#x.\n", hr);
3587         return hr;
3588     }
3589
3590     surface->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
3591     hr = IWineD3DSurface_GetDesc(surface->WineD3DSurface, &wined3d_desc);
3592     if (FAILED(hr))
3593     {
3594         ERR("Failed to get wined3d surface desc, hr %#x.\n", hr);
3595         IWineD3DSurface_Release(surface->WineD3DSurface);
3596         return hr;
3597     }
3598
3599     format = wined3d_desc.format;
3600     if (format == WINED3DFMT_UNKNOWN)
3601     {
3602         FIXME("IWineD3DSurface::GetDesc returned WINED3DFMT_UNKNOWN.\n");
3603     }
3604     PixelFormat_WineD3DtoDD(&surface->surface_desc.u4.ddpfPixelFormat, format);
3605
3606     /* Anno 1602 stores the pitch right after surface creation, so make sure
3607      * it's there. TODO: Test other fourcc formats. */
3608     if (format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3
3609             || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)
3610     {
3611         surface->surface_desc.dwFlags |= DDSD_LINEARSIZE;
3612         if (format == WINED3DFMT_DXT1)
3613         {
3614             surface->surface_desc.u1.dwLinearSize = max(4, wined3d_desc.width) * max(4, wined3d_desc.height) / 2;
3615         }
3616         else
3617         {
3618             surface->surface_desc.u1.dwLinearSize = max(4, wined3d_desc.width) * max(4, wined3d_desc.height);
3619         }
3620     }
3621     else
3622     {
3623         surface->surface_desc.dwFlags |= DDSD_PITCH;
3624         surface->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch(surface->WineD3DSurface);
3625     }
3626
3627     if (desc->dwFlags & DDSD_CKDESTOVERLAY)
3628     {
3629         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3630                 DDCKEY_DESTOVERLAY, (WINEDDCOLORKEY *)&desc->u3.ddckCKDestOverlay);
3631     }
3632     if (desc->dwFlags & DDSD_CKDESTBLT)
3633     {
3634         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3635                 DDCKEY_DESTBLT, (WINEDDCOLORKEY *)&desc->ddckCKDestBlt);
3636     }
3637     if (desc->dwFlags & DDSD_CKSRCOVERLAY)
3638     {
3639         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3640                 DDCKEY_SRCOVERLAY, (WINEDDCOLORKEY *)&desc->ddckCKSrcOverlay);
3641     }
3642     if (desc->dwFlags & DDSD_CKSRCBLT)
3643     {
3644         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3645                 DDCKEY_SRCBLT, (WINEDDCOLORKEY *)&desc->ddckCKSrcBlt);
3646     }
3647     if (desc->dwFlags & DDSD_LPSURFACE)
3648     {
3649         hr = IWineD3DSurface_SetMem(surface->WineD3DSurface, desc->lpSurface);
3650         if (FAILED(hr))
3651         {
3652             ERR("Failed to set surface memory, hr %#x.\n", hr);
3653             IWineD3DSurface_Release(surface->WineD3DSurface);
3654             return hr;
3655         }
3656     }
3657
3658     return DD_OK;
3659 }