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