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