wined3d: Get rid of the swapchain destroy callback.
[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->wined3d_texture)
356             wined3d_texture_decref(This->wined3d_texture);
357
358         /* If it's the RenderTarget, destroy the d3ddevice */
359         else if(This->wineD3DSwapChain)
360         {
361             if((ddraw->d3d_initialized) && (This == ddraw->d3d_target)) {
362                 TRACE("(%p) Destroying the render target, uninitializing D3D\n", This);
363
364                 /* Unset any index buffer, just to be sure */
365                 IWineD3DDevice_SetIndexBuffer(ddraw->wineD3DDevice, NULL, WINED3DFMT_UNKNOWN);
366                 IWineD3DDevice_SetDepthStencilSurface(ddraw->wineD3DDevice, NULL);
367                 IWineD3DDevice_SetVertexDeclaration(ddraw->wineD3DDevice, NULL);
368                 for (i = 0; i < ddraw->numConvertedDecls; ++i)
369                 {
370                     wined3d_vertex_declaration_decref(ddraw->decls[i].decl);
371                 }
372                 HeapFree(GetProcessHeap(), 0, ddraw->decls);
373                 ddraw->numConvertedDecls = 0;
374
375                 if (FAILED(IWineD3DDevice_Uninit3D(ddraw->wineD3DDevice)))
376                 {
377                     /* Not good */
378                     ERR("(%p) Failed to uninit 3D\n", This);
379                 }
380                 else
381                 {
382                     /* Free the d3d window if one was created */
383                     if(ddraw->d3d_window != 0 && ddraw->d3d_window != ddraw->dest_window)
384                     {
385                         TRACE(" (%p) Destroying the hidden render window %p\n", This, ddraw->d3d_window);
386                         DestroyWindow(ddraw->d3d_window);
387                         ddraw->d3d_window = 0;
388                     }
389                     /* Unset the pointers */
390                 }
391
392                 This->wineD3DSwapChain = NULL; /* Uninit3D releases the swapchain */
393                 ddraw->d3d_initialized = FALSE;
394                 ddraw->d3d_target = NULL;
395             }
396             else
397             {
398                 IWineD3DDevice_UninitGDI(ddraw->wineD3DDevice);
399                 This->wineD3DSwapChain = NULL;
400             }
401
402             /* Reset to the default surface implementation type. This is needed if apps use
403              * non render target surfaces and expect blits to work after destroying the render
404              * target.
405              *
406              * TODO: Recreate existing offscreen surfaces
407              */
408             ddraw->ImplType = DefaultSurfaceType;
409
410             /* Write a trace because D3D unloading was the reason for many
411              * crashes during development.
412              */
413             TRACE("(%p) D3D unloaded\n", This);
414         }
415
416         /* The refcount test shows that the palette is detached when the surface is destroyed */
417         IDirectDrawSurface7_SetPalette((IDirectDrawSurface7 *)This, NULL);
418
419         /* Loop through all complex attached surfaces,
420          * and destroy them.
421          *
422          * Yet again, only the root can have more than one complexly attached surface, all the others
423          * have a total of one;
424          */
425         for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
426         {
427             if(!This->complex_array[i]) break;
428
429             surf = This->complex_array[i];
430             This->complex_array[i] = NULL;
431             while(surf)
432             {
433                 IDirectDrawSurfaceImpl *destroy = surf;
434                 surf = surf->complex_array[0];              /* Iterate through the "tree" */
435                 ddraw_surface_destroy(destroy);             /* Destroy it */
436             }
437         }
438
439         /* Destroy the root surface. */
440         ddraw_surface_destroy(This);
441
442         /* Reduce the ddraw refcount */
443         if(ifaceToRelease) IUnknown_Release(ifaceToRelease);
444         LeaveCriticalSection(&ddraw_cs);
445     }
446
447     return ref;
448 }
449
450 static ULONG WINAPI ddraw_surface3_Release(IDirectDrawSurface3 *iface)
451 {
452     TRACE("iface %p.\n", iface);
453
454     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_surface3(iface));
455 }
456
457 static ULONG WINAPI ddraw_gamma_control_Release(IDirectDrawGammaControl *iface)
458 {
459     TRACE("iface %p.\n", iface);
460
461     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_gamma_control(iface));
462 }
463
464 static ULONG WINAPI d3d_texture2_Release(IDirect3DTexture2 *iface)
465 {
466     TRACE("iface %p.\n", iface);
467
468     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_texture2(iface));
469 }
470
471 static ULONG WINAPI d3d_texture1_Release(IDirect3DTexture *iface)
472 {
473     TRACE("iface %p.\n", iface);
474
475     return ddraw_surface7_Release((IDirectDrawSurface7 *)surface_from_texture1(iface));
476 }
477
478 /*****************************************************************************
479  * IDirectDrawSurface7::GetAttachedSurface
480  *
481  * Returns an attached surface with the requested caps. Surface attachment
482  * and complex surfaces are not clearly described by the MSDN or sdk,
483  * so this method is tricky and likely to contain problems.
484  * This implementation searches the complex list first, then the
485  * attachment chain.
486  *
487  * The chains are searched from This down to the last surface in the chain,
488  * not from the first element in the chain. The first surface found is
489  * returned. The MSDN says that this method fails if more than one surface
490  * matches the caps, but it is not sure if that is right. The attachment
491  * structure may not even allow two matching surfaces.
492  *
493  * The found surface is AddRef-ed before it is returned.
494  *
495  * Params:
496  *  Caps: Pointer to a DDCAPS2 structure describing the caps asked for
497  *  Surface: Address to store the found surface
498  *
499  * Returns:
500  *  DD_OK on success
501  *  DDERR_INVALIDPARAMS if Caps or Surface is NULL
502  *  DDERR_NOTFOUND if no surface was found
503  *
504  *****************************************************************************/
505 static HRESULT WINAPI ddraw_surface7_GetAttachedSurface(IDirectDrawSurface7 *iface,
506         DDSCAPS2 *Caps, IDirectDrawSurface7 **Surface)
507 {
508     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
509     IDirectDrawSurfaceImpl *surf;
510     DDSCAPS2 our_caps;
511     int i;
512
513     TRACE("iface %p, caps %p, attachment %p.\n", iface, Caps, Surface);
514
515     EnterCriticalSection(&ddraw_cs);
516
517     if(This->version < 7)
518     {
519         /* Earlier dx apps put garbage into these members, clear them */
520         our_caps.dwCaps = Caps->dwCaps;
521         our_caps.dwCaps2 = 0;
522         our_caps.dwCaps3 = 0;
523         our_caps.dwCaps4 = 0;
524     }
525     else
526     {
527         our_caps = *Caps;
528     }
529
530     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 */
531
532     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
533     {
534         surf = This->complex_array[i];
535         if(!surf) break;
536
537         if (TRACE_ON(ddraw))
538         {
539             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
540                    surf->surface_desc.ddsCaps.dwCaps,
541                    surf->surface_desc.ddsCaps.dwCaps2,
542                    surf->surface_desc.ddsCaps.dwCaps3,
543                    surf->surface_desc.ddsCaps.dwCaps4);
544         }
545
546         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
547             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
548
549             /* MSDN: "This method fails if more than one surface is attached
550              * that matches the capabilities requested."
551              *
552              * Not sure how to test this.
553              */
554
555             TRACE("(%p): Returning surface %p\n", This, surf);
556             TRACE("(%p): mipmapcount=%d\n", This, surf->mipmap_level);
557             *Surface = (IDirectDrawSurface7 *)surf;
558             ddraw_surface7_AddRef(*Surface);
559             LeaveCriticalSection(&ddraw_cs);
560             return DD_OK;
561         }
562     }
563
564     /* Next, look at the attachment chain */
565     surf = This;
566
567     while( (surf = surf->next_attached) )
568     {
569         if (TRACE_ON(ddraw))
570         {
571             TRACE("Surface: (%p) caps: %x,%x,%x,%x\n", surf,
572                    surf->surface_desc.ddsCaps.dwCaps,
573                    surf->surface_desc.ddsCaps.dwCaps2,
574                    surf->surface_desc.ddsCaps.dwCaps3,
575                    surf->surface_desc.ddsCaps.dwCaps4);
576         }
577
578         if (((surf->surface_desc.ddsCaps.dwCaps & our_caps.dwCaps) == our_caps.dwCaps) &&
579             ((surf->surface_desc.ddsCaps.dwCaps2 & our_caps.dwCaps2) == our_caps.dwCaps2)) {
580
581             TRACE("(%p): Returning surface %p\n", This, surf);
582             *Surface = (IDirectDrawSurface7 *)surf;
583             ddraw_surface7_AddRef(*Surface);
584             LeaveCriticalSection(&ddraw_cs);
585             return DD_OK;
586         }
587     }
588
589     TRACE("(%p) Didn't find a valid surface\n", This);
590     LeaveCriticalSection(&ddraw_cs);
591
592     *Surface = NULL;
593     return DDERR_NOTFOUND;
594 }
595
596 static HRESULT WINAPI ddraw_surface3_GetAttachedSurface(IDirectDrawSurface3 *iface,
597         DDSCAPS *caps, IDirectDrawSurface3 **attachment)
598 {
599     IDirectDrawSurface7 *attachment7;
600     DDSCAPS2 caps2;
601     HRESULT hr;
602
603     TRACE("iface %p, caps %p, attachment %p.\n", iface, caps, attachment);
604
605     caps2.dwCaps  = caps->dwCaps;
606     caps2.dwCaps2 = 0;
607     caps2.dwCaps3 = 0;
608     caps2.dwCaps4 = 0;
609
610     hr = ddraw_surface7_GetAttachedSurface((IDirectDrawSurface7 *)surface_from_surface3(iface),
611             &caps2, &attachment7);
612     if (FAILED(hr)) *attachment = NULL;
613     else *attachment = attachment7 ?
614             (IDirectDrawSurface3 *)&((IDirectDrawSurfaceImpl *)attachment7)->IDirectDrawSurface3_vtbl : NULL;
615
616     return hr;
617 }
618
619 /*****************************************************************************
620  * IDirectDrawSurface7::Lock
621  *
622  * Locks the surface and returns a pointer to the surface's memory
623  *
624  * Params:
625  *  Rect: Rectangle to lock. If NULL, the whole surface is locked
626  *  DDSD: Pointer to a DDSURFACEDESC2 which shall receive the surface's desc.
627  *  Flags: Locking flags, e.g Read only or write only
628  *  h: An event handle that's not used and must be NULL
629  *
630  * Returns:
631  *  DD_OK on success
632  *  DDERR_INVALIDPARAMS if DDSD is NULL
633  *  For more details, see IWineD3DSurface::LockRect
634  *
635  *****************************************************************************/
636 static HRESULT WINAPI ddraw_surface7_Lock(IDirectDrawSurface7 *iface,
637         RECT *Rect, DDSURFACEDESC2 *DDSD, DWORD Flags, HANDLE h)
638 {
639     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
640     WINED3DLOCKED_RECT LockedRect;
641     HRESULT hr;
642
643     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
644             iface, wine_dbgstr_rect(Rect), DDSD, Flags, h);
645
646     if(!DDSD)
647         return DDERR_INVALIDPARAMS;
648
649     /* This->surface_desc.dwWidth and dwHeight are changeable, thus lock */
650     EnterCriticalSection(&ddraw_cs);
651
652     /* Should I check for the handle to be NULL?
653      *
654      * The DDLOCK flags and the D3DLOCK flags are equal
655      * for the supported values. The others are ignored by WineD3D
656      */
657
658     if(DDSD->dwSize != sizeof(DDSURFACEDESC) &&
659        DDSD->dwSize != sizeof(DDSURFACEDESC2))
660     {
661         WARN("Invalid structure size %d, returning DDERR_INVALIDPARAMS\n", DDERR_INVALIDPARAMS);
662         LeaveCriticalSection(&ddraw_cs);
663         return DDERR_INVALIDPARAMS;
664     }
665
666     /* Windows zeroes this if the rect is invalid */
667     DDSD->lpSurface = 0;
668
669     if (Rect)
670     {
671         if ((Rect->left < 0)
672                 || (Rect->top < 0)
673                 || (Rect->left > Rect->right)
674                 || (Rect->top > Rect->bottom)
675                 || (Rect->right > This->surface_desc.dwWidth)
676                 || (Rect->bottom > This->surface_desc.dwHeight))
677         {
678             WARN("Trying to lock an invalid rectangle, returning DDERR_INVALIDPARAMS\n");
679             LeaveCriticalSection(&ddraw_cs);
680             return DDERR_INVALIDPARAMS;
681         }
682     }
683
684     hr = IWineD3DSurface_Map(This->WineD3DSurface, &LockedRect, Rect, Flags);
685     if (FAILED(hr))
686     {
687         LeaveCriticalSection(&ddraw_cs);
688         switch(hr)
689         {
690             /* D3D8 and D3D9 return the general D3DERR_INVALIDCALL error, but ddraw has a more
691              * specific error. But since IWineD3DSurface::LockRect returns that error in this
692              * only occasion, keep d3d8 and d3d9 free from the return value override. There are
693              * many different places where d3d8/9 would have to catch the DDERR_SURFACEBUSY, it
694              * is much easier to do it in one place in ddraw
695              */
696             case WINED3DERR_INVALIDCALL:    return DDERR_SURFACEBUSY;
697             default:                        return hr;
698         }
699     }
700
701     /* Override the memory area. The pitch should be set already. Strangely windows
702      * does not set the LPSURFACE flag on locked surfaces !?!.
703      * DDSD->dwFlags |= DDSD_LPSURFACE;
704      */
705     This->surface_desc.lpSurface = LockedRect.pBits;
706     DD_STRUCT_COPY_BYSIZE(DDSD,&(This->surface_desc));
707
708     TRACE("locked surface returning description :\n");
709     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
710
711     LeaveCriticalSection(&ddraw_cs);
712     return DD_OK;
713 }
714
715 static HRESULT WINAPI ddraw_surface3_Lock(IDirectDrawSurface3 *iface, RECT *rect,
716         DDSURFACEDESC *surface_desc, DWORD flags, HANDLE h)
717 {
718     TRACE("iface %p, rect %s, surface_desc %p, flags %#x, h %p.\n",
719             iface, wine_dbgstr_rect(rect), surface_desc, flags, h);
720
721     return ddraw_surface7_Lock((IDirectDrawSurface7 *)surface_from_surface3(iface),
722             rect, (DDSURFACEDESC2 *)surface_desc, flags, h);
723 }
724
725 /*****************************************************************************
726  * IDirectDrawSurface7::Unlock
727  *
728  * Unlocks an locked surface
729  *
730  * Params:
731  *  Rect: Not used by this implementation
732  *
733  * Returns:
734  *  D3D_OK on success
735  *  For more details, see IWineD3DSurface::UnlockRect
736  *
737  *****************************************************************************/
738 static HRESULT WINAPI ddraw_surface7_Unlock(IDirectDrawSurface7 *iface, RECT *pRect)
739 {
740     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
741     HRESULT hr;
742
743     TRACE("iface %p, rect %s.\n", iface, wine_dbgstr_rect(pRect));
744
745     EnterCriticalSection(&ddraw_cs);
746     hr = IWineD3DSurface_Unmap(This->WineD3DSurface);
747     if (SUCCEEDED(hr))
748     {
749         This->surface_desc.lpSurface = NULL;
750     }
751     LeaveCriticalSection(&ddraw_cs);
752     return hr;
753 }
754
755 static HRESULT WINAPI ddraw_surface3_Unlock(IDirectDrawSurface3 *iface, void *data)
756 {
757     TRACE("iface %p, data %p.\n", iface, data);
758
759     /* data might not be the LPRECT of later versions, so drop it. */
760     return ddraw_surface7_Unlock((IDirectDrawSurface7 *)surface_from_surface3(iface), NULL);
761 }
762
763 /*****************************************************************************
764  * IDirectDrawSurface7::Flip
765  *
766  * Flips a surface with the DDSCAPS_FLIP flag. The flip is relayed to
767  * IWineD3DSurface::Flip. Because WineD3D doesn't handle attached surfaces,
768  * the flip target is passed to WineD3D, even if the app didn't specify one
769  *
770  * Params:
771  *  DestOverride: Specifies the surface that will become the new front
772  *                buffer. If NULL, the current back buffer is used
773  *  Flags: some DirectDraw flags, see include/ddraw.h
774  *
775  * Returns:
776  *  DD_OK on success
777  *  DDERR_NOTFLIPPABLE if no flip target could be found
778  *  DDERR_INVALIDOBJECT if the surface isn't a front buffer
779  *  For more details, see IWineD3DSurface::Flip
780  *
781  *****************************************************************************/
782 static HRESULT WINAPI ddraw_surface7_Flip(IDirectDrawSurface7 *iface, IDirectDrawSurface7 *DestOverride, DWORD Flags)
783 {
784     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
785     IDirectDrawSurfaceImpl *Override = (IDirectDrawSurfaceImpl *)DestOverride;
786     IDirectDrawSurface7 *Override7;
787     HRESULT hr;
788
789     TRACE("iface %p, dst %p, flags %#x.\n", iface, DestOverride, Flags);
790
791     /* Flip has to be called from a front buffer
792      * What about overlay surfaces, AFAIK they can flip too?
793      */
794     if( !(This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_OVERLAY)) )
795         return DDERR_INVALIDOBJECT; /* Unchecked */
796
797     EnterCriticalSection(&ddraw_cs);
798
799     /* WineD3D doesn't keep track of attached surface, so find the target */
800     if(!Override)
801     {
802         DDSCAPS2 Caps;
803
804         memset(&Caps, 0, sizeof(Caps));
805         Caps.dwCaps |= DDSCAPS_BACKBUFFER;
806         hr = ddraw_surface7_GetAttachedSurface(iface, &Caps, &Override7);
807         if(hr != DD_OK)
808         {
809             ERR("Can't find a flip target\n");
810             LeaveCriticalSection(&ddraw_cs);
811             return DDERR_NOTFLIPPABLE; /* Unchecked */
812         }
813         Override = (IDirectDrawSurfaceImpl *)Override7;
814
815         /* For the GetAttachedSurface */
816         ddraw_surface7_Release(Override7);
817     }
818
819     hr = IWineD3DSurface_Flip(This->WineD3DSurface,
820                               Override->WineD3DSurface,
821                               Flags);
822     LeaveCriticalSection(&ddraw_cs);
823     return hr;
824 }
825
826 static HRESULT WINAPI ddraw_surface3_Flip(IDirectDrawSurface3 *iface, IDirectDrawSurface3 *dst, DWORD flags)
827 {
828     TRACE("iface %p, dst %p, flags %#x.\n", iface, dst, flags);
829
830     return ddraw_surface7_Flip((IDirectDrawSurface7 *)surface_from_surface3(iface),
831             dst ? (IDirectDrawSurface7 *)surface_from_surface3(dst) : NULL, flags);
832 }
833
834 /*****************************************************************************
835  * IDirectDrawSurface7::Blt
836  *
837  * Performs a blit on the surface
838  *
839  * Params:
840  *  DestRect: Destination rectangle, can be NULL
841  *  SrcSurface: Source surface, can be NULL
842  *  SrcRect: Source rectangle, can be NULL
843  *  Flags: Blt flags
844  *  DDBltFx: Some extended blt parameters, connected to the flags
845  *
846  * Returns:
847  *  D3D_OK on success
848  *  See IWineD3DSurface::Blt for more details
849  *
850  *****************************************************************************/
851 static HRESULT WINAPI ddraw_surface7_Blt(IDirectDrawSurface7 *iface, RECT *DestRect,
852         IDirectDrawSurface7 *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx)
853 {
854     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
855     IDirectDrawSurfaceImpl *Src = (IDirectDrawSurfaceImpl *)SrcSurface;
856     HRESULT hr;
857
858     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p.\n",
859             iface, wine_dbgstr_rect(DestRect), SrcSurface, wine_dbgstr_rect(SrcRect), Flags, DDBltFx);
860
861     /* Check for validity of the flags here. WineD3D Has the software-opengl selection path and would have
862      * to check at 2 places, and sometimes do double checks. This also saves the call to wined3d :-)
863      */
864     if((Flags & DDBLT_KEYSRCOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYSRC)) {
865         WARN("Invalid source color key parameters, returning DDERR_INVALIDPARAMS\n");
866         return DDERR_INVALIDPARAMS;
867     }
868
869     if((Flags & DDBLT_KEYDESTOVERRIDE) && (!DDBltFx || Flags & DDBLT_KEYDEST)) {
870         WARN("Invalid destination color key parameters, returning DDERR_INVALIDPARAMS\n");
871         return DDERR_INVALIDPARAMS;
872     }
873
874     /* Sizes can change, therefore hold the lock when testing the rectangles */
875     EnterCriticalSection(&ddraw_cs);
876     if(DestRect)
877     {
878         if(DestRect->top >= DestRect->bottom || DestRect->left >= DestRect->right ||
879            DestRect->right > This->surface_desc.dwWidth ||
880            DestRect->bottom > This->surface_desc.dwHeight)
881         {
882             WARN("Destination rectangle is invalid, returning DDERR_INVALIDRECT\n");
883             LeaveCriticalSection(&ddraw_cs);
884             return DDERR_INVALIDRECT;
885         }
886     }
887     if(Src && SrcRect)
888     {
889         if(SrcRect->top >= SrcRect->bottom || SrcRect->left >=SrcRect->right ||
890            SrcRect->right > Src->surface_desc.dwWidth ||
891            SrcRect->bottom > Src->surface_desc.dwHeight)
892         {
893             WARN("Source rectangle is invalid, returning DDERR_INVALIDRECT\n");
894             LeaveCriticalSection(&ddraw_cs);
895             return DDERR_INVALIDRECT;
896         }
897     }
898
899     if(Flags & DDBLT_KEYSRC && (!Src || !(Src->surface_desc.dwFlags & DDSD_CKSRCBLT))) {
900         WARN("DDBLT_KEYDEST blit without color key in surface, returning DDERR_INVALIDPARAMS\n");
901         LeaveCriticalSection(&ddraw_cs);
902         return DDERR_INVALIDPARAMS;
903     }
904
905     /* TODO: Check if the DDBltFx contains any ddraw surface pointers. If it does, copy the struct,
906      * and replace the ddraw surfaces with the wined3d surfaces
907      * So far no blitting operations using surfaces in the bltfx struct are supported anyway.
908      */
909     hr = IWineD3DSurface_Blt(This->WineD3DSurface, DestRect, Src ? Src->WineD3DSurface : NULL,
910             SrcRect, Flags, (WINEDDBLTFX *)DDBltFx, WINED3DTEXF_LINEAR);
911
912     LeaveCriticalSection(&ddraw_cs);
913     switch(hr)
914     {
915         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
916         case WINED3DERR_WRONGTEXTUREFORMAT: return DDERR_INVALIDPIXELFORMAT;
917         default:                            return hr;
918     }
919 }
920
921 static HRESULT WINAPI ddraw_surface3_Blt(IDirectDrawSurface3 *iface, RECT *dst_rect,
922         IDirectDrawSurface3 *src_surface, RECT *src_rect, DWORD flags, DDBLTFX *fx)
923 {
924     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p.\n",
925             iface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect), flags, fx);
926
927     return ddraw_surface7_Blt((IDirectDrawSurface7 *)surface_from_surface3(iface), dst_rect,
928             src_surface ? (IDirectDrawSurface7 *)surface_from_surface3(src_surface) : NULL, src_rect, flags, fx);
929 }
930
931 /*****************************************************************************
932  * IDirectDrawSurface7::AddAttachedSurface
933  *
934  * Attaches a surface to another surface. How the surface attachments work
935  * is not totally understood yet, and this method is prone to problems.
936  * he surface that is attached is AddRef-ed.
937  *
938  * Tests with complex surfaces suggest that the surface attachments form a
939  * tree, but no method to test this has been found yet.
940  *
941  * The attachment list consists of a first surface (first_attached) and
942  * for each surface a pointer to the next attached surface (next_attached).
943  * For the first surface, and a surface that has no attachments
944  * first_attached points to the surface itself. A surface that has
945  * no successors in the chain has next_attached set to NULL.
946  *
947  * Newly attached surfaces are attached right after the root surface.
948  * If a surface is attached to a complex surface compound, it's attached to
949  * the surface that the app requested, not the complex root. See
950  * GetAttachedSurface for a description how surfaces are found.
951  *
952  * This is how the current implementation works, and it was coded by looking
953  * at the needs of the applications.
954  *
955  * So far only Z-Buffer attachments are tested, and they are activated in
956  * WineD3D. Mipmaps could be tricky to activate in WineD3D.
957  * Back buffers should work in 2D mode, but they are not tested(They can be
958  * attached in older iface versions). Rendering to the front buffer and
959  * switching between that and double buffering is not yet implemented in
960  * WineD3D, so for 3D it might have unexpected results.
961  *
962  * ddraw_surface_attach_surface is the real thing,
963  * ddraw_surface7_AddAttachedSurface is a wrapper around it that
964  * performs additional checks. Version 7 of this interface is much more restrictive
965  * than its predecessors.
966  *
967  * Params:
968  *  Attach: Surface to attach to iface
969  *
970  * Returns:
971  *  DD_OK on success
972  *  DDERR_CANNOTATTACHSURFACE if the surface can't be attached for some reason
973  *
974  *****************************************************************************/
975 static HRESULT ddraw_surface_attach_surface(IDirectDrawSurfaceImpl *This, IDirectDrawSurfaceImpl *Surf)
976 {
977     TRACE("surface %p, attachment %p.\n", This, Surf);
978
979     if(Surf == This)
980         return DDERR_CANNOTATTACHSURFACE; /* unchecked */
981
982     EnterCriticalSection(&ddraw_cs);
983
984     /* Check if the surface is already attached somewhere */
985     if (Surf->next_attached || Surf->first_attached != Surf)
986     {
987         /* TODO: Test for the structure of the manual attachment. Is it a
988          * chain or a list? What happens if one surface is attached to 2
989          * different surfaces? */
990         WARN("Surface %p is already attached somewhere. next_attached %p, first_attached %p.\n",
991                 Surf, Surf->next_attached, Surf->first_attached);
992
993         LeaveCriticalSection(&ddraw_cs);
994         return DDERR_SURFACEALREADYATTACHED;
995     }
996
997     /* This inserts the new surface at the 2nd position in the chain, right after the root surface */
998     Surf->next_attached = This->next_attached;
999     Surf->first_attached = This->first_attached;
1000     This->next_attached = Surf;
1001
1002     /* Check if the WineD3D depth stencil needs updating */
1003     if(This->ddraw->d3ddevice)
1004     {
1005         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
1006     }
1007
1008     ddraw_surface7_AddRef((IDirectDrawSurface7 *)Surf);
1009     LeaveCriticalSection(&ddraw_cs);
1010     return DD_OK;
1011 }
1012
1013 static HRESULT WINAPI ddraw_surface7_AddAttachedSurface(IDirectDrawSurface7 *iface, IDirectDrawSurface7 *Attach)
1014 {
1015     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1016     IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Attach;
1017
1018     TRACE("iface %p, attachment %p.\n", iface, Attach);
1019
1020     /* Version 7 of this interface seems to refuse everything except z buffers, as per msdn */
1021     if(!(Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
1022     {
1023
1024         WARN("Application tries to attach a non Z buffer surface. caps %08x\n",
1025               Surf->surface_desc.ddsCaps.dwCaps);
1026         return DDERR_CANNOTATTACHSURFACE;
1027     }
1028
1029     return ddraw_surface_attach_surface(This, Surf);
1030 }
1031
1032 static HRESULT WINAPI ddraw_surface3_AddAttachedSurface(IDirectDrawSurface3 *iface, IDirectDrawSurface3 *attachment)
1033 {
1034     IDirectDrawSurfaceImpl *surface = surface_from_surface3(iface);
1035     IDirectDrawSurfaceImpl *attach_impl = surface_from_surface3(attachment);
1036
1037     TRACE("iface %p, attachment %p.\n", iface, attachment);
1038
1039     /* Tests suggest that
1040      * -> offscreen plain surfaces can be attached to other offscreen plain surfaces
1041      * -> offscreen plain surfaces can be attached to primaries
1042      * -> primaries can be attached to offscreen plain surfaces
1043      * -> z buffers can be attached to primaries */
1044     if (surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_OFFSCREENPLAIN)
1045             && attach_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_OFFSCREENPLAIN))
1046     {
1047         /* Sizes have to match */
1048         if (attach_impl->surface_desc.dwWidth != surface->surface_desc.dwWidth
1049                 || attach_impl->surface_desc.dwHeight != surface->surface_desc.dwHeight)
1050         {
1051             WARN("Surface sizes do not match.\n");
1052             return DDERR_CANNOTATTACHSURFACE;
1053         }
1054         /* OK */
1055     }
1056     else if (surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE)
1057             && attach_impl->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER))
1058     {
1059         /* OK */
1060     }
1061     else
1062     {
1063         WARN("Invalid attachment combination.\n");
1064         return DDERR_CANNOTATTACHSURFACE;
1065     }
1066
1067     return ddraw_surface_attach_surface(surface, attach_impl);
1068 }
1069
1070 /*****************************************************************************
1071  * IDirectDrawSurface7::DeleteAttachedSurface
1072  *
1073  * Removes a surface from the attachment chain. The surface's refcount
1074  * is decreased by one after it has been removed
1075  *
1076  * Params:
1077  *  Flags: Some flags, not used by this implementation
1078  *  Attach: Surface to detach
1079  *
1080  * Returns:
1081  *  DD_OK on success
1082  *  DDERR_SURFACENOTATTACHED if the surface isn't attached to
1083  *
1084  *****************************************************************************/
1085 static HRESULT WINAPI ddraw_surface7_DeleteAttachedSurface(IDirectDrawSurface7 *iface,
1086         DWORD Flags, IDirectDrawSurface7 *Attach)
1087 {
1088     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1089     IDirectDrawSurfaceImpl *Surf = (IDirectDrawSurfaceImpl *)Attach;
1090     IDirectDrawSurfaceImpl *Prev = This;
1091
1092     TRACE("iface %p, flags %#x, attachment %p.\n", iface, Flags, Attach);
1093
1094     EnterCriticalSection(&ddraw_cs);
1095     if (!Surf || (Surf->first_attached != This) || (Surf == This) )
1096     {
1097         LeaveCriticalSection(&ddraw_cs);
1098         return DDERR_CANNOTDETACHSURFACE;
1099     }
1100
1101     /* Remove MIPMAPSUBLEVEL if this seemed to be one */
1102     if (This->surface_desc.ddsCaps.dwCaps &
1103         Surf->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
1104     {
1105         Surf->surface_desc.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
1106         /* FIXME: we should probably also subtract from dwMipMapCount of this
1107          * and all parent surfaces */
1108     }
1109
1110     /* Find the predecessor of the detached surface */
1111     while(Prev)
1112     {
1113         if(Prev->next_attached == Surf) break;
1114         Prev = Prev->next_attached;
1115     }
1116
1117     /* There must be a surface, otherwise there's a bug */
1118     assert(Prev != NULL);
1119
1120     /* Unchain the surface */
1121     Prev->next_attached = Surf->next_attached;
1122     Surf->next_attached = NULL;
1123     Surf->first_attached = Surf;
1124
1125     /* Check if the WineD3D depth stencil needs updating */
1126     if(This->ddraw->d3ddevice)
1127     {
1128         IDirect3DDeviceImpl_UpdateDepthStencil(This->ddraw->d3ddevice);
1129     }
1130
1131     ddraw_surface7_Release(Attach);
1132     LeaveCriticalSection(&ddraw_cs);
1133     return DD_OK;
1134 }
1135
1136 static HRESULT WINAPI ddraw_surface3_DeleteAttachedSurface(IDirectDrawSurface3 *iface,
1137         DWORD flags, IDirectDrawSurface3 *attachment)
1138 {
1139     TRACE("iface %p, flags %#x, attachment %p.\n", iface, flags, attachment);
1140
1141     return ddraw_surface7_DeleteAttachedSurface((IDirectDrawSurface7 *)surface_from_surface3(iface), flags,
1142             attachment ? (IDirectDrawSurface7 *)surface_from_surface3(attachment) : NULL);
1143 }
1144
1145 /*****************************************************************************
1146  * IDirectDrawSurface7::AddOverlayDirtyRect
1147  *
1148  * "This method is not currently implemented"
1149  *
1150  * Params:
1151  *  Rect: ?
1152  *
1153  * Returns:
1154  *  DDERR_UNSUPPORTED
1155  *
1156  *****************************************************************************/
1157 static HRESULT WINAPI ddraw_surface7_AddOverlayDirtyRect(IDirectDrawSurface7 *iface, RECT *Rect)
1158 {
1159     TRACE("iface %p, rect %s.\n", iface, wine_dbgstr_rect(Rect));
1160
1161     return DDERR_UNSUPPORTED; /* unchecked */
1162 }
1163
1164 static HRESULT WINAPI ddraw_surface3_AddOverlayDirtyRect(IDirectDrawSurface3 *iface, RECT *rect)
1165 {
1166     TRACE("iface %p, rect %s.\n", iface, wine_dbgstr_rect(rect));
1167
1168     return ddraw_surface7_AddOverlayDirtyRect((IDirectDrawSurface7 *)surface_from_surface3(iface), rect);
1169 }
1170
1171 /*****************************************************************************
1172  * IDirectDrawSurface7::GetDC
1173  *
1174  * Returns a GDI device context for the surface
1175  *
1176  * Params:
1177  *  hdc: Address of a HDC variable to store the dc to
1178  *
1179  * Returns:
1180  *  DD_OK on success
1181  *  DDERR_INVALIDPARAMS if hdc is NULL
1182  *  For details, see IWineD3DSurface::GetDC
1183  *
1184  *****************************************************************************/
1185 static HRESULT WINAPI ddraw_surface7_GetDC(IDirectDrawSurface7 *iface, HDC *hdc)
1186 {
1187     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1188     HRESULT hr;
1189
1190     TRACE("iface %p, dc %p.\n", iface, hdc);
1191
1192     if(!hdc)
1193         return DDERR_INVALIDPARAMS;
1194
1195     EnterCriticalSection(&ddraw_cs);
1196     hr = IWineD3DSurface_GetDC(This->WineD3DSurface,
1197                                hdc);
1198     LeaveCriticalSection(&ddraw_cs);
1199     switch(hr)
1200     {
1201         /* Some, but not all errors set *hdc to NULL. E.g. DCALREADYCREATED does not
1202          * touch *hdc
1203          */
1204         case WINED3DERR_INVALIDCALL:
1205             if(hdc) *hdc = NULL;
1206             return DDERR_INVALIDPARAMS;
1207
1208         default: return hr;
1209     }
1210 }
1211
1212 static HRESULT WINAPI ddraw_surface3_GetDC(IDirectDrawSurface3 *iface, HDC *dc)
1213 {
1214     TRACE("iface %p, dc %p.\n", iface, dc);
1215
1216     return ddraw_surface7_GetDC((IDirectDrawSurface7 *)surface_from_surface3(iface), dc);
1217 }
1218
1219 /*****************************************************************************
1220  * IDirectDrawSurface7::ReleaseDC
1221  *
1222  * Releases the DC that was constructed with GetDC
1223  *
1224  * Params:
1225  *  hdc: HDC to release
1226  *
1227  * Returns:
1228  *  DD_OK on success
1229  *  For more details, see IWineD3DSurface::ReleaseDC
1230  *
1231  *****************************************************************************/
1232 static HRESULT WINAPI ddraw_surface7_ReleaseDC(IDirectDrawSurface7 *iface, HDC hdc)
1233 {
1234     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1235     HRESULT hr;
1236
1237     TRACE("iface %p, dc %p.\n", iface, hdc);
1238
1239     EnterCriticalSection(&ddraw_cs);
1240     hr = IWineD3DSurface_ReleaseDC(This->WineD3DSurface, hdc);
1241     LeaveCriticalSection(&ddraw_cs);
1242     return hr;
1243 }
1244
1245 static HRESULT WINAPI ddraw_surface3_ReleaseDC(IDirectDrawSurface3 *iface, HDC dc)
1246 {
1247     TRACE("iface %p, dc %p.\n", iface, dc);
1248
1249     return ddraw_surface7_ReleaseDC((IDirectDrawSurface7 *)surface_from_surface3(iface), dc);
1250 }
1251
1252 /*****************************************************************************
1253  * IDirectDrawSurface7::GetCaps
1254  *
1255  * Returns the surface's caps
1256  *
1257  * Params:
1258  *  Caps: Address to write the caps to
1259  *
1260  * Returns:
1261  *  DD_OK on success
1262  *  DDERR_INVALIDPARAMS if Caps is NULL
1263  *
1264  *****************************************************************************/
1265 static HRESULT WINAPI ddraw_surface7_GetCaps(IDirectDrawSurface7 *iface, DDSCAPS2 *Caps)
1266 {
1267     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1268
1269     TRACE("iface %p, caps %p.\n", iface, Caps);
1270
1271     if(!Caps)
1272         return DDERR_INVALIDPARAMS;
1273
1274     *Caps = This->surface_desc.ddsCaps;
1275     return DD_OK;
1276 }
1277
1278 static HRESULT WINAPI ddraw_surface3_GetCaps(IDirectDrawSurface3 *iface, DDSCAPS *caps)
1279 {
1280     DDSCAPS2 caps2;
1281     HRESULT hr;
1282
1283     TRACE("iface %p, caps %p.\n", iface, caps);
1284
1285     hr = ddraw_surface7_GetCaps((IDirectDrawSurface7 *)surface_from_surface3(iface), &caps2);
1286     if (FAILED(hr)) return hr;
1287
1288     caps->dwCaps = caps2.dwCaps;
1289     return hr;
1290 }
1291
1292 /*****************************************************************************
1293  * IDirectDrawSurface7::SetPriority
1294  *
1295  * Sets a texture priority for managed textures.
1296  *
1297  * Params:
1298  *  Priority: The new priority
1299  *
1300  * Returns:
1301  *  DD_OK on success
1302  *  For more details, see IWineD3DSurface::SetPriority
1303  *
1304  *****************************************************************************/
1305 static HRESULT WINAPI ddraw_surface7_SetPriority(IDirectDrawSurface7 *iface, DWORD Priority)
1306 {
1307     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1308     HRESULT hr;
1309
1310     TRACE("iface %p, priority %u.\n", iface, Priority);
1311
1312     EnterCriticalSection(&ddraw_cs);
1313     hr = IWineD3DSurface_SetPriority(This->WineD3DSurface, Priority);
1314     LeaveCriticalSection(&ddraw_cs);
1315     return hr;
1316 }
1317
1318 /*****************************************************************************
1319  * IDirectDrawSurface7::GetPriority
1320  *
1321  * Returns the surface's priority
1322  *
1323  * Params:
1324  *  Priority: Address of a variable to write the priority to
1325  *
1326  * Returns:
1327  *  D3D_OK on success
1328  *  DDERR_INVALIDPARAMS if Priority == NULL
1329  *  For more details, see IWineD3DSurface::GetPriority
1330  *
1331  *****************************************************************************/
1332 static HRESULT WINAPI ddraw_surface7_GetPriority(IDirectDrawSurface7 *iface, DWORD *Priority)
1333 {
1334     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1335
1336     TRACE("iface %p, priority %p.\n", iface, Priority);
1337
1338     if(!Priority)
1339     {
1340         return DDERR_INVALIDPARAMS;
1341     }
1342
1343     EnterCriticalSection(&ddraw_cs);
1344     *Priority = IWineD3DSurface_GetPriority(This->WineD3DSurface);
1345     LeaveCriticalSection(&ddraw_cs);
1346     return DD_OK;
1347 }
1348
1349 /*****************************************************************************
1350  * IDirectDrawSurface7::SetPrivateData
1351  *
1352  * Stores some data in the surface that is intended for the application's
1353  * use.
1354  *
1355  * Params:
1356  *  tag: GUID that identifies the data
1357  *  Data: Pointer to the private data
1358  *  Size: Size of the private data
1359  *  Flags: Some flags
1360  *
1361  * Returns:
1362  *  D3D_OK on success
1363  *  For more details, see IWineD3DSurface::SetPrivateData
1364  *
1365  *****************************************************************************/
1366 static HRESULT WINAPI ddraw_surface7_SetPrivateData(IDirectDrawSurface7 *iface,
1367         REFGUID tag, void *Data, DWORD Size, DWORD Flags)
1368 {
1369     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1370     HRESULT hr;
1371
1372     TRACE("iface %p, tag %s, data %p, data_size %u, flags %#x.\n",
1373             iface, debugstr_guid(tag), Data, Size, Flags);
1374
1375     EnterCriticalSection(&ddraw_cs);
1376     hr = IWineD3DSurface_SetPrivateData(This->WineD3DSurface,
1377                                         tag,
1378                                         Data,
1379                                         Size,
1380                                         Flags);
1381     LeaveCriticalSection(&ddraw_cs);
1382     switch(hr)
1383     {
1384         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1385         default:                            return hr;
1386     }
1387 }
1388
1389 /*****************************************************************************
1390  * IDirectDrawSurface7::GetPrivateData
1391  *
1392  * Returns the private data set with IDirectDrawSurface7::SetPrivateData
1393  *
1394  * Params:
1395  *  tag: GUID of the data to return
1396  *  Data: Address where to write the data to
1397  *  Size: Size of the buffer at Data
1398  *
1399  * Returns:
1400  *  DD_OK on success
1401  *  DDERR_INVALIDPARAMS if Data is NULL
1402  *  For more details, see IWineD3DSurface::GetPrivateData
1403  *
1404  *****************************************************************************/
1405 static HRESULT WINAPI ddraw_surface7_GetPrivateData(IDirectDrawSurface7 *iface, REFGUID tag, void *Data, DWORD *Size)
1406 {
1407     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1408     HRESULT hr;
1409
1410     TRACE("iface %p, tag %s, data %p, data_size %p.\n",
1411             iface, debugstr_guid(tag), Data, Size);
1412
1413     if(!Data)
1414         return DDERR_INVALIDPARAMS;
1415
1416     EnterCriticalSection(&ddraw_cs);
1417     hr = IWineD3DSurface_GetPrivateData(This->WineD3DSurface,
1418                                         tag,
1419                                         Data,
1420                                         Size);
1421     LeaveCriticalSection(&ddraw_cs);
1422     return hr;
1423 }
1424
1425 /*****************************************************************************
1426  * IDirectDrawSurface7::FreePrivateData
1427  *
1428  * Frees private data stored in the surface
1429  *
1430  * Params:
1431  *  tag: Tag of the data to free
1432  *
1433  * Returns:
1434  *  D3D_OK on success
1435  *  For more details, see IWineD3DSurface::FreePrivateData
1436  *
1437  *****************************************************************************/
1438 static HRESULT WINAPI ddraw_surface7_FreePrivateData(IDirectDrawSurface7 *iface, REFGUID tag)
1439 {
1440     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1441     HRESULT hr;
1442
1443     TRACE("iface %p, tag %s.\n", iface, debugstr_guid(tag));
1444
1445     EnterCriticalSection(&ddraw_cs);
1446     hr = IWineD3DSurface_FreePrivateData(This->WineD3DSurface, tag);
1447     LeaveCriticalSection(&ddraw_cs);
1448     return hr;
1449 }
1450
1451 /*****************************************************************************
1452  * IDirectDrawSurface7::PageLock
1453  *
1454  * Prevents a sysmem surface from being paged out
1455  *
1456  * Params:
1457  *  Flags: Not used, must be 0(unchecked)
1458  *
1459  * Returns:
1460  *  DD_OK, because it's a stub
1461  *
1462  *****************************************************************************/
1463 static HRESULT WINAPI ddraw_surface7_PageLock(IDirectDrawSurface7 *iface, DWORD Flags)
1464 {
1465     TRACE("iface %p, flags %#x.\n", iface, Flags);
1466
1467     /* This is Windows memory management related - we don't need this */
1468     return DD_OK;
1469 }
1470
1471 static HRESULT WINAPI ddraw_surface3_PageLock(IDirectDrawSurface3 *iface, DWORD flags)
1472 {
1473     TRACE("iface %p, flags %#x.\n", iface, flags);
1474
1475     return ddraw_surface7_PageLock((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1476 }
1477
1478 /*****************************************************************************
1479  * IDirectDrawSurface7::PageUnlock
1480  *
1481  * Allows a sysmem surface to be paged out
1482  *
1483  * Params:
1484  *  Flags: Not used, must be 0(unchecked)
1485  *
1486  * Returns:
1487  *  DD_OK, because it's a stub
1488  *
1489  *****************************************************************************/
1490 static HRESULT WINAPI ddraw_surface7_PageUnlock(IDirectDrawSurface7 *iface, DWORD Flags)
1491 {
1492     TRACE("iface %p, flags %#x.\n", iface, Flags);
1493
1494     return DD_OK;
1495 }
1496
1497 static HRESULT WINAPI ddraw_surface3_PageUnlock(IDirectDrawSurface3 *iface, DWORD flags)
1498 {
1499     TRACE("iface %p, flags %#x.\n", iface, flags);
1500
1501     return ddraw_surface7_PageUnlock((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1502 }
1503
1504 /*****************************************************************************
1505  * IDirectDrawSurface7::BltBatch
1506  *
1507  * An unimplemented function
1508  *
1509  * Params:
1510  *  ?
1511  *
1512  * Returns:
1513  *  DDERR_UNSUPPORTED
1514  *
1515  *****************************************************************************/
1516 static HRESULT WINAPI ddraw_surface7_BltBatch(IDirectDrawSurface7 *iface, DDBLTBATCH *Batch, DWORD Count, DWORD Flags)
1517 {
1518     TRACE("iface %p, batch %p, count %u, flags %#x.\n", iface, Batch, Count, Flags);
1519
1520     /* MSDN: "not currently implemented" */
1521     return DDERR_UNSUPPORTED;
1522 }
1523
1524 static HRESULT WINAPI ddraw_surface3_BltBatch(IDirectDrawSurface3 *iface, DDBLTBATCH *batch, DWORD count, DWORD flags)
1525 {
1526     TRACE("iface %p, batch %p, count %u, flags %#x.\n", iface, batch, count, flags);
1527
1528     return ddraw_surface7_BltBatch((IDirectDrawSurface7 *)surface_from_surface3(iface), batch, count, flags);
1529 }
1530
1531 /*****************************************************************************
1532  * IDirectDrawSurface7::EnumAttachedSurfaces
1533  *
1534  * Enumerates all surfaces attached to this surface
1535  *
1536  * Params:
1537  *  context: Pointer to pass unmodified to the callback
1538  *  cb: Callback function to call for each surface
1539  *
1540  * Returns:
1541  *  DD_OK on success
1542  *  DDERR_INVALIDPARAMS if cb is NULL
1543  *
1544  *****************************************************************************/
1545 static HRESULT WINAPI ddraw_surface7_EnumAttachedSurfaces(IDirectDrawSurface7 *iface,
1546         void *context, LPDDENUMSURFACESCALLBACK7 cb)
1547 {
1548     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1549     IDirectDrawSurfaceImpl *surf;
1550     DDSURFACEDESC2 desc;
1551     int i;
1552
1553     /* Attached surfaces aren't handled in WineD3D */
1554     TRACE("iface %p, context %p, callback %p.\n", iface, context, cb);
1555
1556     if(!cb)
1557         return DDERR_INVALIDPARAMS;
1558
1559     EnterCriticalSection(&ddraw_cs);
1560     for(i = 0; i < MAX_COMPLEX_ATTACHED; i++)
1561     {
1562         surf = This->complex_array[i];
1563         if(!surf) break;
1564
1565         ddraw_surface7_AddRef((IDirectDrawSurface7 *)surf);
1566         desc = surf->surface_desc;
1567         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1568         if (cb((IDirectDrawSurface7 *)surf, &desc, context) == DDENUMRET_CANCEL)
1569         {
1570             LeaveCriticalSection(&ddraw_cs);
1571             return DD_OK;
1572         }
1573     }
1574
1575     for (surf = This->next_attached; surf != NULL; surf = surf->next_attached)
1576     {
1577         ddraw_surface7_AddRef((IDirectDrawSurface7 *)surf);
1578         desc = surf->surface_desc;
1579         /* check: != DDENUMRET_OK or == DDENUMRET_CANCEL? */
1580         if (cb((IDirectDrawSurface7 *)surf, &desc, context) == DDENUMRET_CANCEL)
1581         {
1582             LeaveCriticalSection(&ddraw_cs);
1583             return DD_OK;
1584         }
1585     }
1586
1587     TRACE(" end of enumeration.\n");
1588
1589     LeaveCriticalSection(&ddraw_cs);
1590     return DD_OK;
1591 }
1592
1593 struct callback_info
1594 {
1595     LPDDENUMSURFACESCALLBACK callback;
1596     void *context;
1597 };
1598
1599 static HRESULT CALLBACK EnumCallback(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *surface_desc, void *context)
1600 {
1601     const struct callback_info *info = context;
1602
1603     return info->callback((IDirectDrawSurface *)&((IDirectDrawSurfaceImpl *)surface)->IDirectDrawSurface3_vtbl,
1604             (DDSURFACEDESC *)surface_desc, info->context);
1605 }
1606
1607 static HRESULT WINAPI ddraw_surface3_EnumAttachedSurfaces(IDirectDrawSurface3 *iface,
1608         void *context, LPDDENUMSURFACESCALLBACK callback)
1609 {
1610     struct callback_info info;
1611
1612     TRACE("iface %p, context %p, callback %p.\n", iface, context, callback);
1613
1614     info.callback = callback;
1615     info.context  = context;
1616
1617     return ddraw_surface7_EnumAttachedSurfaces((IDirectDrawSurface7 *)surface_from_surface3(iface),
1618             &info, EnumCallback);
1619 }
1620
1621 /*****************************************************************************
1622  * IDirectDrawSurface7::EnumOverlayZOrders
1623  *
1624  * "Enumerates the overlay surfaces on the specified destination"
1625  *
1626  * Params:
1627  *  Flags: DDENUMOVERLAYZ_BACKTOFRONT  or DDENUMOVERLAYZ_FRONTTOBACK
1628  *  context: context to pass back to the callback
1629  *  cb: callback function to call for each enumerated surface
1630  *
1631  * Returns:
1632  *  DD_OK, because it's a stub
1633  *
1634  *****************************************************************************/
1635 static HRESULT WINAPI ddraw_surface7_EnumOverlayZOrders(IDirectDrawSurface7 *iface,
1636         DWORD Flags, void *context, LPDDENUMSURFACESCALLBACK7 cb)
1637 {
1638     FIXME("iface %p, flags %#x, context %p, callback %p stub!\n", iface, Flags, context, cb);
1639
1640     return DD_OK;
1641 }
1642
1643 static HRESULT WINAPI ddraw_surface3_EnumOverlayZOrders(IDirectDrawSurface3 *iface,
1644         DWORD flags, void *context, LPDDENUMSURFACESCALLBACK callback)
1645 {
1646     struct callback_info info;
1647
1648     TRACE("iface %p, flags %#x, context %p, callback %p.\n", iface, flags, context, callback);
1649
1650     info.callback = callback;
1651     info.context  = context;
1652
1653     return ddraw_surface7_EnumOverlayZOrders((IDirectDrawSurface7 *)surface_from_surface3(iface),
1654             flags, &info, EnumCallback);
1655 }
1656
1657 /*****************************************************************************
1658  * IDirectDrawSurface7::GetBltStatus
1659  *
1660  * Returns the blitting status
1661  *
1662  * Params:
1663  *  Flags: DDGBS_CANBLT or DDGBS_ISBLTDONE
1664  *
1665  * Returns:
1666  *  See IWineD3DSurface::Blt
1667  *
1668  *****************************************************************************/
1669 static HRESULT WINAPI ddraw_surface7_GetBltStatus(IDirectDrawSurface7 *iface, DWORD Flags)
1670 {
1671     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1672     HRESULT hr;
1673
1674     TRACE("iface %p, flags %#x.\n", iface, Flags);
1675
1676     EnterCriticalSection(&ddraw_cs);
1677     hr = IWineD3DSurface_GetBltStatus(This->WineD3DSurface, Flags);
1678     LeaveCriticalSection(&ddraw_cs);
1679     switch(hr)
1680     {
1681         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1682         default:                            return hr;
1683     }
1684 }
1685
1686 static HRESULT WINAPI ddraw_surface3_GetBltStatus(IDirectDrawSurface3 *iface, DWORD flags)
1687 {
1688     TRACE("iface %p, flags %#x.\n", iface, flags);
1689
1690     return ddraw_surface7_GetBltStatus((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1691 }
1692
1693 /*****************************************************************************
1694  * IDirectDrawSurface7::GetColorKey
1695  *
1696  * Returns the color key assigned to the surface
1697  *
1698  * Params:
1699  *  Flags: Some flags
1700  *  CKey: Address to store the key to
1701  *
1702  * Returns:
1703  *  DD_OK on success
1704  *  DDERR_INVALIDPARAMS if CKey is NULL
1705  *
1706  *****************************************************************************/
1707 static HRESULT WINAPI ddraw_surface7_GetColorKey(IDirectDrawSurface7 *iface, DWORD Flags, DDCOLORKEY *CKey)
1708 {
1709     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1710
1711     TRACE("iface %p, flags %#x, color_key %p.\n", iface, Flags, CKey);
1712
1713     if(!CKey)
1714         return DDERR_INVALIDPARAMS;
1715
1716     EnterCriticalSection(&ddraw_cs);
1717
1718     switch (Flags)
1719     {
1720     case DDCKEY_DESTBLT:
1721         if (!(This->surface_desc.dwFlags & DDSD_CKDESTBLT))
1722         {
1723             LeaveCriticalSection(&ddraw_cs);
1724             return DDERR_NOCOLORKEY;
1725         }
1726         *CKey = This->surface_desc.ddckCKDestBlt;
1727         break;
1728
1729     case DDCKEY_DESTOVERLAY:
1730         if (!(This->surface_desc.dwFlags & DDSD_CKDESTOVERLAY))
1731             {
1732             LeaveCriticalSection(&ddraw_cs);
1733             return DDERR_NOCOLORKEY;
1734             }
1735         *CKey = This->surface_desc.u3.ddckCKDestOverlay;
1736         break;
1737
1738     case DDCKEY_SRCBLT:
1739         if (!(This->surface_desc.dwFlags & DDSD_CKSRCBLT))
1740         {
1741             LeaveCriticalSection(&ddraw_cs);
1742             return DDERR_NOCOLORKEY;
1743         }
1744         *CKey = This->surface_desc.ddckCKSrcBlt;
1745         break;
1746
1747     case DDCKEY_SRCOVERLAY:
1748         if (!(This->surface_desc.dwFlags & DDSD_CKSRCOVERLAY))
1749         {
1750             LeaveCriticalSection(&ddraw_cs);
1751             return DDERR_NOCOLORKEY;
1752         }
1753         *CKey = This->surface_desc.ddckCKSrcOverlay;
1754         break;
1755
1756     default:
1757         LeaveCriticalSection(&ddraw_cs);
1758         return DDERR_INVALIDPARAMS;
1759     }
1760
1761     LeaveCriticalSection(&ddraw_cs);
1762     return DD_OK;
1763 }
1764
1765 static HRESULT WINAPI ddraw_surface3_GetColorKey(IDirectDrawSurface3 *iface, DWORD flags, DDCOLORKEY *color_key)
1766 {
1767     TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, color_key);
1768
1769     return ddraw_surface7_GetColorKey((IDirectDrawSurface7 *)surface_from_surface3(iface), flags, color_key);
1770 }
1771
1772 /*****************************************************************************
1773  * IDirectDrawSurface7::GetFlipStatus
1774  *
1775  * Returns the flipping status of the surface
1776  *
1777  * Params:
1778  *  Flags: DDGFS_CANFLIP of DDGFS_ISFLIPDONE
1779  *
1780  * Returns:
1781  *  See IWineD3DSurface::GetFlipStatus
1782  *
1783  *****************************************************************************/
1784 static HRESULT WINAPI ddraw_surface7_GetFlipStatus(IDirectDrawSurface7 *iface, DWORD Flags)
1785 {
1786     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1787     HRESULT hr;
1788
1789     TRACE("iface %p, flags %#x.\n", iface, Flags);
1790
1791     EnterCriticalSection(&ddraw_cs);
1792     hr = IWineD3DSurface_GetFlipStatus(This->WineD3DSurface, Flags);
1793     LeaveCriticalSection(&ddraw_cs);
1794     switch(hr)
1795     {
1796         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
1797         default:                            return hr;
1798     }
1799 }
1800
1801 static HRESULT WINAPI ddraw_surface3_GetFlipStatus(IDirectDrawSurface3 *iface, DWORD flags)
1802 {
1803     TRACE("iface %p, flags %#x.\n", iface, flags);
1804
1805     return ddraw_surface7_GetFlipStatus((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
1806 }
1807
1808 /*****************************************************************************
1809  * IDirectDrawSurface7::GetOverlayPosition
1810  *
1811  * Returns the display coordinates of a visible and active overlay surface
1812  *
1813  * Params:
1814  *  X
1815  *  Y
1816  *
1817  * Returns:
1818  *  DDERR_NOTAOVERLAYSURFACE, because it's a stub
1819  *****************************************************************************/
1820 static HRESULT WINAPI ddraw_surface7_GetOverlayPosition(IDirectDrawSurface7 *iface, LONG *X, LONG *Y)
1821 {
1822     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1823     HRESULT hr;
1824
1825     TRACE("iface %p, x %p, y %p.\n", iface, X, Y);
1826
1827     EnterCriticalSection(&ddraw_cs);
1828     hr = IWineD3DSurface_GetOverlayPosition(This->WineD3DSurface,
1829                                             X,
1830                                             Y);
1831     LeaveCriticalSection(&ddraw_cs);
1832     return hr;
1833 }
1834
1835 static HRESULT WINAPI ddraw_surface3_GetOverlayPosition(IDirectDrawSurface3 *iface, LONG *x, LONG *y)
1836 {
1837     TRACE("iface %p, x %p, y %p.\n", iface, x, y);
1838
1839     return ddraw_surface7_GetOverlayPosition((IDirectDrawSurface7 *)surface_from_surface3(iface), x, y);
1840 }
1841
1842 /*****************************************************************************
1843  * IDirectDrawSurface7::GetPixelFormat
1844  *
1845  * Returns the pixel format of the Surface
1846  *
1847  * Params:
1848  *  PixelFormat: Pointer to a DDPIXELFORMAT structure to which the pixel
1849  *               format should be written
1850  *
1851  * Returns:
1852  *  DD_OK on success
1853  *  DDERR_INVALIDPARAMS if PixelFormat is NULL
1854  *
1855  *****************************************************************************/
1856 static HRESULT WINAPI ddraw_surface7_GetPixelFormat(IDirectDrawSurface7 *iface, DDPIXELFORMAT *PixelFormat)
1857 {
1858     /* What is DDERR_INVALIDSURFACETYPE for here? */
1859     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1860
1861     TRACE("iface %p, pixel_format %p.\n", iface, PixelFormat);
1862
1863     if(!PixelFormat)
1864         return DDERR_INVALIDPARAMS;
1865
1866     EnterCriticalSection(&ddraw_cs);
1867     DD_STRUCT_COPY_BYSIZE(PixelFormat,&This->surface_desc.u4.ddpfPixelFormat);
1868     LeaveCriticalSection(&ddraw_cs);
1869
1870     return DD_OK;
1871 }
1872
1873 static HRESULT WINAPI ddraw_surface3_GetPixelFormat(IDirectDrawSurface3 *iface, DDPIXELFORMAT *pixel_format)
1874 {
1875     TRACE("iface %p, pixel_format %p.\n", iface, pixel_format);
1876
1877     return ddraw_surface7_GetPixelFormat((IDirectDrawSurface7 *)surface_from_surface3(iface), pixel_format);
1878 }
1879
1880 /*****************************************************************************
1881  * IDirectDrawSurface7::GetSurfaceDesc
1882  *
1883  * Returns the description of this surface
1884  *
1885  * Params:
1886  *  DDSD: Address of a DDSURFACEDESC2 structure that is to be filled with the
1887  *        surface desc
1888  *
1889  * Returns:
1890  *  DD_OK on success
1891  *  DDERR_INVALIDPARAMS if DDSD is NULL
1892  *
1893  *****************************************************************************/
1894 static HRESULT WINAPI ddraw_surface7_GetSurfaceDesc(IDirectDrawSurface7 *iface, DDSURFACEDESC2 *DDSD)
1895 {
1896     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
1897
1898     TRACE("iface %p, surface_desc %p.\n", iface, DDSD);
1899
1900     if(!DDSD)
1901         return DDERR_INVALIDPARAMS;
1902
1903     if (DDSD->dwSize != sizeof(DDSURFACEDESC2))
1904     {
1905         WARN("Incorrect struct size %d, returning DDERR_INVALIDPARAMS\n",DDSD->dwSize);
1906         return DDERR_INVALIDPARAMS;
1907     }
1908
1909     EnterCriticalSection(&ddraw_cs);
1910     DD_STRUCT_COPY_BYSIZE(DDSD,&This->surface_desc);
1911     TRACE("Returning surface desc:\n");
1912     if (TRACE_ON(ddraw)) DDRAW_dump_surface_desc(DDSD);
1913
1914     LeaveCriticalSection(&ddraw_cs);
1915     return DD_OK;
1916 }
1917
1918 static HRESULT WINAPI ddraw_surface3_GetSurfaceDesc(IDirectDrawSurface3 *iface, DDSURFACEDESC *surface_desc)
1919 {
1920     IDirectDrawSurfaceImpl *surface = surface_from_surface3(iface);
1921
1922     TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1923
1924     if (!surface_desc) return DDERR_INVALIDPARAMS;
1925
1926     if (surface_desc->dwSize != sizeof(DDSURFACEDESC))
1927     {
1928         WARN("Incorrect structure size %u, returning DDERR_INVALIDPARAMS.\n", surface_desc->dwSize);
1929         return DDERR_INVALIDPARAMS;
1930     }
1931
1932     EnterCriticalSection(&ddraw_cs);
1933     DD_STRUCT_COPY_BYSIZE(surface_desc, (DDSURFACEDESC *)&surface->surface_desc);
1934     TRACE("Returning surface desc:\n");
1935     if (TRACE_ON(ddraw))
1936     {
1937         /* DDRAW_dump_surface_desc handles the smaller size */
1938         DDRAW_dump_surface_desc((DDSURFACEDESC2 *)surface_desc);
1939     }
1940
1941     LeaveCriticalSection(&ddraw_cs);
1942     return DD_OK;
1943 }
1944
1945 /*****************************************************************************
1946  * IDirectDrawSurface7::Initialize
1947  *
1948  * Initializes the surface. This is a no-op in Wine
1949  *
1950  * Params:
1951  *  DD: Pointer to an DirectDraw interface
1952  *  DDSD: Surface description for initialization
1953  *
1954  * Returns:
1955  *  DDERR_ALREADYINITIALIZED
1956  *
1957  *****************************************************************************/
1958 static HRESULT WINAPI ddraw_surface7_Initialize(IDirectDrawSurface7 *iface,
1959         IDirectDraw *ddraw, DDSURFACEDESC2 *surface_desc)
1960 {
1961     TRACE("iface %p, ddraw %p, surface_desc %p.\n", iface, ddraw, surface_desc);
1962
1963     return DDERR_ALREADYINITIALIZED;
1964 }
1965
1966 static HRESULT WINAPI ddraw_surface3_Initialize(IDirectDrawSurface3 *iface,
1967         IDirectDraw *ddraw, DDSURFACEDESC *surface_desc)
1968 {
1969     TRACE("iface %p, ddraw %p, surface_desc %p.\n", iface, ddraw, surface_desc);
1970
1971     return ddraw_surface7_Initialize((IDirectDrawSurface7 *)surface_from_surface3(iface),
1972             ddraw, (DDSURFACEDESC2 *)surface_desc);
1973 }
1974
1975 /*****************************************************************************
1976  * IDirect3DTexture1::Initialize
1977  *
1978  * The sdk says it's not implemented
1979  *
1980  * Params:
1981  *  ?
1982  *
1983  * Returns
1984  *  DDERR_UNSUPPORTED
1985  *
1986  *****************************************************************************/
1987 static HRESULT WINAPI d3d_texture1_Initialize(IDirect3DTexture *iface,
1988         IDirect3DDevice *device, IDirectDrawSurface *surface)
1989 {
1990     TRACE("iface %p, device %p, surface %p.\n", iface, device, surface);
1991
1992     return DDERR_UNSUPPORTED; /* Unchecked */
1993 }
1994
1995 /*****************************************************************************
1996  * IDirectDrawSurface7::IsLost
1997  *
1998  * Checks if the surface is lost
1999  *
2000  * Returns:
2001  *  DD_OK, if the surface is usable
2002  *  DDERR_ISLOST if the surface is lost
2003  *  See IWineD3DSurface::IsLost for more details
2004  *
2005  *****************************************************************************/
2006 static HRESULT WINAPI ddraw_surface7_IsLost(IDirectDrawSurface7 *iface)
2007 {
2008     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2009     HRESULT hr;
2010
2011     TRACE("iface %p.\n", iface);
2012
2013     EnterCriticalSection(&ddraw_cs);
2014     /* We lose the surface if the implementation was changed */
2015     if(This->ImplType != This->ddraw->ImplType)
2016     {
2017         /* But this shouldn't happen. When we change the implementation,
2018          * all surfaces are re-created automatically, and their content
2019          * is copied
2020          */
2021         ERR(" (%p) Implementation was changed from %d to %d\n", This, This->ImplType, This->ddraw->ImplType);
2022         LeaveCriticalSection(&ddraw_cs);
2023         return DDERR_SURFACELOST;
2024     }
2025
2026     hr = IWineD3DSurface_IsLost(This->WineD3DSurface);
2027     LeaveCriticalSection(&ddraw_cs);
2028     switch(hr)
2029     {
2030         /* D3D8 and 9 loose full devices, thus there's only a DEVICELOST error.
2031          * WineD3D uses the same error for surfaces
2032          */
2033         case WINED3DERR_DEVICELOST:         return DDERR_SURFACELOST;
2034         default:                            return hr;
2035     }
2036 }
2037
2038 static HRESULT WINAPI ddraw_surface3_IsLost(IDirectDrawSurface3 *iface)
2039 {
2040     TRACE("iface %p.\n", iface);
2041
2042     return ddraw_surface7_IsLost((IDirectDrawSurface7 *)surface_from_surface3(iface));
2043 }
2044
2045 /*****************************************************************************
2046  * IDirectDrawSurface7::Restore
2047  *
2048  * Restores a lost surface. This makes the surface usable again, but
2049  * doesn't reload its old contents
2050  *
2051  * Returns:
2052  *  DD_OK on success
2053  *  See IWineD3DSurface::Restore for more details
2054  *
2055  *****************************************************************************/
2056 static HRESULT WINAPI ddraw_surface7_Restore(IDirectDrawSurface7 *iface)
2057 {
2058     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2059     HRESULT hr;
2060
2061     TRACE("iface %p.\n", iface);
2062
2063     EnterCriticalSection(&ddraw_cs);
2064     if(This->ImplType != This->ddraw->ImplType)
2065     {
2066         /* Call the recreation callback. Make sure to AddRef first */
2067         IDirectDrawSurface_AddRef(iface);
2068         ddraw_recreate_surfaces_cb(iface, &This->surface_desc, NULL /* Not needed */);
2069     }
2070     hr = IWineD3DSurface_Restore(This->WineD3DSurface);
2071     LeaveCriticalSection(&ddraw_cs);
2072     return hr;
2073 }
2074
2075 static HRESULT WINAPI ddraw_surface3_Restore(IDirectDrawSurface3 *iface)
2076 {
2077     TRACE("iface %p.\n", iface);
2078
2079     return ddraw_surface7_Restore((IDirectDrawSurface7 *)surface_from_surface3(iface));
2080 }
2081
2082 /*****************************************************************************
2083  * IDirectDrawSurface7::SetOverlayPosition
2084  *
2085  * Changes the display coordinates of an overlay surface
2086  *
2087  * Params:
2088  *  X:
2089  *  Y:
2090  *
2091  * Returns:
2092  *   DDERR_NOTAOVERLAYSURFACE, because we don't support overlays right now
2093  *****************************************************************************/
2094 static HRESULT WINAPI ddraw_surface7_SetOverlayPosition(IDirectDrawSurface7 *iface, LONG X, LONG Y)
2095 {
2096     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2097     HRESULT hr;
2098
2099     TRACE("iface %p, x %d, y %d.\n", iface, X, Y);
2100
2101     EnterCriticalSection(&ddraw_cs);
2102     hr = IWineD3DSurface_SetOverlayPosition(This->WineD3DSurface,
2103                                             X,
2104                                             Y);
2105     LeaveCriticalSection(&ddraw_cs);
2106     return hr;
2107 }
2108
2109 static HRESULT WINAPI ddraw_surface3_SetOverlayPosition(IDirectDrawSurface3 *iface, LONG x, LONG y)
2110 {
2111     TRACE("iface %p, x %d, y %d.\n", iface, x, y);
2112
2113     return ddraw_surface7_SetOverlayPosition((IDirectDrawSurface7 *)surface_from_surface3(iface), x, y);
2114 }
2115
2116 /*****************************************************************************
2117  * IDirectDrawSurface7::UpdateOverlay
2118  *
2119  * Modifies the attributes of an overlay surface.
2120  *
2121  * Params:
2122  *  SrcRect: The section of the source being used for the overlay
2123  *  DstSurface: Address of the surface that is overlaid
2124  *  DstRect: Place of the overlay
2125  *  Flags: some DDOVER_* flags
2126  *
2127  * Returns:
2128  *  DDERR_UNSUPPORTED, because we don't support overlays
2129  *
2130  *****************************************************************************/
2131 static HRESULT WINAPI ddraw_surface7_UpdateOverlay(IDirectDrawSurface7 *iface, RECT *SrcRect,
2132         IDirectDrawSurface7 *DstSurface, RECT *DstRect, DWORD Flags, DDOVERLAYFX *FX)
2133 {
2134     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2135     IDirectDrawSurfaceImpl *Dst = (IDirectDrawSurfaceImpl *)DstSurface;
2136     HRESULT hr;
2137
2138     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2139             iface, wine_dbgstr_rect(SrcRect), DstSurface, wine_dbgstr_rect(DstRect), Flags, FX);
2140
2141     EnterCriticalSection(&ddraw_cs);
2142     hr = IWineD3DSurface_UpdateOverlay(This->WineD3DSurface,
2143                                        SrcRect,
2144                                        Dst ? Dst->WineD3DSurface : NULL,
2145                                        DstRect,
2146                                        Flags,
2147                                        (WINEDDOVERLAYFX *) FX);
2148     LeaveCriticalSection(&ddraw_cs);
2149     switch(hr) {
2150         case WINED3DERR_INVALIDCALL:        return DDERR_INVALIDPARAMS;
2151         case WINEDDERR_NOTAOVERLAYSURFACE:  return DDERR_NOTAOVERLAYSURFACE;
2152         case WINEDDERR_OVERLAYNOTVISIBLE:   return DDERR_OVERLAYNOTVISIBLE;
2153         default:
2154             return hr;
2155     }
2156 }
2157
2158 static HRESULT WINAPI ddraw_surface3_UpdateOverlay(IDirectDrawSurface3 *iface, RECT *src_rect,
2159         IDirectDrawSurface3 *dst_surface, RECT *dst_rect, DWORD flags, DDOVERLAYFX *fx)
2160 {
2161     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2162             iface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
2163
2164     return ddraw_surface7_UpdateOverlay((IDirectDrawSurface7 *)surface_from_surface3(iface), src_rect,
2165             dst_surface ? (IDirectDrawSurface7 *)surface_from_surface3(dst_surface) : NULL, dst_rect, flags, fx);
2166 }
2167
2168 /*****************************************************************************
2169  * IDirectDrawSurface7::UpdateOverlayDisplay
2170  *
2171  * The DX7 sdk says that it's not implemented
2172  *
2173  * Params:
2174  *  Flags: ?
2175  *
2176  * Returns: DDERR_UNSUPPORTED, because we don't support overlays
2177  *
2178  *****************************************************************************/
2179 static HRESULT WINAPI ddraw_surface7_UpdateOverlayDisplay(IDirectDrawSurface7 *iface, DWORD Flags)
2180 {
2181     TRACE("iface %p, flags %#x.\n", iface, Flags);
2182
2183     return DDERR_UNSUPPORTED;
2184 }
2185
2186 static HRESULT WINAPI ddraw_surface3_UpdateOverlayDisplay(IDirectDrawSurface3 *iface, DWORD flags)
2187 {
2188     TRACE("iface %p, flags %#x.\n", iface, flags);
2189
2190     return ddraw_surface7_UpdateOverlayDisplay((IDirectDrawSurface7 *)surface_from_surface3(iface), flags);
2191 }
2192
2193 /*****************************************************************************
2194  * IDirectDrawSurface7::UpdateOverlayZOrder
2195  *
2196  * Sets an overlay's Z order
2197  *
2198  * Params:
2199  *  Flags: DDOVERZ_* flags
2200  *  DDSRef: Defines the relative position in the overlay chain
2201  *
2202  * Returns:
2203  *  DDERR_NOTOVERLAYSURFACE, because we don't support overlays
2204  *
2205  *****************************************************************************/
2206 static HRESULT WINAPI ddraw_surface7_UpdateOverlayZOrder(IDirectDrawSurface7 *iface,
2207         DWORD Flags, IDirectDrawSurface7 *DDSRef)
2208 {
2209     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2210     IDirectDrawSurfaceImpl *Ref = (IDirectDrawSurfaceImpl *)DDSRef;
2211     HRESULT hr;
2212
2213     TRACE("iface %p, flags %#x, reference %p.\n", iface, Flags, DDSRef);
2214
2215     EnterCriticalSection(&ddraw_cs);
2216     hr =  IWineD3DSurface_UpdateOverlayZOrder(This->WineD3DSurface,
2217                                               Flags,
2218                                               Ref ? Ref->WineD3DSurface : NULL);
2219     LeaveCriticalSection(&ddraw_cs);
2220     return hr;
2221 }
2222
2223 static HRESULT WINAPI ddraw_surface3_UpdateOverlayZOrder(IDirectDrawSurface3 *iface,
2224         DWORD flags, IDirectDrawSurface3 *reference)
2225 {
2226     TRACE("iface %p, flags %#x, reference %p.\n", iface, flags, reference);
2227
2228     return ddraw_surface7_UpdateOverlayZOrder((IDirectDrawSurface7 *)surface_from_surface3(iface), flags,
2229             reference ? (IDirectDrawSurface7 *)surface_from_surface3(reference) : NULL);
2230 }
2231
2232 /*****************************************************************************
2233  * IDirectDrawSurface7::GetDDInterface
2234  *
2235  * Returns the IDirectDraw7 interface pointer of the DirectDraw object this
2236  * surface belongs to
2237  *
2238  * Params:
2239  *  DD: Address to write the interface pointer to
2240  *
2241  * Returns:
2242  *  DD_OK on success
2243  *  DDERR_INVALIDPARAMS if DD is NULL
2244  *
2245  *****************************************************************************/
2246 static HRESULT WINAPI ddraw_surface7_GetDDInterface(IDirectDrawSurface7 *iface, void **DD)
2247 {
2248     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2249
2250     TRACE("iface %p, ddraw %p.\n", iface, DD);
2251
2252     if(!DD)
2253         return DDERR_INVALIDPARAMS;
2254
2255     switch(This->version)
2256     {
2257         case 7:
2258             *DD = &This->ddraw->IDirectDraw7_iface;
2259             break;
2260
2261         case 4:
2262             *DD = &This->ddraw->IDirectDraw4_iface;
2263             break;
2264
2265         case 2:
2266             *DD = &This->ddraw->IDirectDraw2_iface;
2267             break;
2268
2269         case 1:
2270             *DD = &This->ddraw->IDirectDraw_iface;
2271             break;
2272
2273     }
2274     IUnknown_AddRef((IUnknown *)*DD);
2275
2276     return DD_OK;
2277 }
2278
2279 static HRESULT WINAPI ddraw_surface3_GetDDInterface(IDirectDrawSurface3 *iface, void **ddraw)
2280 {
2281     TRACE("iface %p, ddraw %p.\n", iface, ddraw);
2282
2283     return ddraw_surface7_GetDDInterface((IDirectDrawSurface7 *)surface_from_surface3(iface), ddraw);
2284 }
2285
2286 /* This seems also windows implementation specific - I don't think WineD3D needs this */
2287 static HRESULT WINAPI ddraw_surface7_ChangeUniquenessValue(IDirectDrawSurface7 *iface)
2288 {
2289     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2290     volatile IDirectDrawSurfaceImpl* vThis = This;
2291
2292     TRACE("iface %p.\n", iface);
2293
2294     EnterCriticalSection(&ddraw_cs);
2295     /* A uniqueness value of 0 is apparently special.
2296      * This needs to be checked.
2297      * TODO: Write tests for this code and check if the volatile, interlocked stuff is really needed
2298      */
2299     while (1) {
2300         DWORD old_uniqueness_value = vThis->uniqueness_value;
2301         DWORD new_uniqueness_value = old_uniqueness_value+1;
2302
2303         if (old_uniqueness_value == 0) break;
2304         if (new_uniqueness_value == 0) new_uniqueness_value = 1;
2305
2306         if (InterlockedCompareExchange((LONG*)&vThis->uniqueness_value,
2307                                       old_uniqueness_value,
2308                                       new_uniqueness_value)
2309             == old_uniqueness_value)
2310             break;
2311     }
2312
2313     LeaveCriticalSection(&ddraw_cs);
2314     return DD_OK;
2315 }
2316
2317 static HRESULT WINAPI ddraw_surface7_GetUniquenessValue(IDirectDrawSurface7 *iface, DWORD *pValue)
2318 {
2319     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2320
2321     TRACE("iface %p, value %p.\n", iface, pValue);
2322
2323     EnterCriticalSection(&ddraw_cs);
2324     *pValue = This->uniqueness_value;
2325     LeaveCriticalSection(&ddraw_cs);
2326     return DD_OK;
2327 }
2328
2329 /*****************************************************************************
2330  * IDirectDrawSurface7::SetLOD
2331  *
2332  * Sets the level of detail of a texture
2333  *
2334  * Params:
2335  *  MaxLOD: LOD to set
2336  *
2337  * Returns:
2338  *  DD_OK on success
2339  *  DDERR_INVALIDOBJECT if the surface is invalid for this method
2340  *
2341  *****************************************************************************/
2342 static HRESULT WINAPI ddraw_surface7_SetLOD(IDirectDrawSurface7 *iface, DWORD MaxLOD)
2343 {
2344     IDirectDrawSurfaceImpl *This = (IDirectDrawSurfaceImpl *)iface;
2345     HRESULT hr;
2346
2347     TRACE("iface %p, lod %u.\n", iface, MaxLOD);
2348
2349     EnterCriticalSection(&ddraw_cs);
2350     if (!(This->surface_desc.ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE))
2351     {
2352         LeaveCriticalSection(&ddraw_cs);
2353         return DDERR_INVALIDOBJECT;
2354     }
2355
2356     if (!This->wined3d_texture)
2357     {
2358         ERR("(%p) The DirectDraw texture has no WineD3DTexture!\n", This);
2359         LeaveCriticalSection(&ddraw_cs);
2360         return DDERR_INVALIDOBJECT;
2361     }
2362
2363     hr = wined3d_texture_set_lod(This->wined3d_texture, 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 = wined3d_texture_get_lod(This->wined3d_texture);
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     struct wined3d_palette *wined3d_palette;
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, &wined3d_palette);
2730     if (FAILED(hr))
2731     {
2732         LeaveCriticalSection(&ddraw_cs);
2733         return hr;
2734     }
2735
2736     if (wined3d_palette)
2737     {
2738         *Pal = wined3d_palette_get_parent(wined3d_palette);
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         struct wined3d_palette *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)
3249             dst_pal = wined3d_palette_get_parent(wined3d_dst_pal);
3250
3251         hr = IWineD3DSurface_GetPalette(src_surface->WineD3DSurface, &wined3d_src_pal);
3252         if (FAILED(hr))
3253         {
3254             ERR("Failed to get source palette, hr %#x.\n", hr);
3255             LeaveCriticalSection(&ddraw_cs);
3256             return D3DERR_TEXTURE_LOAD_FAILED;
3257         }
3258         if (wined3d_src_pal)
3259             src_pal = wined3d_palette_get_parent(wined3d_src_pal);
3260
3261         if (src_pal)
3262         {
3263             PALETTEENTRY palent[256];
3264
3265             if (!dst_pal)
3266             {
3267                 LeaveCriticalSection(&ddraw_cs);
3268                 return DDERR_NOPALETTEATTACHED;
3269             }
3270             IDirectDrawPalette_GetEntries(src_pal, 0, 0, 256, palent);
3271             IDirectDrawPalette_SetEntries(dst_pal, 0, 0, 256, palent);
3272         }
3273
3274         /* Copy one surface on the other */
3275         dst_desc = (DDSURFACEDESC *)&(dst_surface->surface_desc);
3276         src_desc = (DDSURFACEDESC *)&(src_surface->surface_desc);
3277
3278         if ((src_desc->dwWidth != dst_desc->dwWidth) || (src_desc->dwHeight != dst_desc->dwHeight))
3279         {
3280             /* Should also check for same pixel format, u1.lPitch, ... */
3281             ERR("Error in surface sizes.\n");
3282             LeaveCriticalSection(&ddraw_cs);
3283             return D3DERR_TEXTURE_LOAD_FAILED;
3284         }
3285         else
3286         {
3287             WINED3DLOCKED_RECT src_rect, dst_rect;
3288
3289             /* Copy also the ColorKeying stuff */
3290             if (src_desc->dwFlags & DDSD_CKSRCBLT)
3291             {
3292                 dst_desc->dwFlags |= DDSD_CKSRCBLT;
3293                 dst_desc->ddckCKSrcBlt.dwColorSpaceLowValue = src_desc->ddckCKSrcBlt.dwColorSpaceLowValue;
3294                 dst_desc->ddckCKSrcBlt.dwColorSpaceHighValue = src_desc->ddckCKSrcBlt.dwColorSpaceHighValue;
3295             }
3296
3297             /* Copy the main memory texture into the surface that corresponds
3298              * to the OpenGL texture object. */
3299
3300             hr = IWineD3DSurface_Map(src_surface->WineD3DSurface, &src_rect, NULL, 0);
3301             if (FAILED(hr))
3302             {
3303                 ERR("Failed to lock source surface, hr %#x.\n", hr);
3304                 LeaveCriticalSection(&ddraw_cs);
3305                 return D3DERR_TEXTURE_LOAD_FAILED;
3306             }
3307
3308             hr = IWineD3DSurface_Map(dst_surface->WineD3DSurface, &dst_rect, NULL, 0);
3309             if (FAILED(hr))
3310             {
3311                 ERR("Failed to lock destination surface, hr %#x.\n", hr);
3312                 IWineD3DSurface_Unmap(src_surface->WineD3DSurface);
3313                 LeaveCriticalSection(&ddraw_cs);
3314                 return D3DERR_TEXTURE_LOAD_FAILED;
3315             }
3316
3317             if (dst_surface->surface_desc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
3318                 memcpy(dst_rect.pBits, src_rect.pBits, src_surface->surface_desc.u1.dwLinearSize);
3319             else
3320                 memcpy(dst_rect.pBits, src_rect.pBits, src_rect.Pitch * src_desc->dwHeight);
3321
3322             IWineD3DSurface_Unmap(src_surface->WineD3DSurface);
3323             IWineD3DSurface_Unmap(dst_surface->WineD3DSurface);
3324         }
3325
3326         if (src_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3327             src_surface = get_sub_mimaplevel(src_surface);
3328         else
3329             src_surface = NULL;
3330
3331         if (dst_surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
3332             dst_surface = get_sub_mimaplevel(dst_surface);
3333         else
3334             dst_surface = NULL;
3335
3336         if (!src_surface || !dst_surface)
3337         {
3338             if (src_surface != dst_surface)
3339                 ERR("Loading surface with different mipmap structure.\n");
3340             break;
3341         }
3342     }
3343
3344     LeaveCriticalSection(&ddraw_cs);
3345
3346     return hr;
3347 }
3348
3349 static HRESULT WINAPI d3d_texture1_Load(IDirect3DTexture *iface, IDirect3DTexture *src_texture)
3350 {
3351     TRACE("iface %p, src_texture %p.\n", iface, src_texture);
3352
3353     return d3d_texture2_Load((IDirect3DTexture2 *)&surface_from_texture1(iface)->IDirect3DTexture2_vtbl,
3354             src_texture ? (IDirect3DTexture2 *)&surface_from_texture1(src_texture)->IDirect3DTexture2_vtbl : NULL);
3355 }
3356
3357 /*****************************************************************************
3358  * The VTable
3359  *****************************************************************************/
3360
3361 static const struct IDirectDrawSurface7Vtbl ddraw_surface7_vtbl =
3362 {
3363     /* IUnknown */
3364     ddraw_surface7_QueryInterface,
3365     ddraw_surface7_AddRef,
3366     ddraw_surface7_Release,
3367     /* IDirectDrawSurface */
3368     ddraw_surface7_AddAttachedSurface,
3369     ddraw_surface7_AddOverlayDirtyRect,
3370     ddraw_surface7_Blt,
3371     ddraw_surface7_BltBatch,
3372     ddraw_surface7_BltFast,
3373     ddraw_surface7_DeleteAttachedSurface,
3374     ddraw_surface7_EnumAttachedSurfaces,
3375     ddraw_surface7_EnumOverlayZOrders,
3376     ddraw_surface7_Flip,
3377     ddraw_surface7_GetAttachedSurface,
3378     ddraw_surface7_GetBltStatus,
3379     ddraw_surface7_GetCaps,
3380     ddraw_surface7_GetClipper,
3381     ddraw_surface7_GetColorKey,
3382     ddraw_surface7_GetDC,
3383     ddraw_surface7_GetFlipStatus,
3384     ddraw_surface7_GetOverlayPosition,
3385     ddraw_surface7_GetPalette,
3386     ddraw_surface7_GetPixelFormat,
3387     ddraw_surface7_GetSurfaceDesc,
3388     ddraw_surface7_Initialize,
3389     ddraw_surface7_IsLost,
3390     ddraw_surface7_Lock,
3391     ddraw_surface7_ReleaseDC,
3392     ddraw_surface7_Restore,
3393     ddraw_surface7_SetClipper,
3394     ddraw_surface7_SetColorKey,
3395     ddraw_surface7_SetOverlayPosition,
3396     ddraw_surface7_SetPalette,
3397     ddraw_surface7_Unlock,
3398     ddraw_surface7_UpdateOverlay,
3399     ddraw_surface7_UpdateOverlayDisplay,
3400     ddraw_surface7_UpdateOverlayZOrder,
3401     /* IDirectDrawSurface2 */
3402     ddraw_surface7_GetDDInterface,
3403     ddraw_surface7_PageLock,
3404     ddraw_surface7_PageUnlock,
3405     /* IDirectDrawSurface3 */
3406     ddraw_surface7_SetSurfaceDesc,
3407     /* IDirectDrawSurface4 */
3408     ddraw_surface7_SetPrivateData,
3409     ddraw_surface7_GetPrivateData,
3410     ddraw_surface7_FreePrivateData,
3411     ddraw_surface7_GetUniquenessValue,
3412     ddraw_surface7_ChangeUniquenessValue,
3413     /* IDirectDrawSurface7 */
3414     ddraw_surface7_SetPriority,
3415     ddraw_surface7_GetPriority,
3416     ddraw_surface7_SetLOD,
3417     ddraw_surface7_GetLOD,
3418 };
3419
3420 static const struct IDirectDrawSurface3Vtbl ddraw_surface3_vtbl =
3421 {
3422     /* IUnknown */
3423     ddraw_surface3_QueryInterface,
3424     ddraw_surface3_AddRef,
3425     ddraw_surface3_Release,
3426     /* IDirectDrawSurface */
3427     ddraw_surface3_AddAttachedSurface,
3428     ddraw_surface3_AddOverlayDirtyRect,
3429     ddraw_surface3_Blt,
3430     ddraw_surface3_BltBatch,
3431     ddraw_surface3_BltFast,
3432     ddraw_surface3_DeleteAttachedSurface,
3433     ddraw_surface3_EnumAttachedSurfaces,
3434     ddraw_surface3_EnumOverlayZOrders,
3435     ddraw_surface3_Flip,
3436     ddraw_surface3_GetAttachedSurface,
3437     ddraw_surface3_GetBltStatus,
3438     ddraw_surface3_GetCaps,
3439     ddraw_surface3_GetClipper,
3440     ddraw_surface3_GetColorKey,
3441     ddraw_surface3_GetDC,
3442     ddraw_surface3_GetFlipStatus,
3443     ddraw_surface3_GetOverlayPosition,
3444     ddraw_surface3_GetPalette,
3445     ddraw_surface3_GetPixelFormat,
3446     ddraw_surface3_GetSurfaceDesc,
3447     ddraw_surface3_Initialize,
3448     ddraw_surface3_IsLost,
3449     ddraw_surface3_Lock,
3450     ddraw_surface3_ReleaseDC,
3451     ddraw_surface3_Restore,
3452     ddraw_surface3_SetClipper,
3453     ddraw_surface3_SetColorKey,
3454     ddraw_surface3_SetOverlayPosition,
3455     ddraw_surface3_SetPalette,
3456     ddraw_surface3_Unlock,
3457     ddraw_surface3_UpdateOverlay,
3458     ddraw_surface3_UpdateOverlayDisplay,
3459     ddraw_surface3_UpdateOverlayZOrder,
3460     /* IDirectDrawSurface2 */
3461     ddraw_surface3_GetDDInterface,
3462     ddraw_surface3_PageLock,
3463     ddraw_surface3_PageUnlock,
3464     /* IDirectDrawSurface3 */
3465     ddraw_surface3_SetSurfaceDesc,
3466 };
3467
3468 static const struct IDirectDrawGammaControlVtbl ddraw_gamma_control_vtbl =
3469 {
3470     ddraw_gamma_control_QueryInterface,
3471     ddraw_gamma_control_AddRef,
3472     ddraw_gamma_control_Release,
3473     ddraw_gamma_control_GetGammaRamp,
3474     ddraw_gamma_control_SetGammaRamp,
3475 };
3476
3477 static const struct IDirect3DTexture2Vtbl d3d_texture2_vtbl =
3478 {
3479     d3d_texture2_QueryInterface,
3480     d3d_texture2_AddRef,
3481     d3d_texture2_Release,
3482     d3d_texture2_GetHandle,
3483     d3d_texture2_PaletteChanged,
3484     d3d_texture2_Load,
3485 };
3486
3487 static const struct IDirect3DTextureVtbl d3d_texture1_vtbl =
3488 {
3489     d3d_texture1_QueryInterface,
3490     d3d_texture1_AddRef,
3491     d3d_texture1_Release,
3492     d3d_texture1_Initialize,
3493     d3d_texture1_GetHandle,
3494     d3d_texture1_PaletteChanged,
3495     d3d_texture1_Load,
3496     d3d_texture1_Unload,
3497 };
3498
3499 HRESULT ddraw_surface_init(IDirectDrawSurfaceImpl *surface, IDirectDrawImpl *ddraw,
3500         DDSURFACEDESC2 *desc, UINT mip_level, WINED3DSURFTYPE surface_type)
3501 {
3502     struct wined3d_resource_desc wined3d_desc;
3503     struct wined3d_resource *wined3d_resource;
3504     WINED3DPOOL pool = WINED3DPOOL_DEFAULT;
3505     enum wined3d_format_id format;
3506     DWORD usage = 0;
3507     HRESULT hr;
3508
3509     if (!(desc->ddsCaps.dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY))
3510             && !((desc->ddsCaps.dwCaps & DDSCAPS_TEXTURE)
3511             && (desc->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)))
3512     {
3513         /* Tests show surfaces without memory flags get these flags added
3514          * right after creation. */
3515         desc->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
3516     }
3517
3518     if (desc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
3519     {
3520         usage |= WINED3DUSAGE_RENDERTARGET;
3521         desc->ddsCaps.dwCaps |= DDSCAPS_VISIBLE;
3522     }
3523
3524     if ((desc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) && !(desc->ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
3525     {
3526         usage |= WINED3DUSAGE_RENDERTARGET;
3527     }
3528
3529     if (desc->ddsCaps.dwCaps & (DDSCAPS_OVERLAY))
3530     {
3531         usage |= WINED3DUSAGE_OVERLAY;
3532     }
3533
3534     if (ddraw->depthstencil || (desc->ddsCaps.dwCaps & DDSCAPS_ZBUFFER))
3535     {
3536         /* The depth stencil creation callback sets this flag. Set the
3537          * wined3d usage to let it know it's a depth/stencil surface. */
3538         usage |= WINED3DUSAGE_DEPTHSTENCIL;
3539     }
3540
3541     if (desc->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
3542     {
3543         pool = WINED3DPOOL_SYSTEMMEM;
3544     }
3545     else if (desc->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
3546     {
3547         pool = WINED3DPOOL_MANAGED;
3548         /* Managed textures have the system memory flag set. */
3549         desc->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
3550     }
3551     else if (desc->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
3552     {
3553         /* Videomemory adds localvidmem. This is mutually exclusive with
3554          * systemmemory and texturemanage. */
3555         desc->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM;
3556     }
3557
3558     format = PixelFormat_DD2WineD3D(&desc->u4.ddpfPixelFormat);
3559     if (format == WINED3DFMT_UNKNOWN)
3560     {
3561         WARN("Unsupported / unknown pixelformat.\n");
3562         return DDERR_INVALIDPIXELFORMAT;
3563     }
3564
3565     surface->lpVtbl = &ddraw_surface7_vtbl;
3566     surface->IDirectDrawSurface3_vtbl = &ddraw_surface3_vtbl;
3567     surface->IDirectDrawGammaControl_vtbl = &ddraw_gamma_control_vtbl;
3568     surface->IDirect3DTexture2_vtbl = &d3d_texture2_vtbl;
3569     surface->IDirect3DTexture_vtbl = &d3d_texture1_vtbl;
3570     surface->ref = 1;
3571     surface->version = 7;
3572     surface->ddraw = ddraw;
3573
3574     surface->surface_desc.dwSize = sizeof(DDSURFACEDESC2);
3575     surface->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
3576     DD_STRUCT_COPY_BYSIZE(&surface->surface_desc, desc);
3577
3578     surface->first_attached = surface;
3579     surface->ImplType = surface_type;
3580
3581     hr = IWineD3DDevice_CreateSurface(ddraw->wineD3DDevice, desc->dwWidth, desc->dwHeight, format,
3582             TRUE /* Lockable */, FALSE /* Discard */, mip_level, usage, pool,
3583             WINED3DMULTISAMPLE_NONE, 0 /* MultiSampleQuality */, surface_type, surface,
3584             &ddraw_null_wined3d_parent_ops, &surface->WineD3DSurface);
3585     if (FAILED(hr))
3586     {
3587         WARN("Failed to create wined3d surface, hr %#x.\n", hr);
3588         return hr;
3589     }
3590
3591     surface->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
3592     wined3d_resource = IWineD3DSurface_GetResource(surface->WineD3DSurface);
3593     wined3d_resource_get_desc(wined3d_resource, &wined3d_desc);
3594
3595     format = wined3d_desc.format;
3596     if (format == WINED3DFMT_UNKNOWN)
3597     {
3598         FIXME("IWineD3DSurface::GetDesc returned WINED3DFMT_UNKNOWN.\n");
3599     }
3600     PixelFormat_WineD3DtoDD(&surface->surface_desc.u4.ddpfPixelFormat, format);
3601
3602     /* Anno 1602 stores the pitch right after surface creation, so make sure
3603      * it's there. TODO: Test other fourcc formats. */
3604     if (format == WINED3DFMT_DXT1 || format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3
3605             || format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5)
3606     {
3607         surface->surface_desc.dwFlags |= DDSD_LINEARSIZE;
3608         if (format == WINED3DFMT_DXT1)
3609         {
3610             surface->surface_desc.u1.dwLinearSize = max(4, wined3d_desc.width) * max(4, wined3d_desc.height) / 2;
3611         }
3612         else
3613         {
3614             surface->surface_desc.u1.dwLinearSize = max(4, wined3d_desc.width) * max(4, wined3d_desc.height);
3615         }
3616     }
3617     else
3618     {
3619         surface->surface_desc.dwFlags |= DDSD_PITCH;
3620         surface->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch(surface->WineD3DSurface);
3621     }
3622
3623     if (desc->dwFlags & DDSD_CKDESTOVERLAY)
3624     {
3625         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3626                 DDCKEY_DESTOVERLAY, (WINEDDCOLORKEY *)&desc->u3.ddckCKDestOverlay);
3627     }
3628     if (desc->dwFlags & DDSD_CKDESTBLT)
3629     {
3630         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3631                 DDCKEY_DESTBLT, (WINEDDCOLORKEY *)&desc->ddckCKDestBlt);
3632     }
3633     if (desc->dwFlags & DDSD_CKSRCOVERLAY)
3634     {
3635         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3636                 DDCKEY_SRCOVERLAY, (WINEDDCOLORKEY *)&desc->ddckCKSrcOverlay);
3637     }
3638     if (desc->dwFlags & DDSD_CKSRCBLT)
3639     {
3640         IWineD3DSurface_SetColorKey(surface->WineD3DSurface,
3641                 DDCKEY_SRCBLT, (WINEDDCOLORKEY *)&desc->ddckCKSrcBlt);
3642     }
3643     if (desc->dwFlags & DDSD_LPSURFACE)
3644     {
3645         hr = IWineD3DSurface_SetMem(surface->WineD3DSurface, desc->lpSurface);
3646         if (FAILED(hr))
3647         {
3648             ERR("Failed to set surface memory, hr %#x.\n", hr);
3649             IWineD3DSurface_Release(surface->WineD3DSurface);
3650             return hr;
3651         }
3652     }
3653
3654     return DD_OK;
3655 }