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