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