wined3d: Use a swapchain for GDI surfaces.
[wine] / dlls / ddraw / ddraw.c
1 /*
2  * Copyright 1997-2000 Marcus Meissner
3  * Copyright 1998-2000 Lionel Ulmer
4  * Copyright 2000-2001 TransGaming Technologies Inc.
5  * Copyright 2006 Stefan Dösinger
6  * Copyright 2008 Denver Gingerich
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <assert.h>
27 #include <stdarg.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #define COBJMACROS
32 #define NONAMELESSUNION
33
34 #include "windef.h"
35 #include "winbase.h"
36 #include "winerror.h"
37 #include "wingdi.h"
38 #include "wine/exception.h"
39
40 #include "ddraw.h"
41 #include "d3d.h"
42
43 #include "ddraw_private.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
47
48 static BOOL IDirectDrawImpl_DDSD_Match(const DDSURFACEDESC2* requested, const DDSURFACEDESC2* provided);
49 static HRESULT WINAPI IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This, IDirectDrawSurfaceImpl *primary);
50 static HRESULT WINAPI IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This, DDSURFACEDESC2 *pDDSD, IDirectDrawSurfaceImpl **ppSurf, UINT level);
51 static HRESULT WINAPI IDirectDrawImpl_CreateGDISwapChain(IDirectDrawImpl *This, IDirectDrawSurfaceImpl *primary);
52
53 /* Device identifier. Don't relay it to WineD3D */
54 static const DDDEVICEIDENTIFIER2 deviceidentifier =
55 {
56     "display",
57     "DirectDraw HAL",
58     { { 0x00010001, 0x00010001 } },
59     0, 0, 0, 0,
60     /* a8373c10-7ac4-4deb-849a-009844d08b2d */
61     {0xa8373c10,0x7ac4,0x4deb, {0x84,0x9a,0x00,0x98,0x44,0xd0,0x8b,0x2d}},
62     0
63 };
64
65 /*****************************************************************************
66  * IUnknown Methods
67  *****************************************************************************/
68
69 /*****************************************************************************
70  * IDirectDraw7::QueryInterface
71  *
72  * Queries different interfaces of the DirectDraw object. It can return
73  * IDirectDraw interfaces in version 1, 2, 4 and 7, and IDirect3D interfaces
74  * in version 1, 2, 3 and 7. An IDirect3DDevice can be created with this
75  * method.
76  * The returned interface is AddRef()-ed before it's returned
77  *
78  * Used for version 1, 2, 4 and 7
79  *
80  * Params:
81  *  refiid: Interface ID asked for
82  *  obj: Used to return the interface pointer
83  *
84  * Returns:
85  *  S_OK if an interface was found
86  *  E_NOINTERFACE if the requested interface wasn't found
87  *
88  *****************************************************************************/
89 static HRESULT WINAPI
90 IDirectDrawImpl_QueryInterface(IDirectDraw7 *iface,
91                                REFIID refiid,
92                                void **obj)
93 {
94     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
95
96     TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(refiid), obj);
97
98     /* Can change surface impl type */
99     EnterCriticalSection(&ddraw_cs);
100
101     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
102     *obj = NULL;
103
104     if(!refiid)
105     {
106         LeaveCriticalSection(&ddraw_cs);
107         return DDERR_INVALIDPARAMS;
108     }
109
110     /* Check DirectDraw Interfaces */
111     if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
112          IsEqualGUID( &IID_IDirectDraw7, refiid ) )
113     {
114         *obj = ICOM_INTERFACE(This, IDirectDraw7);
115         TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
116     }
117     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
118     {
119         *obj = ICOM_INTERFACE(This, IDirectDraw4);
120         TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
121     }
122     else if ( IsEqualGUID( &IID_IDirectDraw3, refiid ) )
123     {
124         *obj = ICOM_INTERFACE(This, IDirectDraw3);
125         TRACE("(%p) Returning IDirectDraw3 interface at %p\n", This, *obj);
126     }
127     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
128     {
129         *obj = ICOM_INTERFACE(This, IDirectDraw2);
130         TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
131     }
132     else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
133     {
134         *obj = ICOM_INTERFACE(This, IDirectDraw);
135         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
136     }
137
138     /* Direct3D
139      * The refcount unit test revealed that an IDirect3D7 interface can only be queried
140      * from a DirectDraw object that was created as an IDirectDraw7 interface. No idea
141      * who had this idea and why. The older interfaces can query and IDirect3D version
142      * because they are all created as IDirectDraw(1). This isn't really crucial behavior,
143      * and messy to implement with the common creation function, so it has been left out here.
144      */
145     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ||
146               IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
147               IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
148               IsEqualGUID( &IID_IDirect3D7 , refiid ) )
149     {
150         /* Check the surface implementation */
151         if(This->ImplType == SURFACE_UNKNOWN)
152         {
153             /* Apps may create the IDirect3D Interface before the primary surface.
154              * set the surface implementation */
155             This->ImplType = SURFACE_OPENGL;
156             TRACE("(%p) Choosing OpenGL surfaces because a Direct3D interface was requested\n", This);
157         }
158         else if(This->ImplType != SURFACE_OPENGL && DefaultSurfaceType == SURFACE_UNKNOWN)
159         {
160             ERR("(%p) The App is requesting a D3D device, but a non-OpenGL surface type was choosen. Prepare for trouble!\n", This);
161             ERR(" (%p) You may want to contact wine-devel for help\n", This);
162             /* Should I assert(0) here??? */
163         }
164         else if(This->ImplType != SURFACE_OPENGL)
165         {
166             WARN("The app requests a Direct3D interface, but non-opengl surfaces where set in winecfg\n");
167             /* Do not abort here, only reject 3D Device creation */
168         }
169
170         if ( IsEqualGUID( &IID_IDirect3D  , refiid ) )
171         {
172             This->d3dversion = 1;
173             *obj = ICOM_INTERFACE(This, IDirect3D);
174             TRACE(" returning Direct3D interface at %p.\n", *obj);
175         }
176         else if ( IsEqualGUID( &IID_IDirect3D2  , refiid ) )
177         {
178             This->d3dversion = 2;
179             *obj = ICOM_INTERFACE(This, IDirect3D2);
180             TRACE(" returning Direct3D2 interface at %p.\n", *obj);
181         }
182         else if ( IsEqualGUID( &IID_IDirect3D3  , refiid ) )
183         {
184             This->d3dversion = 3;
185             *obj = ICOM_INTERFACE(This, IDirect3D3);
186             TRACE(" returning Direct3D3 interface at %p.\n", *obj);
187         }
188         else if(IsEqualGUID( &IID_IDirect3D7  , refiid ))
189         {
190             This->d3dversion = 7;
191             *obj = ICOM_INTERFACE(This, IDirect3D7);
192             TRACE(" returning Direct3D7 interface at %p.\n", *obj);
193         }
194     }
195
196     /* Unknown interface */
197     else
198     {
199         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
200         LeaveCriticalSection(&ddraw_cs);
201         return E_NOINTERFACE;
202     }
203
204     IUnknown_AddRef( (IUnknown *) *obj );
205     LeaveCriticalSection(&ddraw_cs);
206     return S_OK;
207 }
208
209 /*****************************************************************************
210  * IDirectDraw7::AddRef
211  *
212  * Increases the interfaces refcount, basically
213  *
214  * DDraw refcounting is a bit tricky. The different DirectDraw interface
215  * versions have individual refcounts, but the IDirect3D interfaces do not.
216  * All interfaces are from one object, that means calling QueryInterface on an
217  * IDirectDraw7 interface for an IDirectDraw4 interface does not create a new
218  * IDirectDrawImpl object.
219  *
220  * That means all AddRef and Release implementations of IDirectDrawX work
221  * with their own counter, and IDirect3DX::AddRef thunk to IDirectDraw (1),
222  * except of IDirect3D7 which thunks to IDirectDraw7
223  *
224  * Returns: The new refcount
225  *
226  *****************************************************************************/
227 static ULONG WINAPI
228 IDirectDrawImpl_AddRef(IDirectDraw7 *iface)
229 {
230     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
231     ULONG ref = InterlockedIncrement(&This->ref7);
232
233     TRACE("(%p) : incrementing IDirectDraw7 refcount from %u.\n", This, ref -1);
234
235     if(ref == 1) InterlockedIncrement(&This->numIfaces);
236
237     return ref;
238 }
239
240 /*****************************************************************************
241  * IDirectDrawImpl_Destroy
242  *
243  * Destroys a ddraw object if all refcounts are 0. This is to share code
244  * between the IDirectDrawX::Release functions
245  *
246  * Params:
247  *  This: DirectDraw object to destroy
248  *
249  *****************************************************************************/
250 void
251 IDirectDrawImpl_Destroy(IDirectDrawImpl *This)
252 {
253     /* Clear the cooplevel to restore window and display mode */
254     IDirectDraw7_SetCooperativeLevel(ICOM_INTERFACE(This, IDirectDraw7),
255                                         NULL,
256                                         DDSCL_NORMAL);
257
258     /* Destroy the device window if we created one */
259     if(This->devicewindow != 0)
260     {
261         TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
262         DestroyWindow(This->devicewindow);
263         This->devicewindow = 0;
264     }
265
266     /* Unregister the window class */
267     UnregisterClassA(This->classname, 0);
268
269     EnterCriticalSection(&ddraw_cs);
270     list_remove(&This->ddraw_list_entry);
271     LeaveCriticalSection(&ddraw_cs);
272
273     /* Release the attached WineD3D stuff */
274     IWineD3DDevice_Release(This->wineD3DDevice);
275     IWineD3D_Release(This->wineD3D);
276
277     /* Now free the object */
278     HeapFree(GetProcessHeap(), 0, This);
279 }
280
281 /*****************************************************************************
282  * IDirectDraw7::Release
283  *
284  * Decreases the refcount. If the refcount falls to 0, the object is destroyed
285  *
286  * Returns: The new refcount
287  *****************************************************************************/
288 static ULONG WINAPI
289 IDirectDrawImpl_Release(IDirectDraw7 *iface)
290 {
291     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
292     ULONG ref = InterlockedDecrement(&This->ref7);
293
294     TRACE("(%p)->() decrementing IDirectDraw7 refcount from %u.\n", This, ref +1);
295
296     if(ref == 0)
297     {
298         ULONG ifacecount = InterlockedDecrement(&This->numIfaces);
299         if(ifacecount == 0) IDirectDrawImpl_Destroy(This);
300     }
301
302     return ref;
303 }
304
305 /*****************************************************************************
306  * IDirectDraw methods
307  *****************************************************************************/
308
309 /*****************************************************************************
310  * IDirectDraw7::SetCooperativeLevel
311  *
312  * Sets the cooperative level for the DirectDraw object, and the window
313  * assigned to it. The cooperative level determines the general behavior
314  * of the DirectDraw application
315  *
316  * Warning: This is quite tricky, as it's not really documented which
317  * cooperative levels can be combined with each other. If a game fails
318  * after this function, try to check the cooperative levels passed on
319  * Windows, and if it returns something different.
320  *
321  * If you think that this function caused the failure because it writes a
322  * fixme, be sure to run again with a +ddraw trace.
323  *
324  * What is known about cooperative levels (See the ddraw modes test):
325  * DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN must be used with each other
326  * DDSCL_NORMAL is not compatible with DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN
327  * DDSCL_SETFOCUSWINDOW can be passed only in DDSCL_NORMAL mode, but after that
328  * DDSCL_FULLSCREEN can be activated
329  * DDSCL_SETFOCUSWINDOW may only be used with DDSCL_NOWINDOWCHANGES
330  *
331  * Handled flags: DDSCL_NORMAL, DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE,
332  *                DDSCL_SETFOCUSWINDOW (partially),
333  *                DDSCL_MULTITHREADED (work in progress)
334  *
335  * Unhandled flags, which should be implemented
336  *  DDSCL_SETDEVICEWINDOW: Sets a window specially used for rendering (I don't
337  *  expect any difference to a normal window for wine)
338  *  DDSCL_CREATEDEVICEWINDOW: Tells ddraw to create its own window for
339  *  rendering (Possible test case: Half-life)
340  *
341  * Unsure about these: DDSCL_FPUSETUP DDSCL_FPURESERVE
342  *
343  * These don't seem very important for wine:
344  *  DDSCL_ALLOWREBOOT, DDSCL_NOWINDOWCHANGES, DDSCL_ALLOWMODEX
345  *
346  * Returns:
347  *  DD_OK if the cooperative level was set successfully
348  *  DDERR_INVALIDPARAMS if the passed cooperative level combination is invalid
349  *  DDERR_HWNDALREADYSET if DDSCL_SETFOCUSWINDOW is passed in exclusive mode
350  *   (Probably others too, have to investigate)
351  *
352  *****************************************************************************/
353 static HRESULT WINAPI
354 IDirectDrawImpl_SetCooperativeLevel(IDirectDraw7 *iface,
355                                     HWND hwnd,
356                                     DWORD cooplevel)
357 {
358     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
359     HWND window;
360     HRESULT hr;
361
362     TRACE("(%p)->(%p,%08x)\n",This,hwnd,cooplevel);
363     DDRAW_dump_cooperativelevel(cooplevel);
364
365     EnterCriticalSection(&ddraw_cs);
366
367     /* Get the old window */
368     hr = IWineD3DDevice_GetHWND(This->wineD3DDevice, &window);
369     if(hr != D3D_OK)
370     {
371         ERR("IWineD3DDevice::GetHWND failed, hr = %08x\n", hr);
372         LeaveCriticalSection(&ddraw_cs);
373         return hr;
374     }
375
376     /* Tests suggest that we need one of them: */
377     if(!(cooplevel & (DDSCL_SETFOCUSWINDOW |
378                       DDSCL_NORMAL         |
379                       DDSCL_EXCLUSIVE      )))
380     {
381         TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
382         LeaveCriticalSection(&ddraw_cs);
383         return DDERR_INVALIDPARAMS;
384     }
385
386     /* Handle those levels first which set various hwnds */
387     if(cooplevel & DDSCL_SETFOCUSWINDOW)
388     {
389         /* This isn't compatible with a lot of flags */
390         if(cooplevel & ( DDSCL_MULTITHREADED   |
391                          DDSCL_FPUSETUP        |
392                          DDSCL_FPUPRESERVE     |
393                          DDSCL_ALLOWREBOOT     |
394                          DDSCL_ALLOWMODEX      |
395                          DDSCL_SETDEVICEWINDOW |
396                          DDSCL_NORMAL          |
397                          DDSCL_EXCLUSIVE       |
398                          DDSCL_FULLSCREEN      ) )
399         {
400             TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
401             LeaveCriticalSection(&ddraw_cs);
402             return DDERR_INVALIDPARAMS;
403         }
404         else if( (This->cooperative_level & DDSCL_FULLSCREEN) && window)
405         {
406             TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET\n");
407             LeaveCriticalSection(&ddraw_cs);
408             return DDERR_HWNDALREADYSET;
409         }
410
411         This->focuswindow = hwnd;
412         /* Won't use the hwnd param for anything else */
413         hwnd = NULL;
414
415         /* Use the focus window for drawing too */
416         IWineD3DDevice_SetHWND(This->wineD3DDevice, This->focuswindow);
417
418         /* Destroy the device window, if we have one */
419         if(This->devicewindow)
420         {
421             DestroyWindow(This->devicewindow);
422             This->devicewindow = NULL;
423         }
424     }
425     /* DDSCL_NORMAL or DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE */
426     if(cooplevel & DDSCL_NORMAL)
427     {
428         /* Can't coexist with fullscreen or exclusive */
429         if(cooplevel & (DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE) )
430         {
431             TRACE("(%p) DDSCL_NORMAL is not compative with DDSCL_FULLSCREEN or DDSCL_EXCLUSIVE\n", This);
432             LeaveCriticalSection(&ddraw_cs);
433             return DDERR_INVALIDPARAMS;
434         }
435
436         /* Switching from fullscreen? */
437         if(This->cooperative_level & DDSCL_FULLSCREEN)
438         {
439             /* Restore the display mode */
440             IDirectDraw7_RestoreDisplayMode(iface);
441
442             This->cooperative_level &= ~DDSCL_FULLSCREEN;
443             This->cooperative_level &= ~DDSCL_EXCLUSIVE;
444             This->cooperative_level &= ~DDSCL_ALLOWMODEX;
445         }
446
447         /* Don't override focus windows or private device windows */
448         if( hwnd &&
449             !(This->focuswindow) &&
450             !(This->devicewindow) &&
451             (hwnd != window) )
452         {
453             IWineD3DDevice_SetHWND(This->wineD3DDevice, hwnd);
454         }
455
456         IWineD3DDevice_SetFullscreen(This->wineD3DDevice,
457                                      FALSE);
458     }
459     else if(cooplevel & DDSCL_FULLSCREEN)
460     {
461         /* Needs DDSCL_EXCLUSIVE */
462         if(!(cooplevel & DDSCL_EXCLUSIVE) )
463         {
464             TRACE("(%p) DDSCL_FULLSCREEN needs DDSCL_EXCLUSIVE\n", This);
465             LeaveCriticalSection(&ddraw_cs);
466             return DDERR_INVALIDPARAMS;
467         }
468         /* Need a HWND
469         if(hwnd == 0)
470         {
471             TRACE("(%p) DDSCL_FULLSCREEN needs a HWND\n", This);
472             return DDERR_INVALIDPARAMS;
473         }
474         */
475
476         This->cooperative_level &= ~DDSCL_NORMAL;
477         IWineD3DDevice_SetFullscreen(This->wineD3DDevice,
478                                      TRUE);
479
480         /* Don't override focus windows or private device windows */
481         if( hwnd &&
482             !(This->focuswindow) &&
483             !(This->devicewindow) &&
484             (hwnd != window) )
485         {
486             IWineD3DDevice_SetHWND(This->wineD3DDevice, hwnd);
487         }
488     }
489     else if(cooplevel & DDSCL_EXCLUSIVE)
490     {
491         TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN\n", This);
492         LeaveCriticalSection(&ddraw_cs);
493         return DDERR_INVALIDPARAMS;
494     }
495
496     if(cooplevel & DDSCL_CREATEDEVICEWINDOW)
497     {
498         /* Don't create a device window if a focus window is set */
499         if( !(This->focuswindow) )
500         {
501             HWND devicewindow = CreateWindowExA(0, This->classname, "DDraw device window",
502                                                 WS_POPUP, 0, 0,
503                                                 GetSystemMetrics(SM_CXSCREEN),
504                                                 GetSystemMetrics(SM_CYSCREEN),
505                                                 NULL, NULL, GetModuleHandleA(0), NULL);
506
507             ShowWindow(devicewindow, SW_SHOW);   /* Just to be sure */
508             TRACE("(%p) Created a DDraw device window. HWND=%p\n", This, devicewindow);
509
510             IWineD3DDevice_SetHWND(This->wineD3DDevice, devicewindow);
511             This->devicewindow = devicewindow;
512         }
513     }
514
515     if(cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
516     {
517         /* Enable thread safety in wined3d */
518         IWineD3DDevice_SetMultithreaded(This->wineD3DDevice);
519     }
520
521     /* Unhandled flags */
522     if(cooplevel & DDSCL_ALLOWREBOOT)
523         WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
524     if(cooplevel & DDSCL_ALLOWMODEX)
525         WARN("(%p) Unhandled flag DDSCL_ALLOWMODEX, harmless\n", This);
526     if(cooplevel & DDSCL_FPUSETUP)
527         WARN("(%p) Unhandled flag DDSCL_FPUSETUP, harmless\n", This);
528
529     /* Store the cooperative_level */
530     This->cooperative_level |= cooplevel;
531     TRACE("SetCooperativeLevel retuning DD_OK\n");
532     LeaveCriticalSection(&ddraw_cs);
533     return DD_OK;
534 }
535
536 /*****************************************************************************
537  *
538  * Helper function for SetDisplayMode and RestoreDisplayMode
539  *
540  * Implements DirectDraw's SetDisplayMode, but ignores the value of
541  * ForceRefreshRate, since it is already handled by
542  * IDirectDrawImpl_SetDisplayMode.  RestoreDisplayMode can use this function
543  * without worrying that ForceRefreshRate will override the refresh rate.  For
544  * argument and return value documentation, see
545  * IDirectDrawImpl_SetDisplayMode.
546  *
547  *****************************************************************************/
548 static HRESULT
549 IDirectDrawImpl_SetDisplayModeNoOverride(IDirectDraw7 *iface,
550                                          DWORD Width,
551                                          DWORD Height,
552                                          DWORD BPP,
553                                          DWORD RefreshRate,
554                                          DWORD Flags)
555 {
556     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
557     WINED3DDISPLAYMODE Mode;
558     HRESULT hr;
559     TRACE("(%p)->(%d,%d,%d,%d,%x: Relay!\n", This, Width, Height, BPP, RefreshRate, Flags);
560
561     EnterCriticalSection(&ddraw_cs);
562     if( !Width || !Height )
563     {
564         ERR("Width=%d, Height=%d, what to do?\n", Width, Height);
565         /* It looks like Need for Speed Porsche Unleashed expects DD_OK here */
566         LeaveCriticalSection(&ddraw_cs);
567         return DD_OK;
568     }
569
570     /* Check the exclusive mode
571     if(!(This->cooperative_level & DDSCL_EXCLUSIVE))
572         return DDERR_NOEXCLUSIVEMODE;
573      * This is WRONG. Don't know if the SDK is completely
574      * wrong and if there are any conditions when DDERR_NOEXCLUSIVE
575      * is returned, but Half-Life 1.1.1.1 (Steam version)
576      * depends on this
577      */
578
579     Mode.Width = Width;
580     Mode.Height = Height;
581     Mode.RefreshRate = RefreshRate;
582     switch(BPP)
583     {
584         case 8:  Mode.Format = WINED3DFMT_P8;       break;
585         case 15: Mode.Format = WINED3DFMT_X1R5G5B5; break;
586         case 16: Mode.Format = WINED3DFMT_R5G6B5;   break;
587         case 24: Mode.Format = WINED3DFMT_R8G8B8;   break;
588         case 32: Mode.Format = WINED3DFMT_X8R8G8B8; break;
589     }
590
591     /* TODO: The possible return values from msdn suggest that
592      * the screen mode can't be changed if a surface is locked
593      * or some drawing is in progress
594      */
595
596     /* TODO: Lose the primary surface */
597     hr = IWineD3DDevice_SetDisplayMode(This->wineD3DDevice,
598                                        0, /* First swapchain */
599                                        &Mode);
600     LeaveCriticalSection(&ddraw_cs);
601     switch(hr)
602     {
603         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
604         default:                            return hr;
605     };
606 }
607
608 /*****************************************************************************
609  * IDirectDraw7::SetDisplayMode
610  *
611  * Sets the display screen resolution, color depth and refresh frequency
612  * when in fullscreen mode (in theory).
613  * Possible return values listed in the SDK suggest that this method fails
614  * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
615  * the display mode in DDSCL_NORMAL mode without an hwnd specified.
616  * It seems to be valid to pass 0 for With and Height, this has to be tested
617  * It could mean that the current video mode should be left as-is. (But why
618  * call it then?)
619  *
620  * Params:
621  *  Height, Width: Screen dimension
622  *  BPP: Color depth in Bits per pixel
623  *  Refreshrate: Screen refresh rate
624  *  Flags: Other stuff
625  *
626  * Returns
627  *  DD_OK on success
628  *
629  *****************************************************************************/
630 static HRESULT WINAPI
631 IDirectDrawImpl_SetDisplayMode(IDirectDraw7 *iface,
632                                DWORD Width,
633                                DWORD Height,
634                                DWORD BPP,
635                                DWORD RefreshRate,
636                                DWORD Flags)
637 {
638     if (force_refresh_rate != 0)
639     {
640         TRACE("ForceRefreshRate overriding passed-in refresh rate (%d Hz) to %d Hz\n", RefreshRate, force_refresh_rate);
641         RefreshRate = force_refresh_rate;
642     }
643
644     return IDirectDrawImpl_SetDisplayModeNoOverride(iface, Width, Height, BPP,
645                                                     RefreshRate, Flags);
646 }
647
648 /*****************************************************************************
649  * IDirectDraw7::RestoreDisplayMode
650  *
651  * Restores the display mode to what it was at creation time. Basically.
652  *
653  * A problem arises when there are 2 DirectDraw objects using the same hwnd:
654  *  -> DD_1 finds the screen at 1400x1050x32 when created, sets it to 640x480x16
655  *  -> DD_2 is created, finds the screen at 640x480x16, sets it to 1024x768x32
656  *  -> DD_1 is released. The screen should be left at 1024x768x32.
657  *  -> DD_2 is released. The screen should be set to 1400x1050x32
658  * This case is unhandled right now, but Empire Earth does it this way.
659  * (But perhaps there is something in SetCooperativeLevel to prevent this)
660  *
661  * The msdn says that this method resets the display mode to what it was before
662  * SetDisplayMode was called. What if SetDisplayModes is called 2 times??
663  *
664  * Returns
665  *  DD_OK on success
666  *  DDERR_NOEXCLUSIVE mode if the device isn't in fullscreen mode
667  *
668  *****************************************************************************/
669 static HRESULT WINAPI
670 IDirectDrawImpl_RestoreDisplayMode(IDirectDraw7 *iface)
671 {
672     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
673     TRACE("(%p)\n", This);
674
675     return IDirectDrawImpl_SetDisplayModeNoOverride(ICOM_INTERFACE(This, IDirectDraw7),
676                                                     This->orig_width,
677                                                     This->orig_height,
678                                                     This->orig_bpp,
679                                                     0,
680                                                     0);
681 }
682
683 /*****************************************************************************
684  * IDirectDraw7::GetCaps
685  *
686  * Returns the drives capabilities
687  *
688  * Used for version 1, 2, 4 and 7
689  *
690  * Params:
691  *  DriverCaps: Structure to write the Hardware accelerated caps to
692  *  HelCaps: Structure to write the emulation caps to
693  *
694  * Returns
695  *  This implementation returns DD_OK only
696  *
697  *****************************************************************************/
698 static HRESULT WINAPI
699 IDirectDrawImpl_GetCaps(IDirectDraw7 *iface,
700                         DDCAPS *DriverCaps,
701                         DDCAPS *HELCaps)
702 {
703     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
704     DDCAPS caps;
705     WINED3DCAPS winecaps;
706     HRESULT hr;
707     DDSCAPS2 ddscaps = {0, 0, 0, 0};
708     TRACE("(%p)->(%p,%p)\n", This, DriverCaps, HELCaps);
709
710     /* One structure must be != NULL */
711     if( (!DriverCaps) && (!HELCaps) )
712     {
713         ERR("(%p) Invalid params to IDirectDrawImpl_GetCaps\n", This);
714         return DDERR_INVALIDPARAMS;
715     }
716
717     memset(&caps, 0, sizeof(caps));
718     memset(&winecaps, 0, sizeof(winecaps));
719     caps.dwSize = sizeof(caps);
720     EnterCriticalSection(&ddraw_cs);
721     hr = IWineD3DDevice_GetDeviceCaps(This->wineD3DDevice, &winecaps);
722     if(FAILED(hr)) {
723         WARN("IWineD3DDevice::GetDeviceCaps failed\n");
724         LeaveCriticalSection(&ddraw_cs);
725         return hr;
726     }
727
728     hr = IDirectDraw7_GetAvailableVidMem(iface, &ddscaps, &caps.dwVidMemTotal, &caps.dwVidMemFree);
729     LeaveCriticalSection(&ddraw_cs);
730     if(FAILED(hr)) {
731         WARN("IDirectDraw7::GetAvailableVidMem failed\n");
732         return hr;
733     }
734
735     caps.dwCaps = winecaps.DirectDrawCaps.Caps;
736     caps.dwCaps2 = winecaps.DirectDrawCaps.Caps2;
737     caps.dwCKeyCaps = winecaps.DirectDrawCaps.CKeyCaps;
738     caps.dwFXCaps = winecaps.DirectDrawCaps.FXCaps;
739     caps.dwPalCaps = winecaps.DirectDrawCaps.PalCaps;
740     caps.ddsCaps.dwCaps = winecaps.DirectDrawCaps.ddsCaps;
741     caps.dwSVBCaps = winecaps.DirectDrawCaps.SVBCaps;
742     caps.dwSVBCKeyCaps = winecaps.DirectDrawCaps.SVBCKeyCaps;
743     caps.dwSVBFXCaps = winecaps.DirectDrawCaps.SVBFXCaps;
744     caps.dwVSBCaps = winecaps.DirectDrawCaps.VSBCaps;
745     caps.dwVSBCKeyCaps = winecaps.DirectDrawCaps.VSBCKeyCaps;
746     caps.dwVSBFXCaps = winecaps.DirectDrawCaps.VSBFXCaps;
747     caps.dwSSBCaps = winecaps.DirectDrawCaps.SSBCaps;
748     caps.dwSSBCKeyCaps = winecaps.DirectDrawCaps.SSBCKeyCaps;
749     caps.dwSSBFXCaps = winecaps.DirectDrawCaps.SSBFXCaps;
750
751     /* Even if WineD3D supports 3D rendering, remove the cap if ddraw is configured
752      * not to use it
753      */
754     if(DefaultSurfaceType == SURFACE_GDI) {
755         caps.dwCaps &= ~DDCAPS_3D;
756         caps.ddsCaps.dwCaps &= ~(DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER);
757     }
758     if(winecaps.DirectDrawCaps.StrideAlign != 0) {
759         caps.dwCaps |= DDCAPS_ALIGNSTRIDE;
760         caps.dwAlignStrideAlign = winecaps.DirectDrawCaps.StrideAlign;
761     }
762
763     if(DriverCaps)
764     {
765         DD_STRUCT_COPY_BYSIZE(DriverCaps, &caps);
766         if (TRACE_ON(ddraw))
767         {
768             TRACE("Driver Caps :\n");
769             DDRAW_dump_DDCAPS(DriverCaps);
770         }
771
772     }
773     if(HELCaps)
774     {
775         DD_STRUCT_COPY_BYSIZE(HELCaps, &caps);
776         if (TRACE_ON(ddraw))
777         {
778             TRACE("HEL Caps :\n");
779             DDRAW_dump_DDCAPS(HELCaps);
780         }
781     }
782
783     return DD_OK;
784 }
785
786 /*****************************************************************************
787  * IDirectDraw7::Compact
788  *
789  * No idea what it does, MSDN says it's not implemented.
790  *
791  * Returns
792  *  DD_OK, but this is unchecked
793  *
794  *****************************************************************************/
795 static HRESULT WINAPI
796 IDirectDrawImpl_Compact(IDirectDraw7 *iface)
797 {
798     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
799     TRACE("(%p)\n", This);
800
801     return DD_OK;
802 }
803
804 /*****************************************************************************
805  * IDirectDraw7::GetDisplayMode
806  *
807  * Returns information about the current display mode
808  *
809  * Exists in Version 1, 2, 4 and 7
810  *
811  * Params:
812  *  DDSD: Address of a surface description structure to write the info to
813  *
814  * Returns
815  *  DD_OK
816  *
817  *****************************************************************************/
818 static HRESULT WINAPI
819 IDirectDrawImpl_GetDisplayMode(IDirectDraw7 *iface,
820                                DDSURFACEDESC2 *DDSD)
821 {
822     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
823     HRESULT hr;
824     WINED3DDISPLAYMODE Mode;
825     DWORD Size;
826     TRACE("(%p)->(%p): Relay\n", This, DDSD);
827
828     EnterCriticalSection(&ddraw_cs);
829     /* This seems sane */
830     if(!DDSD) 
831     {
832         LeaveCriticalSection(&ddraw_cs);
833         return DDERR_INVALIDPARAMS;
834     }
835
836     /* The necessary members of LPDDSURFACEDESC and LPDDSURFACEDESC2 are equal,
837      * so one method can be used for all versions (Hopefully)
838      */
839     hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
840                                       0 /* swapchain 0 */,
841                                       &Mode);
842     if( hr != D3D_OK )
843     {
844         ERR(" (%p) IWineD3DDevice::GetDisplayMode returned %08x\n", This, hr);
845         LeaveCriticalSection(&ddraw_cs);
846         return hr;
847     }
848
849     Size = DDSD->dwSize;
850     memset(DDSD, 0, Size);
851
852     DDSD->dwSize = Size;
853     DDSD->dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
854     DDSD->dwWidth = Mode.Width;
855     DDSD->dwHeight = Mode.Height; 
856     DDSD->u2.dwRefreshRate = 60;
857     DDSD->ddsCaps.dwCaps = 0;
858     DDSD->u4.ddpfPixelFormat.dwSize = sizeof(DDSD->u4.ddpfPixelFormat);
859     PixelFormat_WineD3DtoDD(&DDSD->u4.ddpfPixelFormat, Mode.Format);
860     DDSD->u1.lPitch = Mode.Width * DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount / 8;
861
862     if(TRACE_ON(ddraw))
863     {
864         TRACE("Returning surface desc :\n");
865         DDRAW_dump_surface_desc(DDSD);
866     }
867
868     LeaveCriticalSection(&ddraw_cs);
869     return DD_OK;
870 }
871
872 /*****************************************************************************
873  * IDirectDraw7::GetFourCCCodes
874  *
875  * Returns an array of supported FourCC codes.
876  *
877  * Exists in Version 1, 2, 4 and 7
878  *
879  * Params:
880  *  NumCodes: Contains the number of Codes that Codes can carry. Returns the number
881  *            of enumerated codes
882  *  Codes: Pointer to an array of DWORDs where the supported codes are written
883  *         to
884  *
885  * Returns
886  *  Always returns DD_OK, as it's a stub for now
887  *
888  *****************************************************************************/
889 static HRESULT WINAPI
890 IDirectDrawImpl_GetFourCCCodes(IDirectDraw7 *iface,
891                                DWORD *NumCodes, DWORD *Codes)
892 {
893     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
894     FIXME("(%p)->(%p, %p): Stub!\n", This, NumCodes, Codes);
895
896     if(NumCodes) *NumCodes = 0;
897
898     return DD_OK;
899 }
900
901 /*****************************************************************************
902  * IDirectDraw7::GetMonitorFrequency
903  *
904  * Returns the monitor's frequency
905  *
906  * Exists in Version 1, 2, 4 and 7
907  *
908  * Params:
909  *  Freq: Pointer to a DWORD to write the frequency to
910  *
911  * Returns
912  *  Always returns DD_OK
913  *
914  *****************************************************************************/
915 static HRESULT WINAPI
916 IDirectDrawImpl_GetMonitorFrequency(IDirectDraw7 *iface,
917                                     DWORD *Freq)
918 {
919     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
920     TRACE("(%p)->(%p)\n", This, Freq);
921
922     /* Ideally this should be in WineD3D, as it concerns the screen setup,
923      * but for now this should make the games happy
924      */
925     *Freq = 60;
926     return DD_OK;
927 }
928
929 /*****************************************************************************
930  * IDirectDraw7::GetVerticalBlankStatus
931  *
932  * Returns the Vertical blank status of the monitor. This should be in WineD3D
933  * too basically, but as it's a semi stub, I didn't create a function there
934  *
935  * Params:
936  *  status: Pointer to a BOOL to be filled with the vertical blank status
937  *
938  * Returns
939  *  DD_OK on success
940  *  DDERR_INVALIDPARAMS if status is NULL
941  *
942  *****************************************************************************/
943 static HRESULT WINAPI
944 IDirectDrawImpl_GetVerticalBlankStatus(IDirectDraw7 *iface,
945                                        BOOL *status)
946 {
947     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
948     TRACE("(%p)->(%p)\n", This, status);
949
950     /* This looks sane, the MSDN suggests it too */
951     EnterCriticalSection(&ddraw_cs);
952     if(!status)
953     {
954         LeaveCriticalSection(&ddraw_cs);
955         return DDERR_INVALIDPARAMS;
956     }
957
958     *status = This->fake_vblank;
959     This->fake_vblank = !This->fake_vblank;
960     LeaveCriticalSection(&ddraw_cs);
961     return DD_OK;
962 }
963
964 /*****************************************************************************
965  * IDirectDraw7::GetAvailableVidMem
966  *
967  * Returns the total and free video memory
968  *
969  * Params:
970  *  Caps: Specifies the memory type asked for
971  *  total: Pointer to a DWORD to be filled with the total memory
972  *  free: Pointer to a DWORD to be filled with the free memory
973  *
974  * Returns
975  *  DD_OK on success
976  *  DDERR_INVALIDPARAMS of free and total are NULL
977  *
978  *****************************************************************************/
979 static HRESULT WINAPI
980 IDirectDrawImpl_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *Caps, DWORD *total, DWORD *free)
981 {
982     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
983     TRACE("(%p)->(%p, %p, %p)\n", This, Caps, total, free);
984
985     if(TRACE_ON(ddraw))
986     {
987         TRACE("(%p) Asked for memory with description: ", This);
988         DDRAW_dump_DDSCAPS2(Caps);
989     }
990     EnterCriticalSection(&ddraw_cs);
991
992     /* Todo: System memory vs local video memory vs non-local video memory
993      * The MSDN also mentions differences between texture memory and other
994      * resources, but that's not important
995      */
996
997     if( (!total) && (!free) )
998     {
999         LeaveCriticalSection(&ddraw_cs);
1000         return DDERR_INVALIDPARAMS;
1001     }
1002
1003     if(total) *total = This->total_vidmem;
1004     if(free) *free = IWineD3DDevice_GetAvailableTextureMem(This->wineD3DDevice);
1005
1006     LeaveCriticalSection(&ddraw_cs);
1007     return DD_OK;
1008 }
1009
1010 /*****************************************************************************
1011  * IDirectDraw7::Initialize
1012  *
1013  * Initializes a DirectDraw interface.
1014  *
1015  * Params:
1016  *  GUID: Interface identifier. Well, don't know what this is really good
1017  *   for
1018  *
1019  * Returns
1020  *  Returns DD_OK on the first call,
1021  *  DDERR_ALREADYINITIALIZED on repeated calls
1022  *
1023  *****************************************************************************/
1024 static HRESULT WINAPI
1025 IDirectDrawImpl_Initialize(IDirectDraw7 *iface,
1026                            GUID *Guid)
1027 {
1028     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1029     TRACE("(%p)->(%s): No-op\n", This, debugstr_guid(Guid));
1030
1031     if(This->initialized)
1032     {
1033         return DDERR_ALREADYINITIALIZED;
1034     }
1035     else
1036     {
1037         return DD_OK;
1038     }
1039 }
1040
1041 /*****************************************************************************
1042  * IDirectDraw7::FlipToGDISurface
1043  *
1044  * "Makes the surface that the GDI writes to the primary surface"
1045  * Looks like some windows specific thing we don't have to care about.
1046  * According to MSDN it permits GDI dialog boxes in FULLSCREEN mode. Good to
1047  * show error boxes ;)
1048  * Well, just return DD_OK.
1049  *
1050  * Returns:
1051  *  Always returns DD_OK
1052  *
1053  *****************************************************************************/
1054 static HRESULT WINAPI
1055 IDirectDrawImpl_FlipToGDISurface(IDirectDraw7 *iface)
1056 {
1057     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1058     TRACE("(%p)\n", This);
1059
1060     return DD_OK;
1061 }
1062
1063 /*****************************************************************************
1064  * IDirectDraw7::WaitForVerticalBlank
1065  *
1066  * This method allows applications to get in sync with the vertical blank
1067  * interval.
1068  * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
1069  * redraw the screen, most likely because of this stub
1070  *
1071  * Parameters:
1072  *  Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
1073  *         or DDWAITVB_BLOCKEND
1074  *  h: Not used, according to MSDN
1075  *
1076  * Returns:
1077  *  Always returns DD_OK
1078  *
1079  *****************************************************************************/ 
1080 static HRESULT WINAPI
1081 IDirectDrawImpl_WaitForVerticalBlank(IDirectDraw7 *iface,
1082                                      DWORD Flags,
1083                                      HANDLE h)
1084 {
1085     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1086     FIXME("(%p)->(%x,%p): Stub\n", This, Flags, h);
1087
1088     /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
1089     if(Flags & DDWAITVB_BLOCKBEGINEVENT)
1090         return DDERR_UNSUPPORTED; /* unchecked */
1091
1092     return DD_OK;
1093 }
1094
1095 /*****************************************************************************
1096  * IDirectDraw7::GetScanLine
1097  *
1098  * Returns the scan line that is being drawn on the monitor
1099  *
1100  * Parameters:
1101  *  Scanline: Address to write the scan line value to
1102  *
1103  * Returns:
1104  *  Always returns DD_OK
1105  *
1106  *****************************************************************************/ 
1107 static HRESULT WINAPI IDirectDrawImpl_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
1108 {
1109     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1110     static BOOL hide = FALSE;
1111     WINED3DDISPLAYMODE Mode;
1112
1113     /* This function is called often, so print the fixme only once */
1114     EnterCriticalSection(&ddraw_cs);
1115     if(!hide)
1116     {
1117         FIXME("(%p)->(%p): Semi-Stub\n", This, Scanline);
1118         hide = TRUE;
1119     }
1120
1121     IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
1122                                   0,
1123                                   &Mode);
1124
1125     /* Fake the line sweeping of the monitor */
1126     /* FIXME: We should synchronize with a source to keep the refresh rate */ 
1127     *Scanline = This->cur_scanline++;
1128     /* Assume 20 scan lines in the vertical blank */
1129     if (This->cur_scanline >= Mode.Height + 20)
1130         This->cur_scanline = 0;
1131
1132     LeaveCriticalSection(&ddraw_cs);
1133     return DD_OK;
1134 }
1135
1136 /*****************************************************************************
1137  * IDirectDraw7::TestCooperativeLevel
1138  *
1139  * Informs the application about the state of the video adapter, depending
1140  * on the cooperative level
1141  *
1142  * Returns:
1143  *  DD_OK if the device is in a sane state
1144  *  DDERR_NOEXCLUSIVEMODE or DDERR_EXCLUSIVEMODEALREADYSET
1145  *  if the state is not correct(See below)
1146  *
1147  *****************************************************************************/ 
1148 static HRESULT WINAPI
1149 IDirectDrawImpl_TestCooperativeLevel(IDirectDraw7 *iface)
1150 {
1151     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1152     HRESULT hr;
1153     TRACE("(%p)\n", This);
1154
1155     EnterCriticalSection(&ddraw_cs);
1156     /* Description from MSDN:
1157      * For fullscreen apps return DDERR_NOEXCLUSIVEMODE if the user switched
1158      * away from the app with e.g. alt-tab. Windowed apps receive 
1159      * DDERR_EXCLUSIVEMODEALREADYSET if another application created a 
1160      * DirectDraw object in exclusive mode. DDERR_WRONGMODE is returned,
1161      * when the video mode has changed
1162      */
1163
1164     hr =  IWineD3DDevice_TestCooperativeLevel(This->wineD3DDevice);
1165
1166     /* Fix the result value. These values are mapped from their
1167      * d3d9 counterpart.
1168      */
1169     switch(hr)
1170     {
1171         case WINED3DERR_DEVICELOST:
1172             if(This->cooperative_level & DDSCL_EXCLUSIVE)
1173             {
1174                 LeaveCriticalSection(&ddraw_cs);
1175                 return DDERR_NOEXCLUSIVEMODE;
1176             }
1177             else
1178             {
1179                 LeaveCriticalSection(&ddraw_cs);
1180                 return DDERR_EXCLUSIVEMODEALREADYSET;
1181             }
1182
1183         case WINED3DERR_DEVICENOTRESET:
1184             LeaveCriticalSection(&ddraw_cs);
1185             return DD_OK;
1186
1187         case WINED3D_OK:
1188             LeaveCriticalSection(&ddraw_cs);
1189             return DD_OK;
1190
1191         case WINED3DERR_DRIVERINTERNALERROR:
1192         default:
1193             ERR("(%p) Unexpected return value %08x from wineD3D, "
1194                 " returning DD_OK\n", This, hr);
1195     }
1196
1197     LeaveCriticalSection(&ddraw_cs);
1198     return DD_OK;
1199 }
1200
1201 /*****************************************************************************
1202  * IDirectDraw7::GetGDISurface
1203  *
1204  * Returns the surface that GDI is treating as the primary surface.
1205  * For Wine this is the front buffer
1206  *
1207  * Params:
1208  *  GDISurface: Address to write the surface pointer to
1209  *
1210  * Returns:
1211  *  DD_OK if the surface was found
1212  *  DDERR_NOTFOUND if the GDI surface wasn't found
1213  *
1214  *****************************************************************************/ 
1215 static HRESULT WINAPI
1216 IDirectDrawImpl_GetGDISurface(IDirectDraw7 *iface,
1217                               IDirectDrawSurface7 **GDISurface)
1218 {
1219     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1220     IWineD3DSurface *Surf;
1221     IDirectDrawSurface7 *ddsurf;
1222     HRESULT hr;
1223     DDSCAPS2 ddsCaps;
1224     TRACE("(%p)->(%p)\n", This, GDISurface);
1225
1226     /* Get the back buffer from the wineD3DDevice and search its
1227      * attached surfaces for the front buffer
1228      */
1229     EnterCriticalSection(&ddraw_cs);
1230     hr = IWineD3DDevice_GetBackBuffer(This->wineD3DDevice,
1231                                       0, /* SwapChain */
1232                                       0, /* first back buffer*/
1233                                       WINED3DBACKBUFFER_TYPE_MONO,
1234                                       &Surf);
1235
1236     if( (hr != D3D_OK) ||
1237         (!Surf) )
1238     {
1239         ERR("IWineD3DDevice::GetBackBuffer failed\n");
1240         LeaveCriticalSection(&ddraw_cs);
1241         return DDERR_NOTFOUND;
1242     }
1243
1244     /* GetBackBuffer AddRef()ed the surface, release it */
1245     IWineD3DSurface_Release(Surf);
1246
1247     IWineD3DSurface_GetParent(Surf,
1248                               (IUnknown **) &ddsurf);
1249     IDirectDrawSurface7_Release(ddsurf);  /* For the GetParent */
1250
1251     /* Find the front buffer */
1252     ddsCaps.dwCaps = DDSCAPS_FRONTBUFFER;
1253     hr = IDirectDrawSurface7_GetAttachedSurface(ddsurf,
1254                                                 &ddsCaps,
1255                                                 GDISurface);
1256     if(hr != DD_OK)
1257     {
1258         ERR("IDirectDrawSurface7::GetAttachedSurface failed, hr = %x\n", hr);
1259     }
1260
1261     /* The AddRef is OK this time */
1262     LeaveCriticalSection(&ddraw_cs);
1263     return hr;
1264 }
1265
1266 /*****************************************************************************
1267  * IDirectDraw7::EnumDisplayModes
1268  *
1269  * Enumerates the supported Display modes. The modes can be filtered with
1270  * the DDSD parameter.
1271  *
1272  * Params:
1273  *  Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES
1274  *  DDSD: Surface description to filter the modes
1275  *  Context: Pointer passed back to the callback function
1276  *  cb: Application-provided callback function
1277  *
1278  * Returns:
1279  *  DD_OK on success
1280  *  DDERR_INVALIDPARAMS if the callback wasn't set
1281  *
1282  *****************************************************************************/ 
1283 static HRESULT WINAPI
1284 IDirectDrawImpl_EnumDisplayModes(IDirectDraw7 *iface,
1285                                  DWORD Flags,
1286                                  DDSURFACEDESC2 *DDSD,
1287                                  void *Context,
1288                                  LPDDENUMMODESCALLBACK2 cb)
1289 {
1290     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1291     unsigned int modenum, fmt;
1292     WINED3DFORMAT pixelformat = WINED3DFMT_UNKNOWN;
1293     WINED3DDISPLAYMODE mode;
1294     DDSURFACEDESC2 callback_sd;
1295     WINED3DDISPLAYMODE *enum_modes = NULL;
1296     unsigned enum_mode_count = 0, enum_mode_array_size = 0;
1297
1298     WINED3DFORMAT checkFormatList[] =
1299     {
1300         WINED3DFMT_R8G8B8,
1301         WINED3DFMT_A8R8G8B8,
1302         WINED3DFMT_X8R8G8B8,
1303         WINED3DFMT_R5G6B5,
1304         WINED3DFMT_X1R5G5B5,
1305         WINED3DFMT_A1R5G5B5,
1306         WINED3DFMT_A4R4G4B4,
1307         WINED3DFMT_R3G3B2,
1308         WINED3DFMT_A8R3G3B2,
1309         WINED3DFMT_X4R4G4B4,
1310         WINED3DFMT_A2B10G10R10,
1311         WINED3DFMT_A8B8G8R8,
1312         WINED3DFMT_X8B8G8R8,
1313         WINED3DFMT_A2R10G10B10,
1314         WINED3DFMT_A8P8,
1315         WINED3DFMT_P8
1316     };
1317
1318     TRACE("(%p)->(%p,%p,%p): Relay\n", This, DDSD, Context, cb);
1319
1320     EnterCriticalSection(&ddraw_cs);
1321     /* This looks sane */
1322     if(!cb)
1323     {
1324         LeaveCriticalSection(&ddraw_cs);
1325         return DDERR_INVALIDPARAMS;
1326     }
1327
1328     if(DDSD)
1329     {
1330         if ((DDSD->dwFlags & DDSD_PIXELFORMAT) && (DDSD->u4.ddpfPixelFormat.dwFlags & DDPF_RGB) )
1331             pixelformat = PixelFormat_DD2WineD3D(&DDSD->u4.ddpfPixelFormat);
1332     }
1333
1334     if(!(Flags & DDEDM_REFRESHRATES))
1335     {
1336         enum_mode_array_size = 16;
1337         enum_modes = HeapAlloc(GetProcessHeap(), 0, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1338         if (!enum_modes)
1339         {
1340             ERR("Out of memory\n");
1341             LeaveCriticalSection(&ddraw_cs);
1342             return DDERR_OUTOFMEMORY;
1343         }
1344     }
1345
1346     for(fmt = 0; fmt < (sizeof(checkFormatList) / sizeof(checkFormatList[0])); fmt++)
1347     {
1348         if(pixelformat != WINED3DFMT_UNKNOWN && checkFormatList[fmt] != pixelformat)
1349         {
1350             continue;
1351         }
1352
1353         modenum = 0;
1354         while(IWineD3D_EnumAdapterModes(This->wineD3D,
1355                                         WINED3DADAPTER_DEFAULT,
1356                                         checkFormatList[fmt],
1357                                         modenum++,
1358                                         &mode) == WINED3D_OK)
1359         {
1360             if(DDSD)
1361             {
1362                 if(DDSD->dwFlags & DDSD_WIDTH && mode.Width != DDSD->dwWidth) continue;
1363                 if(DDSD->dwFlags & DDSD_HEIGHT && mode.Height != DDSD->dwHeight) continue;
1364             }
1365
1366             if(!(Flags & DDEDM_REFRESHRATES))
1367             {
1368                 /* DX docs state EnumDisplayMode should return only unique modes. If DDEDM_REFRESHRATES is not set, refresh
1369                  * rate doesn't matter when determining if the mode is unique. So modes only differing in refresh rate have
1370                  * to be reduced to a single unique result in such case.
1371                  */
1372                 BOOL found = FALSE;
1373                 unsigned i;
1374
1375                 for (i = 0; i < enum_mode_count; i++)
1376                 {
1377                     if(enum_modes[i].Width == mode.Width && enum_modes[i].Height == mode.Height &&
1378                        enum_modes[i].Format == mode.Format)
1379                     {
1380                         found = TRUE;
1381                         break;
1382                     }
1383                 }
1384
1385                 if(found) continue;
1386             }
1387
1388             memset(&callback_sd, 0, sizeof(callback_sd));
1389             callback_sd.dwSize = sizeof(callback_sd);
1390             callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
1391
1392             callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH;
1393             if(Flags & DDEDM_REFRESHRATES)
1394             {
1395                 callback_sd.dwFlags |= DDSD_REFRESHRATE;
1396                 callback_sd.u2.dwRefreshRate = mode.RefreshRate;
1397             }
1398
1399             callback_sd.dwWidth = mode.Width;
1400             callback_sd.dwHeight = mode.Height;
1401
1402             PixelFormat_WineD3DtoDD(&callback_sd.u4.ddpfPixelFormat, mode.Format);
1403
1404             /* Calc pitch and DWORD align like MSDN says */
1405             callback_sd.u1.lPitch = (callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8) * mode.Width;
1406             callback_sd.u1.lPitch = (callback_sd.u1.lPitch + 3) & ~3;
1407
1408             TRACE("Enumerating %dx%dx%d @%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
1409               callback_sd.u2.dwRefreshRate);
1410
1411             if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
1412             {
1413                 TRACE("Application asked to terminate the enumeration\n");
1414                 HeapFree(GetProcessHeap(), 0, enum_modes);
1415                 LeaveCriticalSection(&ddraw_cs);
1416                 return DD_OK;
1417             }
1418
1419             if(!(Flags & DDEDM_REFRESHRATES))
1420             {
1421                 if (enum_mode_count == enum_mode_array_size)
1422                 {
1423                     WINED3DDISPLAYMODE *new_enum_modes;
1424
1425                     enum_mode_array_size *= 2;
1426                     new_enum_modes = HeapReAlloc(GetProcessHeap(), 0, enum_modes, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1427
1428                     if (!new_enum_modes)
1429                     {
1430                         ERR("Out of memory\n");
1431                         HeapFree(GetProcessHeap(), 0, enum_modes);
1432                         LeaveCriticalSection(&ddraw_cs);
1433                         return DDERR_OUTOFMEMORY;
1434                     }
1435
1436                     enum_modes = new_enum_modes;
1437                 }
1438
1439                 enum_modes[enum_mode_count++] = mode;
1440             }
1441         }
1442     }
1443
1444     TRACE("End of enumeration\n");
1445     HeapFree(GetProcessHeap(), 0, enum_modes);
1446     LeaveCriticalSection(&ddraw_cs);
1447     return DD_OK;
1448 }
1449
1450 /*****************************************************************************
1451  * IDirectDraw7::EvaluateMode
1452  *
1453  * Used with IDirectDraw7::StartModeTest to test video modes.
1454  * EvaluateMode is used to pass or fail a mode, and continue with the next
1455  * mode
1456  *
1457  * Params:
1458  *  Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
1459  *  Timeout: Returns the amount of seconds left before the mode would have
1460  *           been failed automatically
1461  *
1462  * Returns:
1463  *  This implementation always DD_OK, because it's a stub
1464  *
1465  *****************************************************************************/
1466 static HRESULT WINAPI
1467 IDirectDrawImpl_EvaluateMode(IDirectDraw7 *iface,
1468                              DWORD Flags,
1469                              DWORD *Timeout)
1470 {
1471     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1472     FIXME("(%p)->(%d,%p): Stub!\n", This, Flags, Timeout);
1473
1474     /* When implementing this, implement it in WineD3D */
1475
1476     return DD_OK;
1477 }
1478
1479 /*****************************************************************************
1480  * IDirectDraw7::GetDeviceIdentifier
1481  *
1482  * Returns the device identifier, which gives information about the driver
1483  * Our device identifier is defined at the beginning of this file.
1484  *
1485  * Params:
1486  *  DDDI: Address for the returned structure
1487  *  Flags: Can be DDGDI_GETHOSTIDENTIFIER
1488  *
1489  * Returns:
1490  *  On success it returns DD_OK
1491  *  DDERR_INVALIDPARAMS if DDDI is NULL
1492  *
1493  *****************************************************************************/
1494 static HRESULT WINAPI
1495 IDirectDrawImpl_GetDeviceIdentifier(IDirectDraw7 *iface,
1496                                     DDDEVICEIDENTIFIER2 *DDDI,
1497                                     DWORD Flags)
1498 {
1499     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1500     TRACE("(%p)->(%p,%08x)\n", This, DDDI, Flags);
1501
1502     if(!DDDI)
1503         return DDERR_INVALIDPARAMS;
1504
1505     /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
1506      * host adapter, if there's a secondary 3D adapter. This doesn't apply
1507      * to any modern hardware, nor is it interesting for Wine, so ignore it
1508      */
1509
1510     *DDDI = deviceidentifier;
1511     return DD_OK;
1512 }
1513
1514 /*****************************************************************************
1515  * IDirectDraw7::GetSurfaceFromDC
1516  *
1517  * Returns the Surface for a GDI device context handle.
1518  * Is this related to IDirectDrawSurface::GetDC ???
1519  *
1520  * Params:
1521  *  hdc: hdc to return the surface for
1522  *  Surface: Address to write the surface pointer to
1523  *
1524  * Returns:
1525  *  Always returns DD_OK because it's a stub
1526  *
1527  *****************************************************************************/
1528 static HRESULT WINAPI
1529 IDirectDrawImpl_GetSurfaceFromDC(IDirectDraw7 *iface,
1530                                  HDC hdc,
1531                                  IDirectDrawSurface7 **Surface)
1532 {
1533     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1534     FIXME("(%p)->(%p,%p): Stub!\n", This, hdc, Surface);
1535
1536     /* Implementation idea if needed: Loop through all surfaces and compare
1537      * their hdc with hdc. Implement it in WineD3D! */
1538     return DDERR_NOTFOUND;
1539 }
1540
1541 /*****************************************************************************
1542  * IDirectDraw7::RestoreAllSurfaces
1543  *
1544  * Calls the restore method of all surfaces
1545  *
1546  * Params:
1547  *
1548  * Returns:
1549  *  Always returns DD_OK because it's a stub
1550  *
1551  *****************************************************************************/
1552 static HRESULT WINAPI
1553 IDirectDrawImpl_RestoreAllSurfaces(IDirectDraw7 *iface)
1554 {
1555     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1556     FIXME("(%p): Stub\n", This);
1557
1558     /* This isn't hard to implement: Enumerate all WineD3D surfaces,
1559      * get their parent and call their restore method. Do not implement
1560      * it in WineD3D, as restoring a surface means re-creating the
1561      * WineD3DDSurface
1562      */
1563     return DD_OK;
1564 }
1565
1566 /*****************************************************************************
1567  * IDirectDraw7::StartModeTest
1568  *
1569  * Tests the specified video modes to update the system registry with
1570  * refresh rate information. StartModeTest starts the mode test,
1571  * EvaluateMode is used to fail or pass a mode. If EvaluateMode
1572  * isn't called within 15 seconds, the mode is failed automatically
1573  *
1574  * As refresh rates are handled by the X server, I don't think this
1575  * Method is important
1576  *
1577  * Params:
1578  *  Modes: An array of mode specifications
1579  *  NumModes: The number of modes in Modes
1580  *  Flags: Some flags...
1581  *
1582  * Returns:
1583  *  Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
1584  *  if no modes are passed, DDERR_INVALIDPARAMS is returned,
1585  *  otherwise DD_OK
1586  *
1587  *****************************************************************************/
1588 static HRESULT WINAPI
1589 IDirectDrawImpl_StartModeTest(IDirectDraw7 *iface,
1590                               SIZE *Modes,
1591                               DWORD NumModes,
1592                               DWORD Flags)
1593 {
1594     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
1595     WARN("(%p)->(%p, %d, %x): Semi-Stub, most likely harmless\n", This, Modes, NumModes, Flags);
1596
1597     /* This looks sane */
1598     if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
1599
1600     /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
1601      * As it is not, DDERR_TESTFINISHED is returned
1602      * (hopefully that's correct
1603      *
1604     if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
1605      * well, that value doesn't (yet) exist in the wine headers, so ignore it
1606      */
1607
1608     return DD_OK;
1609 }
1610
1611 /*****************************************************************************
1612  * IDirectDrawImpl_RecreateSurfacesCallback
1613  *
1614  * Enumeration callback for IDirectDrawImpl_RecreateAllSurfaces.
1615  * It re-recreates the WineD3DSurface. It's pretty straightforward
1616  *
1617  *****************************************************************************/
1618 HRESULT WINAPI
1619 IDirectDrawImpl_RecreateSurfacesCallback(IDirectDrawSurface7 *surf,
1620                                          DDSURFACEDESC2 *desc,
1621                                          void *Context)
1622 {
1623     IDirectDrawSurfaceImpl *surfImpl = ICOM_OBJECT(IDirectDrawSurfaceImpl,
1624                                                    IDirectDrawSurface7,
1625                                                    surf);
1626     IDirectDrawImpl *This = surfImpl->ddraw;
1627     IUnknown *Parent;
1628     IParentImpl *parImpl = NULL;
1629     IWineD3DSurface *wineD3DSurface;
1630     IWineD3DSwapChain *swapchain;
1631     HRESULT hr;
1632     void *tmp;
1633     IWineD3DClipper *clipper = NULL;
1634
1635     WINED3DSURFACE_DESC     Desc;
1636     WINED3DFORMAT           Format;
1637     WINED3DRESOURCETYPE     Type;
1638     DWORD                   Usage;
1639     WINED3DPOOL             Pool;
1640     UINT                    Size;
1641
1642     WINED3DMULTISAMPLE_TYPE MultiSampleType;
1643     DWORD                   MultiSampleQuality;
1644     UINT                    Width;
1645     UINT                    Height;
1646
1647     TRACE("(%p): Enumerated Surface %p\n", This, surfImpl);
1648
1649     /* For the enumeration */
1650     IDirectDrawSurface7_Release(surf);
1651
1652     if(surfImpl->ImplType == This->ImplType) return DDENUMRET_OK; /* Continue */
1653
1654     /* Get the objects */
1655     swapchain = surfImpl->wineD3DSwapChain;
1656     surfImpl->wineD3DSwapChain = NULL;
1657     wineD3DSurface = surfImpl->WineD3DSurface;
1658     IWineD3DSurface_GetParent(wineD3DSurface, &Parent);
1659     IUnknown_Release(Parent); /* For the getParent */
1660
1661     /* Is the parent an IParent interface? */
1662     if(IUnknown_QueryInterface(Parent, &IID_IParent, &tmp) == S_OK)
1663     {
1664         /* It is a IParent interface! */
1665         IUnknown_Release(Parent); /* For the QueryInterface */
1666         parImpl = ICOM_OBJECT(IParentImpl, IParent, Parent);
1667         /* Release the reference the parent interface is holding */
1668         IWineD3DSurface_Release(wineD3DSurface);
1669     }
1670
1671     /* get the clipper */
1672     IWineD3DSurface_GetClipper(wineD3DSurface, &clipper);
1673
1674     /* Get the surface properties */
1675     Desc.Format = &Format;
1676     Desc.Type = &Type;
1677     Desc.Usage = &Usage;
1678     Desc.Pool = &Pool;
1679     Desc.Size = &Size;
1680     Desc.MultiSampleType = &MultiSampleType;
1681     Desc.MultiSampleQuality = &MultiSampleQuality;
1682     Desc.Width = &Width;
1683     Desc.Height = &Height;
1684
1685     hr = IWineD3DSurface_GetDesc(wineD3DSurface, &Desc);
1686     if(hr != D3D_OK) return hr;
1687
1688     if(swapchain) {
1689         /* If there's a swapchain, it owns the IParent interface. Create a new one for the
1690          * new surface
1691          */
1692         parImpl = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*parImpl));
1693         ICOM_INIT_INTERFACE(parImpl, IParent, IParent_Vtbl);
1694         parImpl->ref = 1;
1695
1696         Parent = (IUnknown *) parImpl;
1697     }
1698
1699     /* Create the new surface */
1700     hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice,
1701                                       Width, Height, Format,
1702                                       TRUE /* Lockable */,
1703                                       FALSE /* Discard */,
1704                                       surfImpl->mipmap_level,
1705                                       &surfImpl->WineD3DSurface,
1706                                       Type,
1707                                       Usage,
1708                                       Pool,
1709                                       MultiSampleType,
1710                                       MultiSampleQuality,
1711                                       0 /* SharedHandle */,
1712                                       This->ImplType,
1713                                       Parent);
1714
1715     if(hr != D3D_OK)
1716         return hr;
1717
1718     IWineD3DSurface_SetClipper(surfImpl->WineD3DSurface, clipper);
1719
1720     /* Update the IParent if it exists */
1721     if(parImpl)
1722     {
1723         parImpl->child = (IUnknown *) surfImpl->WineD3DSurface;
1724         /* Add a reference for the IParent */
1725         IWineD3DSurface_AddRef(surfImpl->WineD3DSurface);
1726     }
1727     /* TODO: Copy the surface content, except for render targets */
1728
1729     /* If there's a swapchain, it owns the wined3d surfaces. So Destroy
1730      * the swapchain
1731      */
1732     if(swapchain) {
1733         /* The backbuffers have the swapchain set as well, but the primary
1734          * owns it and destroys it
1735          */
1736         if(surfImpl->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) {
1737             IWineD3DDevice_UninitGDI(This->wineD3DDevice, D3D7CB_DestroySwapChain);
1738         }
1739         surfImpl->isRenderTarget = FALSE;
1740     } else {
1741         if(IWineD3DSurface_Release(wineD3DSurface) == 0)
1742             TRACE("Surface released successful, next surface\n");
1743         else
1744             ERR("Something's still holding the old WineD3DSurface\n");
1745     }
1746
1747     surfImpl->ImplType = This->ImplType;
1748
1749     if(clipper)
1750     {
1751         IWineD3DClipper_Release(clipper);
1752     }
1753     return DDENUMRET_OK;
1754 }
1755
1756 /*****************************************************************************
1757  * IDirectDrawImpl_RecreateAllSurfaces
1758  *
1759  * A function, that converts all wineD3DSurfaces to the new implementation type
1760  * It enumerates all surfaces with IWineD3DDevice::EnumSurfaces, creates a
1761  * new WineD3DSurface, copies the content and releases the old surface
1762  *
1763  *****************************************************************************/
1764 static HRESULT
1765 IDirectDrawImpl_RecreateAllSurfaces(IDirectDrawImpl *This)
1766 {
1767     DDSURFACEDESC2 desc;
1768     TRACE("(%p): Switch to implementation %d\n", This, This->ImplType);
1769
1770     if(This->ImplType != SURFACE_OPENGL && This->d3d_initialized)
1771     {
1772         /* Should happen almost never */
1773         FIXME("(%p) Switching to non-opengl surfaces with d3d started. Is this a bug?\n", This);
1774         /* Shutdown d3d */
1775         IWineD3DDevice_Uninit3D(This->wineD3DDevice, D3D7CB_DestroyDepthStencilSurface, D3D7CB_DestroySwapChain);
1776     }
1777     /* Contrary: D3D starting is handled by the caller, because it knows the render target */
1778
1779     memset(&desc, 0, sizeof(desc));
1780     desc.dwSize = sizeof(desc);
1781
1782     return IDirectDraw7_EnumSurfaces(ICOM_INTERFACE(This, IDirectDraw7),
1783                                      0,
1784                                      &desc,
1785                                      This,
1786                                      IDirectDrawImpl_RecreateSurfacesCallback);
1787 }
1788
1789 /*****************************************************************************
1790  * D3D7CB_CreateSurface
1791  *
1792  * Callback function for IDirect3DDevice_CreateTexture. It searches for the
1793  * correct mipmap sublevel, and returns it to WineD3D.
1794  * The surfaces are created already by IDirectDraw7::CreateSurface
1795  *
1796  * Params:
1797  *  With, Height: With and height of the surface
1798  *  Format: The requested format
1799  *  Usage, Pool: D3DUSAGE and D3DPOOL of the surface
1800  *  level: The mipmap level
1801  *  Face: The cube map face type
1802  *  Surface: Pointer to pass the created surface back at
1803  *  SharedHandle: NULL
1804  *
1805  * Returns:
1806  *  D3D_OK
1807  *
1808  *****************************************************************************/
1809 static HRESULT WINAPI
1810 D3D7CB_CreateSurface(IUnknown *device,
1811                      IUnknown *pSuperior,
1812                      UINT Width, UINT Height,
1813                      WINED3DFORMAT Format,
1814                      DWORD Usage, WINED3DPOOL Pool, UINT level,
1815                      WINED3DCUBEMAP_FACES Face,
1816                      IWineD3DSurface **Surface,
1817                      HANDLE *SharedHandle)
1818 {
1819     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
1820     IDirectDrawSurfaceImpl *surf = NULL;
1821     int i = 0;
1822     DDSCAPS2 searchcaps = This->tex_root->surface_desc.ddsCaps;
1823     TRACE("(%p) call back. surf=%p. Face %d level %d\n", device, This->tex_root, Face, level);
1824
1825     searchcaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
1826     switch(Face)
1827     {
1828         case WINED3DCUBEMAP_FACE_POSITIVE_X:
1829             TRACE("Asked for positive x\n");
1830             if(searchcaps.dwCaps2 & DDSCAPS2_CUBEMAP) {
1831                 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
1832             }
1833             surf = This->tex_root; break;
1834         case WINED3DCUBEMAP_FACE_NEGATIVE_X:
1835             TRACE("Asked for negative x\n");
1836             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX; break;
1837         case WINED3DCUBEMAP_FACE_POSITIVE_Y:
1838             TRACE("Asked for positive y\n");
1839             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY; break;
1840         case WINED3DCUBEMAP_FACE_NEGATIVE_Y:
1841             TRACE("Asked for negative y\n");
1842             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY; break;
1843         case WINED3DCUBEMAP_FACE_POSITIVE_Z:
1844             TRACE("Asked for positive z\n");
1845             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ; break;
1846         case WINED3DCUBEMAP_FACE_NEGATIVE_Z:
1847             TRACE("Asked for negative z\n");
1848             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
1849         default: {ERR("Unexpected cube face\n");} /* Stupid compiler */
1850     }
1851
1852     if(!surf)
1853     {
1854         IDirectDrawSurface7 *attached;
1855         IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(This->tex_root, IDirectDrawSurface7),
1856                                                &searchcaps,
1857                                                &attached);
1858         surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attached);
1859         IDirectDrawSurface7_Release(attached);
1860     }
1861     if(!surf) ERR("root search surface not found\n");
1862
1863     /* Find the wanted mipmap. There are enough mipmaps in the chain */
1864     while(i < level)
1865     {
1866         IDirectDrawSurface7 *attached;
1867         IDirectDrawSurface7_GetAttachedSurface(ICOM_INTERFACE(surf, IDirectDrawSurface7),
1868                                                &searchcaps,
1869                                                &attached);
1870         if(!attached) ERR("Surface not found\n");
1871         surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, attached);
1872         IDirectDrawSurface7_Release(attached);
1873         i++;
1874     }
1875
1876     /* Return the surface */
1877     *Surface = surf->WineD3DSurface;
1878
1879     TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *Surface, surf);
1880     return D3D_OK;
1881 }
1882
1883 ULONG WINAPI D3D7CB_DestroySwapChain(IWineD3DSwapChain *pSwapChain) {
1884     IUnknown* swapChainParent;
1885     TRACE("(%p) call back\n", pSwapChain);
1886
1887     IWineD3DSwapChain_GetParent(pSwapChain, &swapChainParent);
1888     IUnknown_Release(swapChainParent);
1889     return IUnknown_Release(swapChainParent);
1890 }
1891
1892 ULONG WINAPI D3D7CB_DestroyDepthStencilSurface(IWineD3DSurface *pSurface) {
1893     IUnknown* surfaceParent;
1894     TRACE("(%p) call back\n", pSurface);
1895
1896     IWineD3DSurface_GetParent(pSurface, &surfaceParent);
1897     IUnknown_Release(surfaceParent);
1898     return IUnknown_Release(surfaceParent);
1899 }
1900
1901 /*****************************************************************************
1902  * IDirectDrawImpl_CreateNewSurface
1903  *
1904  * A helper function for IDirectDraw7::CreateSurface. It creates a new surface
1905  * with the passed parameters.
1906  *
1907  * Params:
1908  *  DDSD: Description of the surface to create
1909  *  Surf: Address to store the interface pointer at
1910  *
1911  * Returns:
1912  *  DD_OK on success
1913  *
1914  *****************************************************************************/
1915 static HRESULT WINAPI
1916 IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This,
1917                                  DDSURFACEDESC2 *pDDSD,
1918                                  IDirectDrawSurfaceImpl **ppSurf,
1919                                  UINT level)
1920 {
1921     HRESULT hr;
1922     UINT Width = 0, Height = 0;
1923     WINED3DFORMAT Format = WINED3DFMT_UNKNOWN;
1924     WINED3DRESOURCETYPE ResType = WINED3DRTYPE_SURFACE;
1925     DWORD Usage = 0;
1926     WINED3DSURFTYPE ImplType = This->ImplType;
1927     WINED3DSURFACE_DESC Desc;
1928     IUnknown *Parent;
1929     IParentImpl *parImpl = NULL;
1930     WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
1931
1932     /* Dummies for GetDesc */
1933     WINED3DPOOL dummy_d3dpool;
1934     WINED3DMULTISAMPLE_TYPE dummy_mst;
1935     UINT dummy_uint;
1936     DWORD dummy_dword;
1937
1938     if (TRACE_ON(ddraw))
1939     {
1940         TRACE(" (%p) Requesting surface desc :\n", This);
1941         DDRAW_dump_surface_desc(pDDSD);
1942     }
1943
1944     /* Select the surface type, if it wasn't choosen yet */
1945     if(ImplType == SURFACE_UNKNOWN)
1946     {
1947         /* Use GL Surfaces if a D3DDEVICE Surface is requested */
1948         if(pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
1949         {
1950             TRACE("(%p) Choosing GL surfaces because a 3DDEVICE Surface was requested\n", This);
1951             ImplType = SURFACE_OPENGL;
1952         }
1953
1954         /* Otherwise use GDI surfaces for now */
1955         else
1956         {
1957             TRACE("(%p) Choosing GDI surfaces for 2D rendering\n", This);
1958             ImplType = SURFACE_GDI;
1959         }
1960
1961         /* Policy if all surface implementations are available:
1962          * First, check if a default type was set with winecfg. If not,
1963          * try Xrender surfaces, and use them if they work. Next, check if
1964          * accelerated OpenGL is available, and use GL surfaces in this
1965          * case. If all else fails, use GDI surfaces. If a 3DDEVICE surface
1966          * was created, always use OpenGL surfaces.
1967          *
1968          * (Note: Xrender surfaces are not implemented for now, the
1969          * unaccelerated implementation uses GDI to render in Software)
1970          */
1971
1972         /* Store the type. If it needs to be changed, all WineD3DSurfaces have to
1973          * be re-created. This could be done with IDirectDrawSurface7::Restore
1974          */
1975         This->ImplType = ImplType;
1976     }
1977     else
1978     {
1979          if((pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE ) && 
1980             (This->ImplType != SURFACE_OPENGL ) && DefaultSurfaceType == SURFACE_UNKNOWN)
1981         {
1982             /* We have to change to OpenGL,
1983              * and re-create all WineD3DSurfaces
1984              */
1985             ImplType = SURFACE_OPENGL;
1986             This->ImplType = ImplType;
1987             TRACE("(%p) Re-creating all surfaces\n", This);
1988             IDirectDrawImpl_RecreateAllSurfaces(This);
1989             TRACE("(%p) Done recreating all surfaces\n", This);
1990         }
1991         else if(This->ImplType != SURFACE_OPENGL && pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE)
1992         {
1993             WARN("The application requests a 3D capable surface, but a non-opengl surface was set in the registry\n");
1994             /* Do not fail surface creation, only fail 3D device creation */
1995         }
1996     }
1997
1998     if (!(pDDSD->ddsCaps.dwCaps & (DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY)) &&
1999         !((pDDSD->ddsCaps.dwCaps & DDSCAPS_TEXTURE) && (pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)) )
2000     {
2001         /* Tests show surfaces without memory flags get these flags added right after creation. */
2002         pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
2003     }
2004     /* Get the correct wined3d usage */
2005     if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE |
2006                                  DDSCAPS_BACKBUFFER     |
2007                                  DDSCAPS_3DDEVICE       ) )
2008     {
2009         Usage |= WINED3DUSAGE_RENDERTARGET;
2010
2011         pDDSD->ddsCaps.dwCaps |= DDSCAPS_VISIBLE;
2012     }
2013     if (pDDSD->ddsCaps.dwCaps & (DDSCAPS_OVERLAY))
2014     {
2015         Usage |= WINED3DUSAGE_OVERLAY;
2016     }
2017     if(This->depthstencil || (pDDSD->ddsCaps.dwCaps & DDSCAPS_ZBUFFER) )
2018     {
2019         /* The depth stencil creation callback sets this flag.
2020          * Set the WineD3D usage to let it know that it's a depth
2021          * Stencil surface.
2022          */
2023         Usage |= WINED3DUSAGE_DEPTHSTENCIL;
2024     }
2025     if(pDDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
2026     {
2027         Pool = WINED3DPOOL_SYSTEMMEM;
2028     }
2029     else if(pDDSD->ddsCaps.dwCaps2 & DDSCAPS2_TEXTUREMANAGE)
2030     {
2031         Pool = WINED3DPOOL_MANAGED;
2032         /* Managed textures have the system memory flag set */
2033         pDDSD->ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;
2034     }
2035     else if(pDDSD->ddsCaps.dwCaps & DDSCAPS_VIDEOMEMORY)
2036     {
2037         /* Videomemory adds localvidmem, this is mutually exclusive with systemmemory
2038          * and texturemanage
2039          */
2040         pDDSD->ddsCaps.dwCaps |= DDSCAPS_LOCALVIDMEM;
2041     }
2042
2043     Format = PixelFormat_DD2WineD3D(&pDDSD->u4.ddpfPixelFormat);
2044     if(Format == WINED3DFMT_UNKNOWN)
2045     {
2046         ERR("Unsupported / Unknown pixelformat\n");
2047         return DDERR_INVALIDPIXELFORMAT;
2048     }
2049
2050     /* Create the Surface object */
2051     *ppSurf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawSurfaceImpl));
2052     if(!*ppSurf)
2053     {
2054         ERR("(%p) Error allocating memory for a surface\n", This);
2055         return DDERR_OUTOFVIDEOMEMORY;
2056     }
2057     ICOM_INIT_INTERFACE(*ppSurf, IDirectDrawSurface7, IDirectDrawSurface7_Vtbl);
2058     ICOM_INIT_INTERFACE(*ppSurf, IDirectDrawSurface3, IDirectDrawSurface3_Vtbl);
2059     ICOM_INIT_INTERFACE(*ppSurf, IDirectDrawGammaControl, IDirectDrawGammaControl_Vtbl);
2060     ICOM_INIT_INTERFACE(*ppSurf, IDirect3DTexture2, IDirect3DTexture2_Vtbl);
2061     ICOM_INIT_INTERFACE(*ppSurf, IDirect3DTexture, IDirect3DTexture1_Vtbl);
2062     (*ppSurf)->ref = 1;
2063     (*ppSurf)->version = 7;
2064     (*ppSurf)->ddraw = This;
2065     (*ppSurf)->surface_desc.dwSize = sizeof(DDSURFACEDESC2);
2066     (*ppSurf)->surface_desc.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
2067     DD_STRUCT_COPY_BYSIZE(&(*ppSurf)->surface_desc, pDDSD);
2068
2069     /* Surface attachments */
2070     (*ppSurf)->next_attached = NULL;
2071     (*ppSurf)->first_attached = *ppSurf;
2072
2073     /* Needed to re-create the surface on an implementation change */
2074     (*ppSurf)->ImplType = ImplType;
2075
2076     /* For D3DDevice creation */
2077     (*ppSurf)->isRenderTarget = FALSE;
2078
2079     /* A trace message for debugging */
2080     TRACE("(%p) Created IDirectDrawSurface implementation structure at %p\n", This, *ppSurf);
2081
2082     if(pDDSD->ddsCaps.dwCaps & ( DDSCAPS_PRIMARYSURFACE | DDSCAPS_TEXTURE | DDSCAPS_3DDEVICE) )
2083     {
2084         /* Render targets and textures need a IParent interface,
2085          * because WineD3D will destroy them when the swapchain
2086          * is released
2087          */
2088         parImpl = HeapAlloc(GetProcessHeap(), 0, sizeof(IParentImpl));
2089         if(!parImpl)
2090         {
2091             ERR("Out of memory when allocating memory for a IParent implementation\n");
2092             return DDERR_OUTOFMEMORY;
2093         }
2094         parImpl->ref = 1;
2095         ICOM_INIT_INTERFACE(parImpl, IParent, IParent_Vtbl);
2096         Parent = (IUnknown *) ICOM_INTERFACE(parImpl, IParent);
2097         TRACE("Using IParent interface %p as parent\n", parImpl);
2098     }
2099     else
2100     {
2101         /* Use the surface as parent */
2102         Parent = (IUnknown *) ICOM_INTERFACE(*ppSurf, IDirectDrawSurface7);
2103         TRACE("Using Surface interface %p as parent\n", *ppSurf);
2104     }
2105
2106     /* Now create the WineD3D Surface */
2107     hr = IWineD3DDevice_CreateSurface(This->wineD3DDevice,
2108                                       pDDSD->dwWidth,
2109                                       pDDSD->dwHeight,
2110                                       Format,
2111                                       TRUE /* Lockable */,
2112                                       FALSE /* Discard */,
2113                                       level,
2114                                       &(*ppSurf)->WineD3DSurface,
2115                                       ResType, Usage,
2116                                       Pool,
2117                                       WINED3DMULTISAMPLE_NONE,
2118                                       0 /* MultiSampleQuality */,
2119                                       0 /* SharedHandle */,
2120                                       ImplType,
2121                                       Parent);
2122
2123     if(hr != D3D_OK)
2124     {
2125         ERR("IWineD3DDevice::CreateSurface failed. hr = %08x\n", hr);
2126         return hr;
2127     }
2128
2129     /* Set the child of the parent implementation if it exists */
2130     if(parImpl)
2131     {
2132         parImpl->child = (IUnknown *) (*ppSurf)->WineD3DSurface;
2133         /* The IParent releases the WineD3DSurface, and
2134          * the ddraw surface does that too. Hold a reference
2135          */
2136         IWineD3DSurface_AddRef((*ppSurf)->WineD3DSurface);
2137     }
2138
2139     /* Increase the surface counter, and attach the surface */
2140     InterlockedIncrement(&This->surfaces);
2141     list_add_head(&This->surface_list, &(*ppSurf)->surface_list_entry);
2142
2143     /* Here we could store all created surfaces in the DirectDrawImpl structure,
2144      * But this could also be delegated to WineDDraw, as it keeps track of all its
2145      * resources. Not implemented for now, as there are more important things ;)
2146      */
2147
2148     /* Get the pixel format of the WineD3DSurface and store it.
2149      * Don't use the Format choosen above, WineD3D might have
2150      * changed it
2151      */
2152     Desc.Format = &Format;
2153     Desc.Type = &ResType;
2154     Desc.Usage = &Usage;
2155     Desc.Pool = &dummy_d3dpool;
2156     Desc.Size = &dummy_uint;
2157     Desc.MultiSampleType = &dummy_mst;
2158     Desc.MultiSampleQuality = &dummy_dword;
2159     Desc.Width = &Width;
2160     Desc.Height = &Height;
2161
2162     (*ppSurf)->surface_desc.dwFlags |= DDSD_PIXELFORMAT;
2163     hr = IWineD3DSurface_GetDesc((*ppSurf)->WineD3DSurface, &Desc);
2164     if(hr != D3D_OK)
2165     {
2166         ERR("IWineD3DSurface::GetDesc failed\n");
2167         IDirectDrawSurface7_Release( (IDirectDrawSurface7 *) *ppSurf);
2168         return hr;
2169     }
2170
2171     if(Format == WINED3DFMT_UNKNOWN)
2172     {
2173         FIXME("IWineD3DSurface::GetDesc returned WINED3DFMT_UNKNOWN\n");
2174     }
2175     PixelFormat_WineD3DtoDD( &(*ppSurf)->surface_desc.u4.ddpfPixelFormat, Format);
2176
2177     /* Anno 1602 stores the pitch right after surface creation, so make sure it's there.
2178      * I can't LockRect() the surface here because if OpenGL surfaces are in use, the
2179      * WineD3DDevice might not be usable for 3D yet, so an extra method was created.
2180      * TODO: Test other fourcc formats
2181      */
2182     if(Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
2183        Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5)
2184     {
2185         (*ppSurf)->surface_desc.dwFlags |= DDSD_LINEARSIZE;
2186         if(Format == WINED3DFMT_DXT1)
2187         {
2188             (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height) / 2;
2189         }
2190         else
2191         {
2192             (*ppSurf)->surface_desc.u1.dwLinearSize = max(4, Width) * max(4, Height);
2193         }
2194     }
2195     else
2196     {
2197         (*ppSurf)->surface_desc.dwFlags |= DDSD_PITCH;
2198         (*ppSurf)->surface_desc.u1.lPitch = IWineD3DSurface_GetPitch((*ppSurf)->WineD3DSurface);
2199     }
2200
2201     /* Application passed a color key? Set it! */
2202     if(pDDSD->dwFlags & DDSD_CKDESTOVERLAY)
2203     {
2204         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2205                                     DDCKEY_DESTOVERLAY,
2206                                     (WINEDDCOLORKEY *) &pDDSD->u3.ddckCKDestOverlay);
2207     }
2208     if(pDDSD->dwFlags & DDSD_CKDESTBLT)
2209     {
2210         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2211                                     DDCKEY_DESTBLT,
2212                                     (WINEDDCOLORKEY *) &pDDSD->ddckCKDestBlt);
2213     }
2214     if(pDDSD->dwFlags & DDSD_CKSRCOVERLAY)
2215     {
2216         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2217                                     DDCKEY_SRCOVERLAY,
2218                                     (WINEDDCOLORKEY *) &pDDSD->ddckCKSrcOverlay);
2219     }
2220     if(pDDSD->dwFlags & DDSD_CKSRCBLT)
2221     {
2222         IWineD3DSurface_SetColorKey((*ppSurf)->WineD3DSurface,
2223                                     DDCKEY_SRCBLT,
2224                                     (WINEDDCOLORKEY *) &pDDSD->ddckCKSrcBlt);
2225     }
2226     if ( pDDSD->dwFlags & DDSD_LPSURFACE)
2227     {
2228         hr = IWineD3DSurface_SetMem((*ppSurf)->WineD3DSurface, pDDSD->lpSurface);
2229         if(hr != WINED3D_OK)
2230         {
2231             /* No need for a trace here, wined3d does that for us */
2232             IDirectDrawSurface7_Release(ICOM_INTERFACE((*ppSurf), IDirectDrawSurface7));
2233             return hr;
2234         }
2235     }
2236
2237     return DD_OK;
2238 }
2239 /*****************************************************************************
2240  * CreateAdditionalSurfaces
2241  *
2242  * Creates a new mipmap chain.
2243  *
2244  * Params:
2245  *  root: Root surface to attach the newly created chain to
2246  *  count: number of surfaces to create
2247  *  DDSD: Description of the surface. Intentionally not a pointer to avoid side
2248  *        effects on the caller
2249  *  CubeFaceRoot: Whether the new surface is a root of a cube map face. This
2250  *                creates an additional surface without the mipmapping flags
2251  *
2252  *****************************************************************************/
2253 static HRESULT
2254 CreateAdditionalSurfaces(IDirectDrawImpl *This,
2255                          IDirectDrawSurfaceImpl *root,
2256                          UINT count,
2257                          DDSURFACEDESC2 DDSD,
2258                          BOOL CubeFaceRoot)
2259 {
2260     UINT i, j, level = 0;
2261     HRESULT hr;
2262     IDirectDrawSurfaceImpl *last = root;
2263
2264     for(i = 0; i < count; i++)
2265     {
2266         IDirectDrawSurfaceImpl *object2 = NULL;
2267
2268         /* increase the mipmap level, but only if a mipmap is created
2269          * In this case, also halve the size
2270          */
2271         if(DDSD.ddsCaps.dwCaps & DDSCAPS_MIPMAP && !CubeFaceRoot)
2272         {
2273             level++;
2274             if(DDSD.dwWidth > 1) DDSD.dwWidth /= 2;
2275             if(DDSD.dwHeight > 1) DDSD.dwHeight /= 2;
2276             /* Set the mipmap sublevel flag according to msdn */
2277             DDSD.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
2278         }
2279         else
2280         {
2281             DDSD.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2282         }
2283         CubeFaceRoot = FALSE;
2284
2285         hr = IDirectDrawImpl_CreateNewSurface(This,
2286                                               &DDSD,
2287                                               &object2,
2288                                               level);
2289         if(hr != DD_OK)
2290         {
2291             return hr;
2292         }
2293
2294         /* Add the new surface to the complex attachment array */
2295         for(j = 0; j < MAX_COMPLEX_ATTACHED; j++)
2296         {
2297             if(last->complex_array[j]) continue;
2298             last->complex_array[j] = object2;
2299             break;
2300         }
2301         last = object2;
2302
2303         /* Remove the (possible) back buffer cap from the new surface description,
2304          * because only one surface in the flipping chain is a back buffer, one
2305          * is a front buffer, the others are just primary surfaces.
2306          */
2307         DDSD.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
2308     }
2309     return DD_OK;
2310 }
2311
2312 /*****************************************************************************
2313  * IDirectDraw7::CreateSurface
2314  *
2315  * Creates a new IDirectDrawSurface object and returns its interface.
2316  *
2317  * The surface connections with wined3d are a bit tricky. Basically it works
2318  * like this:
2319  *
2320  * |------------------------|               |-----------------|
2321  * | DDraw surface          |               | WineD3DSurface  |
2322  * |                        |               |                 |
2323  * |        WineD3DSurface  |-------------->|                 |
2324  * |        Child           |<------------->| Parent          |
2325  * |------------------------|               |-----------------|
2326  *
2327  * The DDraw surface is the parent of the wined3d surface, and it releases
2328  * the WineD3DSurface when the ddraw surface is destroyed.
2329  *
2330  * However, for all surfaces which can be in a container in WineD3D,
2331  * we have to do this. These surfaces are usually complex surfaces,
2332  * so this concerns primary surfaces with a front and a back buffer,
2333  * and textures.
2334  *
2335  * |------------------------|               |-----------------|
2336  * | DDraw surface          |               | Container       |
2337  * |                        |               |                 |
2338  * |                  Child |<------------->| Parent          |
2339  * |                Texture |<------------->|                 |
2340  * |         WineD3DSurface |<----|         |          Levels |<--|
2341  * | Complex connection     |     |         |                 |   |
2342  * |------------------------|     |         |-----------------|   |
2343  *  ^                             |                               |
2344  *  |                             |                               |
2345  *  |                             |                               |
2346  *  |    |------------------|     |         |-----------------|   |
2347  *  |    | IParent          |     |-------->| WineD3DSurface  |   |
2348  *  |    |                  |               |                 |   |
2349  *  |    |            Child |<------------->| Parent          |   |
2350  *  |    |                  |               |       Container |<--|
2351  *  |    |------------------|               |-----------------|   |
2352  *  |                                                             |
2353  *  |   |----------------------|                                  |
2354  *  |   | DDraw surface 2      |                                  |
2355  *  |   |                      |                                  |
2356  *  |<->| Complex root   Child |                                  |
2357  *  |   |              Texture |                                  |
2358  *  |   |       WineD3DSurface |<----|                            |
2359  *  |   |----------------------|     |                            |
2360  *  |                                |                            |
2361  *  |    |---------------------|     |      |-----------------|   |
2362  *  |    | IParent             |     |----->| WineD3DSurface  |   |
2363  *  |    |                     |            |                 |   |
2364  *  |    |               Child |<---------->| Parent          |   |
2365  *  |    |---------------------|            |       Container |<--|
2366  *  |                                       |-----------------|   |
2367  *  |                                                             |
2368  *  |             ---More surfaces can follow---                  |
2369  *
2370  * The reason is that the IWineD3DSwapchain(render target container)
2371  * and the IWineD3DTexure(Texture container) release the parents
2372  * of their surface's children, but by releasing the complex root
2373  * the surfaces which are complexly attached to it are destroyed
2374  * too. See IDirectDrawSurface::Release for a more detailed
2375  * explanation.
2376  *
2377  * Params:
2378  *  DDSD: Description of the surface to create
2379  *  Surf: Address to store the interface pointer at
2380  *  UnkOuter: Basically for aggregation support, but ddraw doesn't support
2381  *            aggregation, so it has to be NULL
2382  *
2383  * Returns:
2384  *  DD_OK on success
2385  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
2386  *  DDERR_* if an error occurs
2387  *
2388  *****************************************************************************/
2389 static HRESULT WINAPI
2390 IDirectDrawImpl_CreateSurface(IDirectDraw7 *iface,
2391                               DDSURFACEDESC2 *DDSD,
2392                               IDirectDrawSurface7 **Surf,
2393                               IUnknown *UnkOuter)
2394 {
2395     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
2396     IDirectDrawSurfaceImpl *object = NULL;
2397     HRESULT hr;
2398     LONG extra_surfaces = 0;
2399     DDSURFACEDESC2 desc2;
2400     WINED3DDISPLAYMODE Mode;
2401
2402     TRACE("(%p)->(%p,%p,%p)\n", This, DDSD, Surf, UnkOuter);
2403
2404     /* Some checks before we start */
2405     if (TRACE_ON(ddraw))
2406     {
2407         TRACE(" (%p) Requesting surface desc :\n", This);
2408         DDRAW_dump_surface_desc(DDSD);
2409     }
2410     EnterCriticalSection(&ddraw_cs);
2411
2412     if (UnkOuter != NULL)
2413     {
2414         FIXME("(%p) : outer != NULL?\n", This);
2415         LeaveCriticalSection(&ddraw_cs);
2416         return CLASS_E_NOAGGREGATION; /* unchecked */
2417     }
2418
2419     if (Surf == NULL)
2420     {
2421         FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", This);
2422         LeaveCriticalSection(&ddraw_cs);
2423         return E_POINTER; /* unchecked */
2424     }
2425
2426     if (!(DDSD->dwFlags & DDSD_CAPS))
2427     {
2428         /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
2429         DDSD->dwFlags |= DDSD_CAPS;
2430     }
2431
2432     if (DDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD)
2433     {
2434         /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */
2435         DDSD->dwFlags &= ~DDSD_LPSURFACE;
2436     }
2437
2438     if ((DDSD->dwFlags & DDSD_LPSURFACE) && (DDSD->lpSurface == NULL))
2439     {
2440         /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */
2441         WARN("(%p) Null surface pointer specified, ignore it!\n", This);
2442         DDSD->dwFlags &= ~DDSD_LPSURFACE;
2443     }
2444
2445     if((DDSD->ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE)) == (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE) &&
2446        !(This->cooperative_level & DDSCL_EXCLUSIVE))
2447     {
2448         TRACE("(%p): Attempt to create a flipable primary surface without DDSCL_EXCLUSIVE set\n", This);
2449         *Surf = NULL;
2450         LeaveCriticalSection(&ddraw_cs);
2451         return DDERR_NOEXCLUSIVEMODE;
2452     }
2453
2454     if(DDSD->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER)) {
2455         WARN("Application tried to create an explicit front or back buffer\n");
2456         LeaveCriticalSection(&ddraw_cs);
2457         return DDERR_INVALIDCAPS;
2458     }
2459     /* Check cube maps but only if the size includes them */
2460     if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
2461     {
2462         if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES &&
2463            !(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
2464         {
2465             WARN("Cube map faces requested without cube map flag\n");
2466             LeaveCriticalSection(&ddraw_cs);
2467             return DDERR_INVALIDCAPS;
2468         }
2469         if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
2470            (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) == 0)
2471         {
2472             WARN("Cube map without faces requested\n");
2473             LeaveCriticalSection(&ddraw_cs);
2474             return DDERR_INVALIDPARAMS;
2475         }
2476
2477         /* Quick tests confirm those can be created, but we don't do that yet */
2478         if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
2479            (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) != DDSCAPS2_CUBEMAP_ALLFACES)
2480         {
2481             FIXME("Partial cube maps not supported yet\n");
2482         }
2483     }
2484
2485     /* According to the msdn this flag is ignored by CreateSurface */
2486     if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
2487         DDSD->ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2488
2489     /* Modify some flags */
2490     memset(&desc2, 0, sizeof(desc2));
2491     desc2.dwSize = sizeof(desc2);   /* For the struct copy */
2492     DD_STRUCT_COPY_BYSIZE(&desc2, DDSD);
2493     desc2.dwSize = sizeof(desc2);   /* To override a possibly smaller size */
2494     desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); /* Just to be sure */
2495
2496     /* Get the video mode from WineD3D - we will need it */
2497     hr = IWineD3DDevice_GetDisplayMode(This->wineD3DDevice,
2498                                        0, /* Swapchain 0 */
2499                                        &Mode);
2500     if(FAILED(hr))
2501     {
2502         ERR("Failed to read display mode from wined3d\n");
2503         switch(This->orig_bpp)
2504         {
2505             case 8:
2506                 Mode.Format = WINED3DFMT_P8;
2507                 break;
2508
2509             case 15:
2510                 Mode.Format = WINED3DFMT_X1R5G5B5;
2511                 break;
2512
2513             case 16:
2514                 Mode.Format = WINED3DFMT_R5G6B5;
2515                 break;
2516
2517             case 24:
2518                 Mode.Format = WINED3DFMT_R8G8B8;
2519                 break;
2520
2521             case 32:
2522                 Mode.Format = WINED3DFMT_X8R8G8B8;
2523                 break;
2524         }
2525         Mode.Width = This->orig_width;
2526         Mode.Height = This->orig_height;
2527     }
2528
2529     /* No pixelformat given? Use the current screen format */
2530     if(!(desc2.dwFlags & DDSD_PIXELFORMAT))
2531     {
2532         desc2.dwFlags |= DDSD_PIXELFORMAT;
2533         desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT);
2534
2535         /* Wait: It could be a Z buffer */
2536         if(desc2.ddsCaps.dwCaps & DDSCAPS_ZBUFFER)
2537         {
2538             switch(desc2.u2.dwMipMapCount) /* Who had this glorious idea? */
2539             {
2540                 case 15:
2541                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D15S1);
2542                     break;
2543                 case 16:
2544                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D16);
2545                     break;
2546                 case 24:
2547                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D24X8);
2548                     break;
2549                 case 32:
2550                     PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, WINED3DFMT_D32);
2551                     break;
2552                 default:
2553                     ERR("Unknown Z buffer bit depth\n");
2554             }
2555         }
2556         else
2557         {
2558             PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, Mode.Format);
2559         }
2560     }
2561
2562     /* No Width or no Height? Use the original screen size
2563      */
2564     if(!(desc2.dwFlags & DDSD_WIDTH) ||
2565        !(desc2.dwFlags & DDSD_HEIGHT) )
2566     {
2567         /* Invalid for non-render targets */
2568         if(!(desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
2569         {
2570             WARN("Creating a non-Primary surface without Width or Height info, returning DDERR_INVALIDPARAMS\n");
2571             *Surf = NULL;
2572             LeaveCriticalSection(&ddraw_cs);
2573             return DDERR_INVALIDPARAMS;
2574         }
2575
2576         desc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
2577         desc2.dwWidth = Mode.Width;
2578         desc2.dwHeight = Mode.Height;
2579     }
2580
2581     /* Mipmap count fixes */
2582     if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2583     {
2584         if(desc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
2585         {
2586             if(desc2.dwFlags & DDSD_MIPMAPCOUNT)
2587             {
2588                 /* Mipmap count is given, should not be 0 */
2589                 if( desc2.u2.dwMipMapCount == 0 )
2590                 {
2591                     LeaveCriticalSection(&ddraw_cs);
2592                     return DDERR_INVALIDPARAMS;
2593                 }
2594             }
2595             else
2596             {
2597                 /* Undocumented feature: Create sublevels until
2598                  * either the width or the height is 1
2599                  */
2600                 DWORD min = desc2.dwWidth < desc2.dwHeight ?
2601                             desc2.dwWidth : desc2.dwHeight;
2602                 desc2.u2.dwMipMapCount = 0;
2603                 while( min )
2604                 {
2605                     desc2.u2.dwMipMapCount += 1;
2606                     min >>= 1;
2607                 }
2608             }
2609         }
2610         else
2611         {
2612             /* Not-complex mipmap -> Mipmapcount = 1 */
2613             desc2.u2.dwMipMapCount = 1;
2614         }
2615         extra_surfaces = desc2.u2.dwMipMapCount - 1;
2616
2617         /* There's a mipmap count in the created surface in any case */
2618         desc2.dwFlags |= DDSD_MIPMAPCOUNT;
2619     }
2620     /* If no mipmap is given, the texture has only one level */
2621
2622     /* The first surface is a front buffer, the back buffer is created afterwards */
2623     if( (desc2.dwFlags & DDSD_CAPS) && (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) )
2624     {
2625         desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER;
2626     }
2627
2628     /* The root surface in a cube map is positive x */
2629     if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2630     {
2631         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
2632         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
2633     }
2634
2635     /* Create the first surface */
2636     hr = IDirectDrawImpl_CreateNewSurface(This, &desc2, &object, 0);
2637     if( hr != DD_OK)
2638     {
2639         ERR("IDirectDrawImpl_CreateNewSurface failed with %08x\n", hr);
2640         LeaveCriticalSection(&ddraw_cs);
2641         return hr;
2642     }
2643     object->is_complex_root = TRUE;
2644
2645     *Surf = ICOM_INTERFACE(object, IDirectDrawSurface7);
2646
2647     /* Create Additional surfaces if necessary
2648      * This applies to Primary surfaces which have a back buffer count
2649      * set, but not to mipmap textures. In case of Mipmap textures,
2650      * wineD3D takes care of the creation of additional surfaces
2651      */
2652     if(DDSD->dwFlags & DDSD_BACKBUFFERCOUNT)
2653     {
2654         extra_surfaces = DDSD->dwBackBufferCount;
2655         desc2.ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER; /* It's not a front buffer */
2656         desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
2657     }
2658
2659     hr = DD_OK;
2660     if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2661     {
2662         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
2663         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEZ;
2664         hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2665         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEZ;
2666         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEZ;
2667         hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2668         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEZ;
2669         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEY;
2670         hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2671         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEY;
2672         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEY;
2673         hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2674         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEY;
2675         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEX;
2676         hr |= CreateAdditionalSurfaces(This, object, extra_surfaces + 1, desc2, TRUE);
2677         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEX;
2678         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
2679     }
2680
2681     hr |= CreateAdditionalSurfaces(This, object, extra_surfaces, desc2, FALSE);
2682     if(hr != DD_OK)
2683     {
2684         /* This destroys and possibly created surfaces too */
2685         IDirectDrawSurface_Release( ICOM_INTERFACE(object, IDirectDrawSurface7) );
2686         LeaveCriticalSection(&ddraw_cs);
2687         return hr;
2688     }
2689
2690     /* If the implementation is OpenGL and there's no d3ddevice, attach a d3ddevice
2691      * But attach the d3ddevice only if the currently created surface was
2692      * a primary surface (2D app in 3D mode) or a 3DDEVICE surface (3D app)
2693      * The only case I can think of where this doesn't apply is when a
2694      * 2D app was configured by the user to run with OpenGL and it didn't create
2695      * the render target as first surface. In this case the render target creation
2696      * will cause the 3D init.
2697      */
2698     if( (This->ImplType == SURFACE_OPENGL) && !(This->d3d_initialized) &&
2699         desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE) )
2700     {
2701         IDirectDrawSurfaceImpl *target = object, *surface;
2702         struct list *entry;
2703
2704         /* Search for the primary to use as render target */
2705         LIST_FOR_EACH(entry, &This->surface_list)
2706         {
2707             surface = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
2708             if((surface->surface_desc.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER)) ==
2709                (DDSCAPS_PRIMARYSURFACE | DDSCAPS_FRONTBUFFER))
2710             {
2711                 /* found */
2712                 target = surface;
2713                 TRACE("Using primary %p as render target\n", target);
2714                 break;
2715             }
2716         }
2717
2718         TRACE("(%p) Attaching a D3DDevice, rendertarget = %p\n", This, target);
2719         hr = IDirectDrawImpl_AttachD3DDevice(This, target);
2720         if(hr != D3D_OK)
2721         {
2722             IDirectDrawSurfaceImpl *release_surf;
2723             ERR("IDirectDrawImpl_AttachD3DDevice failed, hr = %x\n", hr);
2724             *Surf = NULL;
2725
2726             /* The before created surface structures are in an incomplete state here.
2727              * WineD3D holds the reference on the IParents, and it released them on the failure
2728              * already. So the regular release method implementation would fail on the attempt
2729              * to destroy either the IParents or the swapchain. So free the surface here.
2730              * The surface structure here is a list, not a tree, because onscreen targets
2731              * cannot be cube textures
2732              */
2733             while(object)
2734             {
2735                 release_surf = object;
2736                 object = object->complex_array[0];
2737                 IDirectDrawSurfaceImpl_Destroy(release_surf);
2738             }
2739             LeaveCriticalSection(&ddraw_cs);
2740             return hr;
2741         }
2742     } else if(!(This->d3d_initialized) && desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) {
2743         IDirectDrawImpl_CreateGDISwapChain(This, object);
2744     }
2745
2746     /* Addref the ddraw interface to keep an reference for each surface */
2747     IDirectDraw7_AddRef(iface);
2748     object->ifaceToRelease = (IUnknown *) iface;
2749
2750     /* Create a WineD3DTexture if a texture was requested */
2751     if(desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
2752     {
2753         UINT levels;
2754         WINED3DFORMAT Format;
2755         WINED3DPOOL Pool = WINED3DPOOL_DEFAULT;
2756
2757         This->tex_root = object;
2758
2759         if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2760         {
2761             /* a mipmap is created, create enough levels */
2762             levels = desc2.u2.dwMipMapCount;
2763         }
2764         else
2765         {
2766             /* No mipmap is created, create one level */
2767             levels = 1;
2768         }
2769
2770         /* DDSCAPS_SYSTEMMEMORY textures are in WINED3DPOOL_SYSTEMMEM */
2771         if(DDSD->ddsCaps.dwCaps & DDSCAPS_SYSTEMMEMORY)
2772         {
2773             Pool = WINED3DPOOL_SYSTEMMEM;
2774         }
2775         /* Should I forward the MANAGED cap to the managed pool ? */
2776
2777         /* Get the format. It's set already by CreateNewSurface */
2778         Format = PixelFormat_DD2WineD3D(&object->surface_desc.u4.ddpfPixelFormat);
2779
2780         /* The surfaces are already created, the callback only
2781          * passes the IWineD3DSurface to WineD3D
2782          */
2783         if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2784         {
2785             hr = IWineD3DDevice_CreateCubeTexture(This->wineD3DDevice,
2786                                                   DDSD->dwWidth, /* Edgelength */
2787                                                   levels,
2788                                                   0, /* usage */
2789                                                   Format,
2790                                                   Pool,
2791                                                   (IWineD3DCubeTexture **) &object->wineD3DTexture,
2792                                                   0, /* SharedHandle */
2793                                                   (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
2794                                                   D3D7CB_CreateSurface);
2795         }
2796         else
2797         {
2798             hr = IWineD3DDevice_CreateTexture(This->wineD3DDevice,
2799                                               DDSD->dwWidth, DDSD->dwHeight,
2800                                               levels, /* MipMapCount = Levels */
2801                                               0, /* usage */
2802                                               Format,
2803                                               Pool,
2804                                               (IWineD3DTexture **) &object->wineD3DTexture,
2805                                               0, /* SharedHandle */
2806                                               (IUnknown *) ICOM_INTERFACE(object, IDirectDrawSurface7),
2807                                               D3D7CB_CreateSurface );
2808         }
2809         This->tex_root = NULL;
2810     }
2811
2812     LeaveCriticalSection(&ddraw_cs);
2813     return hr;
2814 }
2815
2816 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
2817 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
2818
2819 static BOOL
2820 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
2821                                     const DDPIXELFORMAT *provided)
2822 {
2823     /* Some flags must be present in both or neither for a match. */
2824     static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
2825         | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
2826         | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
2827
2828     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
2829         return FALSE;
2830
2831     if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
2832         return FALSE;
2833
2834     if (requested->dwFlags & DDPF_FOURCC)
2835         if (requested->dwFourCC != provided->dwFourCC)
2836             return FALSE;
2837
2838     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
2839                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
2840         if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
2841             return FALSE;
2842
2843     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
2844                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
2845         if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
2846             return FALSE;
2847
2848     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
2849         if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
2850             return FALSE;
2851
2852     /* I could be wrong about the bumpmapping. MSDN docs are vague. */
2853     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
2854                               |DDPF_BUMPDUDV))
2855         if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
2856             return FALSE;
2857
2858     if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
2859         if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
2860             return FALSE;
2861
2862     return TRUE;
2863 }
2864
2865 static BOOL
2866 IDirectDrawImpl_DDSD_Match(const DDSURFACEDESC2* requested,
2867                            const DDSURFACEDESC2* provided)
2868 {
2869     struct compare_info
2870     {
2871         DWORD flag;
2872         ptrdiff_t offset;
2873         size_t size;
2874     };
2875
2876 #define CMP(FLAG, FIELD)                                \
2877         { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
2878           sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
2879
2880     static const struct compare_info compare[] =
2881     {
2882         CMP(ALPHABITDEPTH, dwAlphaBitDepth),
2883         CMP(BACKBUFFERCOUNT, dwBackBufferCount),
2884         CMP(CAPS, ddsCaps),
2885         CMP(CKDESTBLT, ddckCKDestBlt),
2886         CMP(CKDESTOVERLAY, u3 /* ddckCKDestOverlay */),
2887         CMP(CKSRCBLT, ddckCKSrcBlt),
2888         CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
2889         CMP(HEIGHT, dwHeight),
2890         CMP(LINEARSIZE, u1 /* dwLinearSize */),
2891         CMP(LPSURFACE, lpSurface),
2892         CMP(MIPMAPCOUNT, u2 /* dwMipMapCount */),
2893         CMP(PITCH, u1 /* lPitch */),
2894         /* PIXELFORMAT: manual */
2895         CMP(REFRESHRATE, u2 /* dwRefreshRate */),
2896         CMP(TEXTURESTAGE, dwTextureStage),
2897         CMP(WIDTH, dwWidth),
2898         /* ZBUFFERBITDEPTH: "obsolete" */
2899     };
2900
2901 #undef CMP
2902
2903     unsigned int i;
2904
2905     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
2906         return FALSE;
2907
2908     for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
2909     {
2910         if (requested->dwFlags & compare[i].flag
2911             && memcmp((const char *)provided + compare[i].offset,
2912                       (const char *)requested + compare[i].offset,
2913                       compare[i].size) != 0)
2914             return FALSE;
2915     }
2916
2917     if (requested->dwFlags & DDSD_PIXELFORMAT)
2918     {
2919         if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
2920                                                 &provided->u4.ddpfPixelFormat))
2921             return FALSE;
2922     }
2923
2924     return TRUE;
2925 }
2926
2927 #undef DDENUMSURFACES_SEARCHTYPE
2928 #undef DDENUMSURFACES_MATCHTYPE
2929
2930 /*****************************************************************************
2931  * IDirectDraw7::EnumSurfaces
2932  *
2933  * Loops through all surfaces attached to this device and calls the
2934  * application callback. This can't be relayed to WineD3DDevice,
2935  * because some WineD3DSurfaces' parents are IParent objects
2936  *
2937  * Params:
2938  *  Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
2939  *  DDSD: Description to filter for
2940  *  Context: Application-provided pointer, it's passed unmodified to the
2941  *           Callback function
2942  *  Callback: Address to call for each surface
2943  *
2944  * Returns:
2945  *  DDERR_INVALIDPARAMS if the callback is NULL
2946  *  DD_OK on success
2947  *
2948  *****************************************************************************/
2949 static HRESULT WINAPI
2950 IDirectDrawImpl_EnumSurfaces(IDirectDraw7 *iface,
2951                              DWORD Flags,
2952                              DDSURFACEDESC2 *DDSD,
2953                              void *Context,
2954                              LPDDENUMSURFACESCALLBACK7 Callback)
2955 {
2956     /* The surface enumeration is handled by WineDDraw,
2957      * because it keeps track of all surfaces attached to
2958      * it. The filtering is done by our callback function,
2959      * because WineDDraw doesn't handle ddraw-like surface
2960      * caps structures
2961      */
2962     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
2963     IDirectDrawSurfaceImpl *surf;
2964     BOOL all, nomatch;
2965     DDSURFACEDESC2 desc;
2966     struct list *entry, *entry2;
2967
2968     all = Flags & DDENUMSURFACES_ALL;
2969     nomatch = Flags & DDENUMSURFACES_NOMATCH;
2970
2971     TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, DDSD, Context, Callback);
2972     EnterCriticalSection(&ddraw_cs);
2973
2974     if(!Callback)
2975     {
2976         LeaveCriticalSection(&ddraw_cs);
2977         return DDERR_INVALIDPARAMS;
2978     }
2979
2980     /* Use the _SAFE enumeration, the app may destroy enumerated surfaces */
2981     LIST_FOR_EACH_SAFE(entry, entry2, &This->surface_list)
2982     {
2983         surf = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
2984         if (all || (nomatch != IDirectDrawImpl_DDSD_Match(DDSD, &surf->surface_desc)))
2985         {
2986             desc = surf->surface_desc;
2987             IDirectDrawSurface7_AddRef(ICOM_INTERFACE(surf, IDirectDrawSurface7));
2988             if(Callback( ICOM_INTERFACE(surf, IDirectDrawSurface7), &desc, Context) != DDENUMRET_OK)
2989             {
2990                 LeaveCriticalSection(&ddraw_cs);
2991                 return DD_OK;
2992             }
2993         }
2994     }
2995     LeaveCriticalSection(&ddraw_cs);
2996     return DD_OK;
2997 }
2998
2999 static HRESULT WINAPI
3000 findRenderTarget(IDirectDrawSurface7 *surface,
3001                  DDSURFACEDESC2 *desc,
3002                  void *ctx)
3003 {
3004     IDirectDrawSurfaceImpl *surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, surface);
3005     IDirectDrawSurfaceImpl **target = (IDirectDrawSurfaceImpl **) ctx;
3006
3007     if(!surf->isRenderTarget) {
3008         *target = surf;
3009         IDirectDrawSurface7_Release(surface);
3010         return DDENUMRET_CANCEL;
3011     }
3012
3013     /* Recurse into the surface tree */
3014     IDirectDrawSurface7_EnumAttachedSurfaces(surface, ctx, findRenderTarget);
3015
3016     IDirectDrawSurface7_Release(surface);
3017     if(*target) return DDENUMRET_CANCEL;
3018     else return DDENUMRET_OK; /* Continue with the next neighbor surface */
3019 }
3020
3021 /*****************************************************************************
3022  * D3D7CB_CreateRenderTarget
3023  *
3024  * Callback called by WineD3D to create Surfaces for render target usage
3025  * This function takes the D3D target from the IDirectDrawImpl structure,
3026  * and returns the WineD3DSurface. To avoid double usage, the surface
3027  * is marked as render target afterwards
3028  *
3029  * Params
3030  *  device: The WineD3DDevice's parent
3031  *  Width, Height, Format: Dimensions and pixelformat of the render target
3032  *                         Ignored, because the surface already exists
3033  *  MultiSample, MultisampleQuality, Lockable: Ignored for the same reason
3034  *  Lockable: ignored
3035  *  ppSurface: Address to pass the surface pointer back at
3036  *  pSharedHandle: Ignored
3037  *
3038  * Returns:
3039  *  Always returns D3D_OK
3040  *
3041  *****************************************************************************/
3042 static HRESULT WINAPI
3043 D3D7CB_CreateRenderTarget(IUnknown *device, IUnknown *pSuperior,
3044                           UINT Width, UINT Height,
3045                           WINED3DFORMAT Format,
3046                           WINED3DMULTISAMPLE_TYPE MultiSample,
3047                           DWORD MultisampleQuality,
3048                           BOOL Lockable,
3049                           IWineD3DSurface** ppSurface,
3050                           HANDLE* pSharedHandle)
3051 {
3052     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
3053     IDirectDrawSurfaceImpl *d3dSurface = This->d3d_target, *target = NULL;
3054     TRACE("(%p) call back\n", device);
3055
3056     if(d3dSurface->isRenderTarget)
3057     {
3058         IDirectDrawSurface7_EnumAttachedSurfaces(ICOM_INTERFACE(d3dSurface, IDirectDrawSurface7),
3059                                                  &target, findRenderTarget);
3060     }
3061     else
3062     {
3063         target = d3dSurface;
3064     }
3065
3066     if(!target)
3067     {
3068         target = This->d3d_target;
3069         ERR(" (%p) : No DirectDrawSurface found to create the back buffer. Using the front buffer as back buffer. Uncertain consequences\n", This);
3070     }
3071
3072     /* TODO: Return failure if the dimensions do not match, but this shouldn't happen */
3073
3074     *ppSurface = target->WineD3DSurface;
3075     target->isRenderTarget = TRUE;
3076     TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *ppSurface, d3dSurface);
3077     return D3D_OK;
3078 }
3079
3080 static HRESULT WINAPI
3081 D3D7CB_CreateDepthStencilSurface(IUnknown *device,
3082                                  IUnknown *pSuperior,
3083                                  UINT Width,
3084                                  UINT Height,
3085                                  WINED3DFORMAT Format,
3086                                  WINED3DMULTISAMPLE_TYPE MultiSample,
3087                                  DWORD MultisampleQuality,
3088                                  BOOL Discard,
3089                                  IWineD3DSurface** ppSurface,
3090                                  HANDLE* pSharedHandle)
3091 {
3092     /* Create a Depth Stencil surface to make WineD3D happy */
3093     HRESULT hr = D3D_OK;
3094     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
3095     DDSURFACEDESC2 ddsd;
3096
3097     TRACE("(%p) call back\n", device);
3098
3099     *ppSurface = NULL;
3100
3101     /* Create a DirectDraw surface */
3102     memset(&ddsd, 0, sizeof(ddsd));
3103     ddsd.dwSize = sizeof(ddsd);
3104     ddsd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
3105     ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
3106     ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
3107     ddsd.dwHeight = Height;
3108     ddsd.dwWidth = Width;
3109     if(Format != 0)
3110     {
3111       PixelFormat_WineD3DtoDD(&ddsd.u4.ddpfPixelFormat, Format);
3112     }
3113     else
3114     {
3115       ddsd.dwFlags ^= DDSD_PIXELFORMAT;
3116     }
3117
3118     This->depthstencil = TRUE;
3119     hr = IDirectDraw7_CreateSurface((IDirectDraw7 *) This,
3120                                     &ddsd,
3121                                     (IDirectDrawSurface7 **) &This->DepthStencilBuffer,
3122                                     NULL);
3123     This->depthstencil = FALSE;
3124     if(FAILED(hr))
3125     {
3126         ERR(" (%p) Creating a DepthStencil Surface failed, result = %x\n", This, hr);
3127         return hr;
3128     }
3129     *ppSurface = This->DepthStencilBuffer->WineD3DSurface;
3130     return D3D_OK;
3131 }
3132
3133 /*****************************************************************************
3134  * D3D7CB_CreateAdditionalSwapChain
3135  *
3136  * Callback function for WineD3D which creates a new WineD3DSwapchain
3137  * interface. It also creates an IParent interface to store that pointer,
3138  * so the WineD3DSwapchain has a parent and can be released when the D3D
3139  * device is destroyed
3140  *****************************************************************************/
3141 static HRESULT WINAPI
3142 D3D7CB_CreateAdditionalSwapChain(IUnknown *device,
3143                                  WINED3DPRESENT_PARAMETERS* pPresentationParameters,
3144                                  IWineD3DSwapChain ** ppSwapChain)
3145 {
3146     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, device);
3147     IParentImpl *object = NULL;
3148     HRESULT res = D3D_OK;
3149     IWineD3DSwapChain *swapchain;
3150     IDirectDrawSurfaceImpl *iterator;
3151     TRACE("(%p) call back\n", device);
3152
3153     object = HeapAlloc(GetProcessHeap(),  HEAP_ZERO_MEMORY, sizeof(IParentImpl));
3154     if (NULL == object)
3155     {
3156         FIXME("Allocation of memory failed\n");
3157         *ppSwapChain = NULL;
3158         return DDERR_OUTOFVIDEOMEMORY;
3159     }
3160
3161     ICOM_INIT_INTERFACE(object, IParent, IParent_Vtbl);
3162     object->ref = 1;
3163
3164     res = IWineD3DDevice_CreateAdditionalSwapChain(This->wineD3DDevice,
3165                                                    pPresentationParameters, 
3166                                                    &swapchain, 
3167                                                    (IUnknown*) ICOM_INTERFACE(object, IParent),
3168                                                    D3D7CB_CreateRenderTarget,
3169                                                    D3D7CB_CreateDepthStencilSurface,
3170                                                    This->ImplType);
3171     if (res != D3D_OK)
3172     {
3173         FIXME("(%p) call to IWineD3DDevice_CreateAdditionalSwapChain failed\n", This);
3174         HeapFree(GetProcessHeap(), 0 , object);
3175         *ppSwapChain = NULL;
3176     }
3177     else
3178     {
3179         *ppSwapChain = swapchain;
3180         object->child = (IUnknown *) swapchain;
3181         This->d3d_target->wineD3DSwapChain = swapchain;
3182         iterator = This->d3d_target->complex_array[0];
3183         while(iterator) {
3184             iterator->wineD3DSwapChain = swapchain;
3185             iterator = iterator->complex_array[0];
3186         }
3187     }
3188
3189     return res;
3190 }
3191
3192 static HRESULT WINAPI IDirectDrawImpl_CreateGDISwapChain(IDirectDrawImpl *This,
3193                                                          IDirectDrawSurfaceImpl *primary) {
3194     HRESULT hr;
3195     WINED3DPRESENT_PARAMETERS presentation_parameters;
3196     HWND window;
3197
3198     hr = IWineD3DDevice_GetHWND(This->wineD3DDevice,
3199                                 &window);
3200     if(FAILED(hr)) {
3201         return hr;
3202     }
3203
3204     memset(&presentation_parameters, 0, sizeof(presentation_parameters));
3205
3206     /* Use the surface description for the device parameters, not the
3207      * Device settings. The app might render to an offscreen surface
3208      */
3209     presentation_parameters.BackBufferWidth                 = primary->surface_desc.dwWidth;
3210     presentation_parameters.BackBufferHeight                = primary->surface_desc.dwHeight;
3211     presentation_parameters.BackBufferFormat                = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
3212     presentation_parameters.BackBufferCount                 = (primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT) ? primary->surface_desc.dwBackBufferCount : 0;
3213     presentation_parameters.MultiSampleType                 = WINED3DMULTISAMPLE_NONE;
3214     presentation_parameters.MultiSampleQuality              = 0;
3215     presentation_parameters.SwapEffect                      = WINED3DSWAPEFFECT_FLIP;
3216     presentation_parameters.hDeviceWindow                   = window;
3217     presentation_parameters.Windowed                        = !(This->cooperative_level & DDSCL_FULLSCREEN);
3218     presentation_parameters.EnableAutoDepthStencil          = FALSE; /* Not on GDI swapchains */
3219     presentation_parameters.AutoDepthStencilFormat          = 0;
3220     presentation_parameters.Flags                           = 0;
3221     presentation_parameters.FullScreen_RefreshRateInHz      = WINED3DPRESENT_RATE_DEFAULT; /* Default rate: It's already set */
3222     presentation_parameters.PresentationInterval            = WINED3DPRESENT_INTERVAL_DEFAULT;
3223
3224     This->d3d_target = primary;
3225     hr = IWineD3DDevice_InitGDI(This->wineD3DDevice,
3226                                 &presentation_parameters,
3227                                 D3D7CB_CreateAdditionalSwapChain);
3228     This->d3d_target = NULL;
3229
3230     if (hr != D3D_OK)
3231     {
3232         FIXME("(%p) call to IWineD3DDevice_CreateAdditionalSwapChain failed\n", This);
3233         primary->wineD3DSwapChain = NULL;
3234     }
3235     return hr;
3236 }
3237
3238 /*****************************************************************************
3239  * IDirectDrawImpl_AttachD3DDevice
3240  *
3241  * Initializes the D3D capabilities of WineD3D
3242  *
3243  * Params:
3244  *  primary: The primary surface for D3D
3245  *
3246  * Returns
3247  *  DD_OK on success,
3248  *  DDERR_* otherwise
3249  *
3250  *****************************************************************************/
3251 static HRESULT WINAPI
3252 IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This,
3253                                 IDirectDrawSurfaceImpl *primary)
3254 {
3255     HRESULT hr;
3256     HWND                  window;
3257
3258     WINED3DPRESENT_PARAMETERS localParameters;
3259
3260     TRACE("(%p)->(%p)\n", This, primary);
3261
3262     /* Get the window */
3263     hr = IWineD3DDevice_GetHWND(This->wineD3DDevice,
3264                                 &window);
3265     if(hr != D3D_OK)
3266     {
3267         ERR("IWineD3DDevice::GetHWND failed\n");
3268         return hr;
3269     }
3270
3271     /* If there's no window, create a hidden window. WineD3D needs it */
3272     if(window == 0)
3273     {
3274         window = CreateWindowExA(0, This->classname, "Hidden D3D Window",
3275                                  WS_DISABLED, 0, 0,
3276                                  GetSystemMetrics(SM_CXSCREEN),
3277                                  GetSystemMetrics(SM_CYSCREEN),
3278                                  NULL, NULL, GetModuleHandleA(0), NULL);
3279
3280         ShowWindow(window, SW_HIDE);   /* Just to be sure */
3281         WARN("(%p) No window for the Direct3DDevice, created a hidden window. HWND=%p\n", This, window);
3282         This->d3d_window = window;
3283     }
3284     else
3285     {
3286         TRACE("(%p) Using existing window %p for Direct3D rendering\n", This, window);
3287     }
3288
3289     /* Store the future Render Target surface */
3290     This->d3d_target = primary;
3291
3292     /* Use the surface description for the device parameters, not the
3293      * Device settings. The app might render to an offscreen surface
3294      */
3295     localParameters.BackBufferWidth                 = primary->surface_desc.dwWidth;
3296     localParameters.BackBufferHeight                = primary->surface_desc.dwHeight;
3297     localParameters.BackBufferFormat                = PixelFormat_DD2WineD3D(&primary->surface_desc.u4.ddpfPixelFormat);
3298     localParameters.BackBufferCount                 = (primary->surface_desc.dwFlags & DDSD_BACKBUFFERCOUNT) ? primary->surface_desc.dwBackBufferCount : 0;
3299     localParameters.MultiSampleType                 = WINED3DMULTISAMPLE_NONE;
3300     localParameters.MultiSampleQuality              = 0;
3301     localParameters.SwapEffect                      = WINED3DSWAPEFFECT_COPY;
3302     localParameters.hDeviceWindow                   = window;
3303     localParameters.Windowed                        = !(This->cooperative_level & DDSCL_FULLSCREEN);
3304     localParameters.EnableAutoDepthStencil          = TRUE;
3305     localParameters.AutoDepthStencilFormat          = WINED3DFMT_D16;
3306     localParameters.Flags                           = 0;
3307     localParameters.FullScreen_RefreshRateInHz      = WINED3DPRESENT_RATE_DEFAULT; /* Default rate: It's already set */
3308     localParameters.PresentationInterval            = WINED3DPRESENT_INTERVAL_DEFAULT;
3309
3310     TRACE("Passing mode %d\n", localParameters.BackBufferFormat);
3311
3312     /* Set this NOW, otherwise creating the depth stencil surface will cause a
3313      * recursive loop until ram or emulated video memory is full
3314      */
3315     This->d3d_initialized = TRUE;
3316
3317     hr = IWineD3DDevice_Init3D(This->wineD3DDevice,
3318                                &localParameters,
3319                                D3D7CB_CreateAdditionalSwapChain);
3320     if(FAILED(hr))
3321     {
3322         This->d3d_target = NULL;
3323         This->d3d_initialized = FALSE;
3324         return hr;
3325     }
3326
3327     This->declArraySize = 2;
3328     This->decls = HeapAlloc(GetProcessHeap(),
3329                             HEAP_ZERO_MEMORY,
3330                             sizeof(*This->decls) * This->declArraySize);
3331     if(!This->decls)
3332     {
3333         ERR("Error allocating an array for the converted vertex decls\n");
3334         This->declArraySize = 0;
3335         hr = IWineD3DDevice_Uninit3D(This->wineD3DDevice,
3336                                      D3D7CB_DestroyDepthStencilSurface,
3337                                      D3D7CB_DestroySwapChain);
3338         return E_OUTOFMEMORY;
3339     }
3340
3341     /* Create an Index Buffer parent */
3342     TRACE("(%p) Successfully initialized 3D\n", This);
3343     return DD_OK;
3344 }
3345
3346 /*****************************************************************************
3347  * DirectDrawCreateClipper (DDRAW.@)
3348  *
3349  * Creates a new IDirectDrawClipper object.
3350  *
3351  * Params:
3352  *  Clipper: Address to write the interface pointer to
3353  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3354  *            NULL
3355  *
3356  * Returns:
3357  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
3358  *  E_OUTOFMEMORY if allocating the object failed
3359  *
3360  *****************************************************************************/
3361 HRESULT WINAPI
3362 DirectDrawCreateClipper(DWORD Flags,
3363                         LPDIRECTDRAWCLIPPER *Clipper,
3364                         IUnknown *UnkOuter)
3365 {
3366     IDirectDrawClipperImpl* object;
3367     TRACE("(%08x,%p,%p)\n", Flags, Clipper, UnkOuter);
3368
3369     EnterCriticalSection(&ddraw_cs);
3370     if (UnkOuter != NULL)
3371     {
3372         LeaveCriticalSection(&ddraw_cs);
3373         return CLASS_E_NOAGGREGATION;
3374     }
3375
3376     if (!LoadWineD3D())
3377     {
3378         LeaveCriticalSection(&ddraw_cs);
3379         return DDERR_NODIRECTDRAWSUPPORT;
3380     }
3381
3382     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3383                      sizeof(IDirectDrawClipperImpl));
3384     if (object == NULL)
3385     {
3386         LeaveCriticalSection(&ddraw_cs);
3387         return E_OUTOFMEMORY;
3388     }
3389
3390     ICOM_INIT_INTERFACE(object, IDirectDrawClipper, IDirectDrawClipper_Vtbl);
3391     object->ref = 1;
3392     object->wineD3DClipper = pWineDirect3DCreateClipper((IUnknown *) object);
3393     if(!object->wineD3DClipper)
3394     {
3395         HeapFree(GetProcessHeap(), 0, object);
3396         LeaveCriticalSection(&ddraw_cs);
3397         return E_OUTOFMEMORY;
3398     }
3399
3400     *Clipper = (IDirectDrawClipper *) object;
3401     LeaveCriticalSection(&ddraw_cs);
3402     return DD_OK;
3403 }
3404
3405 /*****************************************************************************
3406  * IDirectDraw7::CreateClipper
3407  *
3408  * Creates a DDraw clipper. See DirectDrawCreateClipper for details
3409  *
3410  *****************************************************************************/
3411 static HRESULT WINAPI
3412 IDirectDrawImpl_CreateClipper(IDirectDraw7 *iface,
3413                               DWORD Flags,
3414                               IDirectDrawClipper **Clipper,
3415                               IUnknown *UnkOuter)
3416 {
3417     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
3418     TRACE("(%p)->(%x,%p,%p)\n", This, Flags, Clipper, UnkOuter);
3419     return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
3420 }
3421
3422 /*****************************************************************************
3423  * IDirectDraw7::CreatePalette
3424  *
3425  * Creates a new IDirectDrawPalette object
3426  *
3427  * Params:
3428  *  Flags: The flags for the new clipper
3429  *  ColorTable: Color table to assign to the new clipper
3430  *  Palette: Address to write the interface pointer to
3431  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3432  *            NULL
3433  *
3434  * Returns:
3435  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
3436  *  E_OUTOFMEMORY if allocating the object failed
3437  *
3438  *****************************************************************************/
3439 static HRESULT WINAPI
3440 IDirectDrawImpl_CreatePalette(IDirectDraw7 *iface,
3441                               DWORD Flags,
3442                               PALETTEENTRY *ColorTable,
3443                               IDirectDrawPalette **Palette,
3444                               IUnknown *pUnkOuter)
3445 {
3446     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
3447     IDirectDrawPaletteImpl *object;
3448     HRESULT hr = DDERR_GENERIC;
3449     TRACE("(%p)->(%x,%p,%p,%p)\n", This, Flags, ColorTable, Palette, pUnkOuter);
3450
3451     EnterCriticalSection(&ddraw_cs);
3452     if(pUnkOuter != NULL)
3453     {
3454         WARN("pUnkOuter is %p, returning CLASS_E_NOAGGREGATION\n", pUnkOuter);
3455         LeaveCriticalSection(&ddraw_cs);
3456         return CLASS_E_NOAGGREGATION;
3457     }
3458
3459     /* The refcount test shows that a cooplevel is required for this */
3460     if(!This->cooperative_level)
3461     {
3462         WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
3463         LeaveCriticalSection(&ddraw_cs);
3464         return DDERR_NOCOOPERATIVELEVELSET;
3465     }
3466
3467     object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectDrawPaletteImpl));
3468     if(!object)
3469     {
3470         ERR("Out of memory when allocating memory for a palette implementation\n");
3471         LeaveCriticalSection(&ddraw_cs);
3472         return E_OUTOFMEMORY;
3473     }
3474
3475     ICOM_INIT_INTERFACE(object, IDirectDrawPalette, IDirectDrawPalette_Vtbl);
3476     object->ref = 1;
3477     object->ddraw_owner = This;
3478
3479     hr = IWineD3DDevice_CreatePalette(This->wineD3DDevice, Flags, ColorTable, &object->wineD3DPalette, (IUnknown *) ICOM_INTERFACE(object, IDirectDrawPalette) );
3480     if(hr != DD_OK)
3481     {
3482         HeapFree(GetProcessHeap(), 0, object);
3483         LeaveCriticalSection(&ddraw_cs);
3484         return hr;
3485     }
3486
3487     IDirectDraw7_AddRef(iface);
3488     object->ifaceToRelease = (IUnknown *) iface;
3489     *Palette = ICOM_INTERFACE(object, IDirectDrawPalette);
3490     LeaveCriticalSection(&ddraw_cs);
3491     return DD_OK;
3492 }
3493
3494 /*****************************************************************************
3495  * IDirectDraw7::DuplicateSurface
3496  *
3497  * Duplicates a surface. The surface memory points to the same memory as
3498  * the original surface, and it's released when the last surface referencing
3499  * it is released. I guess that's beyond Wine's surface management right now
3500  * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
3501  * test application to implement this)
3502  *
3503  * Params:
3504  *  Src: Address of the source surface
3505  *  Dest: Address to write the new surface pointer to
3506  *
3507  * Returns:
3508  *  See IDirectDraw7::CreateSurface
3509  *
3510  *****************************************************************************/
3511 static HRESULT WINAPI
3512 IDirectDrawImpl_DuplicateSurface(IDirectDraw7 *iface,
3513                                  IDirectDrawSurface7 *Src,
3514                                  IDirectDrawSurface7 **Dest)
3515 {
3516     ICOM_THIS_FROM(IDirectDrawImpl, IDirectDraw7, iface);
3517     IDirectDrawSurfaceImpl *Surf = ICOM_OBJECT(IDirectDrawSurfaceImpl, IDirectDrawSurface7, Src);
3518
3519     FIXME("(%p)->(%p,%p)\n", This, Surf, Dest);
3520
3521     /* For now, simply create a new, independent surface */
3522     return IDirectDraw7_CreateSurface(iface,
3523                                       &Surf->surface_desc,
3524                                       Dest,
3525                                       NULL);
3526 }
3527
3528 /*****************************************************************************
3529  * IDirectDraw7 VTable
3530  *****************************************************************************/
3531 const IDirectDraw7Vtbl IDirectDraw7_Vtbl =
3532 {
3533     /*** IUnknown ***/
3534     IDirectDrawImpl_QueryInterface,
3535     IDirectDrawImpl_AddRef,
3536     IDirectDrawImpl_Release,
3537     /*** IDirectDraw ***/
3538     IDirectDrawImpl_Compact,
3539     IDirectDrawImpl_CreateClipper,
3540     IDirectDrawImpl_CreatePalette,
3541     IDirectDrawImpl_CreateSurface,
3542     IDirectDrawImpl_DuplicateSurface,
3543     IDirectDrawImpl_EnumDisplayModes,
3544     IDirectDrawImpl_EnumSurfaces,
3545     IDirectDrawImpl_FlipToGDISurface,
3546     IDirectDrawImpl_GetCaps,
3547     IDirectDrawImpl_GetDisplayMode,
3548     IDirectDrawImpl_GetFourCCCodes,
3549     IDirectDrawImpl_GetGDISurface,
3550     IDirectDrawImpl_GetMonitorFrequency,
3551     IDirectDrawImpl_GetScanLine,
3552     IDirectDrawImpl_GetVerticalBlankStatus,
3553     IDirectDrawImpl_Initialize,
3554     IDirectDrawImpl_RestoreDisplayMode,
3555     IDirectDrawImpl_SetCooperativeLevel,
3556     IDirectDrawImpl_SetDisplayMode,
3557     IDirectDrawImpl_WaitForVerticalBlank,
3558     /*** IDirectDraw2 ***/
3559     IDirectDrawImpl_GetAvailableVidMem,
3560     /*** IDirectDraw7 ***/
3561     IDirectDrawImpl_GetSurfaceFromDC,
3562     IDirectDrawImpl_RestoreAllSurfaces,
3563     IDirectDrawImpl_TestCooperativeLevel,
3564     IDirectDrawImpl_GetDeviceIdentifier,
3565     /*** IDirectDraw7 ***/
3566     IDirectDrawImpl_StartModeTest,
3567     IDirectDrawImpl_EvaluateMode
3568 };
3569
3570 /*****************************************************************************
3571  * IDirectDrawImpl_FindDecl
3572  *
3573  * Finds the WineD3D vertex declaration for a specific fvf, and creates one
3574  * if none was found.
3575  *
3576  * This function is in ddraw.c and the DDraw object space because D3D7
3577  * vertex buffers are created using the IDirect3D interface to the ddraw
3578  * object, so they can be valid across D3D devices(theoretically. The ddraw
3579  * object also owns the wined3d device
3580  *
3581  * Parameters:
3582  *  This: Device
3583  *  fvf: Fvf to find the decl for
3584  *
3585  * Returns:
3586  *  NULL in case of an error, the IWineD3DVertexDeclaration interface for the
3587  *  fvf otherwise.
3588  *
3589  *****************************************************************************/
3590 IWineD3DVertexDeclaration *
3591 IDirectDrawImpl_FindDecl(IDirectDrawImpl *This,
3592                          DWORD fvf)
3593 {
3594     HRESULT hr;
3595     IWineD3DVertexDeclaration* pDecl = NULL;
3596     int p, low, high; /* deliberately signed */
3597     struct FvfToDecl *convertedDecls = This->decls;
3598
3599     TRACE("Searching for declaration for fvf %08x... ", fvf);
3600
3601     low = 0;
3602     high = This->numConvertedDecls - 1;
3603     while(low <= high) {
3604         p = (low + high) >> 1;
3605         TRACE("%d ", p);
3606         if(convertedDecls[p].fvf == fvf) {
3607             TRACE("found %p\n", convertedDecls[p].decl);
3608             return convertedDecls[p].decl;
3609         } else if(convertedDecls[p].fvf < fvf) {
3610             low = p + 1;
3611         } else {
3612             high = p - 1;
3613         }
3614     }
3615     TRACE("not found. Creating and inserting at position %d.\n", low);
3616
3617     hr = IWineD3DDevice_CreateVertexDeclarationFromFVF(This->wineD3DDevice,
3618                                                        &pDecl,
3619                                                        (IUnknown *) ICOM_INTERFACE(This, IDirectDraw7),
3620                                                        fvf);
3621     if (hr != S_OK) return NULL;
3622
3623     if(This->declArraySize == This->numConvertedDecls) {
3624         int grow = max(This->declArraySize / 2, 8);
3625         convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
3626                                      sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow));
3627         if(!convertedDecls) {
3628             /* This will destroy it */
3629             IWineD3DVertexDeclaration_Release(pDecl);
3630             return NULL;
3631         }
3632         This->decls = convertedDecls;
3633         This->declArraySize += grow;
3634     }
3635
3636     memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low));
3637     convertedDecls[low].decl = pDecl;
3638     convertedDecls[low].fvf = fvf;
3639     This->numConvertedDecls++;
3640
3641     TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
3642     return pDecl;
3643 }