~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/ddraw/ddraw.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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