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