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