ddraw: Get rid of IDirectDraw3.
[wine] / dlls / ddraw / ddraw.c
1 /*
2  * Copyright 1997-2000 Marcus Meissner
3  * Copyright 1998-2000 Lionel Ulmer
4  * Copyright 2000-2001 TransGaming Technologies Inc.
5  * Copyright 2006 Stefan Dösinger
6  * Copyright 2008 Denver Gingerich
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include "ddraw_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
29
30 /* Device identifier. Don't relay it to WineD3D */
31 static const DDDEVICEIDENTIFIER2 deviceidentifier =
32 {
33     "display",
34     "DirectDraw HAL",
35     { { 0x00010001, 0x00010001 } },
36     0, 0, 0, 0,
37     /* a8373c10-7ac4-4deb-849a-009844d08b2d */
38     {0xa8373c10,0x7ac4,0x4deb, {0x84,0x9a,0x00,0x98,0x44,0xd0,0x8b,0x2d}},
39     0
40 };
41
42 static struct enum_device_entry
43 {
44     char interface_name[100];
45     char device_name[100];
46     const GUID *device_guid;
47 } device_list7[] =
48 {
49     /* T&L HAL device */
50     {
51         "WINE Direct3D7 Hardware Transform and Lighting acceleration using WineD3D",
52         "Wine D3D7 T&L HAL",
53         &IID_IDirect3DTnLHalDevice,
54     },
55
56     /* HAL device */
57     {
58         "WINE Direct3D7 Hardware acceleration using WineD3D",
59         "Wine D3D7 HAL",
60         &IID_IDirect3DHALDevice,
61     },
62
63     /* RGB device */
64     {
65         "WINE Direct3D7 RGB Software Emulation using WineD3D",
66         "Wine D3D7 RGB",
67         &IID_IDirect3DRGBDevice,
68     },
69 };
70
71 static void STDMETHODCALLTYPE ddraw_null_wined3d_object_destroyed(void *parent) {}
72
73 const struct wined3d_parent_ops ddraw_null_wined3d_parent_ops =
74 {
75     ddraw_null_wined3d_object_destroyed,
76 };
77
78 static inline IDirectDrawImpl *impl_from_IDirectDraw(IDirectDraw *iface)
79 {
80     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw_iface);
81 }
82
83 static inline IDirectDrawImpl *impl_from_IDirectDraw2(IDirectDraw2 *iface)
84 {
85     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw2_iface);
86 }
87
88 static inline IDirectDrawImpl *impl_from_IDirectDraw4(IDirectDraw4 *iface)
89 {
90     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw4_iface);
91 }
92
93 static inline IDirectDrawImpl *impl_from_IDirectDraw7(IDirectDraw7 *iface)
94 {
95     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirectDraw7_iface);
96 }
97
98 static inline IDirectDrawImpl *impl_from_IDirect3D(IDirect3D *iface)
99 {
100     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirect3D_iface);
101 }
102
103 static inline IDirectDrawImpl *impl_from_IDirect3D2(IDirect3D2 *iface)
104 {
105     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirect3D2_iface);
106 }
107
108 static inline IDirectDrawImpl *impl_from_IDirect3D3(IDirect3D3 *iface)
109 {
110     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirect3D3_iface);
111 }
112
113 static inline IDirectDrawImpl *impl_from_IDirect3D7(IDirect3D7 *iface)
114 {
115     return CONTAINING_RECORD(iface, IDirectDrawImpl, IDirect3D7_iface);
116 }
117
118 /*****************************************************************************
119  * IUnknown Methods
120  *****************************************************************************/
121
122 /*****************************************************************************
123  * IDirectDraw7::QueryInterface
124  *
125  * Queries different interfaces of the DirectDraw object. It can return
126  * IDirectDraw interfaces in version 1, 2, 4 and 7, and IDirect3D interfaces
127  * in version 1, 2, 3 and 7. An IDirect3DDevice can be created with this
128  * method.
129  * The returned interface is AddRef()-ed before it's returned
130  *
131  * Used for version 1, 2, 4 and 7
132  *
133  * Params:
134  *  refiid: Interface ID asked for
135  *  obj: Used to return the interface pointer
136  *
137  * Returns:
138  *  S_OK if an interface was found
139  *  E_NOINTERFACE if the requested interface wasn't found
140  *
141  *****************************************************************************/
142 static HRESULT WINAPI ddraw7_QueryInterface(IDirectDraw7 *iface, REFIID refiid, void **obj)
143 {
144     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
145
146     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(refiid), obj);
147
148     /* Can change surface impl type */
149     EnterCriticalSection(&ddraw_cs);
150
151     /* According to COM docs, if the QueryInterface fails, obj should be set to NULL */
152     *obj = NULL;
153
154     if(!refiid)
155     {
156         LeaveCriticalSection(&ddraw_cs);
157         return DDERR_INVALIDPARAMS;
158     }
159
160     /* Check DirectDraw Interfaces */
161     if ( IsEqualGUID( &IID_IUnknown, refiid ) ||
162          IsEqualGUID( &IID_IDirectDraw7, refiid ) )
163     {
164         *obj = This;
165         TRACE("(%p) Returning IDirectDraw7 interface at %p\n", This, *obj);
166     }
167     else if ( IsEqualGUID( &IID_IDirectDraw4, refiid ) )
168     {
169         *obj = &This->IDirectDraw4_iface;
170         TRACE("(%p) Returning IDirectDraw4 interface at %p\n", This, *obj);
171     }
172     else if ( IsEqualGUID( &IID_IDirectDraw3, refiid ) )
173     {
174         /* This Interface exists in ddrawex.dll, it is implemented in a wrapper */
175         WARN("IDirectDraw3 is not valid in ddraw.dll\n");
176         *obj = NULL;
177         LeaveCriticalSection(&ddraw_cs);
178         return E_NOINTERFACE;
179     }
180     else if ( IsEqualGUID( &IID_IDirectDraw2, refiid ) )
181     {
182         *obj = &This->IDirectDraw2_iface;
183         TRACE("(%p) Returning IDirectDraw2 interface at %p\n", This, *obj);
184     }
185     else if ( IsEqualGUID( &IID_IDirectDraw, refiid ) )
186     {
187         *obj = &This->IDirectDraw_iface;
188         TRACE("(%p) Returning IDirectDraw interface at %p\n", This, *obj);
189     }
190
191     /* Direct3D
192      * The refcount unit test revealed that an IDirect3D7 interface can only be queried
193      * from a DirectDraw object that was created as an IDirectDraw7 interface. No idea
194      * who had this idea and why. The older interfaces can query and IDirect3D version
195      * because they are all created as IDirectDraw(1). This isn't really crucial behavior,
196      * and messy to implement with the common creation function, so it has been left out here.
197      */
198     else if ( IsEqualGUID( &IID_IDirect3D  , refiid ) ||
199               IsEqualGUID( &IID_IDirect3D2 , refiid ) ||
200               IsEqualGUID( &IID_IDirect3D3 , refiid ) ||
201               IsEqualGUID( &IID_IDirect3D7 , refiid ) )
202     {
203         /* Check the surface implementation */
204         if (DefaultSurfaceType != SURFACE_OPENGL)
205         {
206             WARN("The app requests a Direct3D interface, but non-opengl surfaces where set in winecfg\n");
207             /* Do not abort here, only reject 3D Device creation */
208         }
209
210         if ( IsEqualGUID( &IID_IDirect3D  , refiid ) )
211         {
212             This->d3dversion = 1;
213             *obj = &This->IDirect3D_iface;
214             TRACE(" returning Direct3D interface at %p.\n", *obj);
215         }
216         else if ( IsEqualGUID( &IID_IDirect3D2  , refiid ) )
217         {
218             This->d3dversion = 2;
219             *obj = &This->IDirect3D2_iface;
220             TRACE(" returning Direct3D2 interface at %p.\n", *obj);
221         }
222         else if ( IsEqualGUID( &IID_IDirect3D3  , refiid ) )
223         {
224             This->d3dversion = 3;
225             *obj = &This->IDirect3D3_iface;
226             TRACE(" returning Direct3D3 interface at %p.\n", *obj);
227         }
228         else if(IsEqualGUID( &IID_IDirect3D7  , refiid ))
229         {
230             This->d3dversion = 7;
231             *obj = &This->IDirect3D7_iface;
232             TRACE(" returning Direct3D7 interface at %p.\n", *obj);
233         }
234     }
235     /* Unknown interface */
236     else
237     {
238         ERR("(%p)->(%s, %p): No interface found\n", This, debugstr_guid(refiid), obj);
239         LeaveCriticalSection(&ddraw_cs);
240         return E_NOINTERFACE;
241     }
242
243     IUnknown_AddRef( (IUnknown *) *obj );
244     LeaveCriticalSection(&ddraw_cs);
245     return S_OK;
246 }
247
248 static HRESULT WINAPI ddraw4_QueryInterface(IDirectDraw4 *iface, REFIID riid, void **object)
249 {
250     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
251
252     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
253
254     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
255 }
256
257 static HRESULT WINAPI ddraw2_QueryInterface(IDirectDraw2 *iface, REFIID riid, void **object)
258 {
259     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
260
261     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
262
263     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
264 }
265
266 static HRESULT WINAPI ddraw1_QueryInterface(IDirectDraw *iface, REFIID riid, void **object)
267 {
268     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
269
270     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
271
272     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
273 }
274
275 static HRESULT WINAPI d3d7_QueryInterface(IDirect3D7 *iface, REFIID riid, void **object)
276 {
277     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
278
279     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
280
281     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
282 }
283
284 static HRESULT WINAPI d3d3_QueryInterface(IDirect3D3 *iface, REFIID riid, void **object)
285 {
286     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
287
288     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
289
290     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
291 }
292
293 static HRESULT WINAPI d3d2_QueryInterface(IDirect3D2 *iface, REFIID riid, void **object)
294 {
295     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
296
297     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
298
299     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
300 }
301
302 static HRESULT WINAPI d3d1_QueryInterface(IDirect3D *iface, REFIID riid, void **object)
303 {
304     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
305
306     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
307
308     return ddraw7_QueryInterface(&This->IDirectDraw7_iface, riid, object);
309 }
310
311 /*****************************************************************************
312  * IDirectDraw7::AddRef
313  *
314  * Increases the interfaces refcount, basically
315  *
316  * DDraw refcounting is a bit tricky. The different DirectDraw interface
317  * versions have individual refcounts, but the IDirect3D interfaces do not.
318  * All interfaces are from one object, that means calling QueryInterface on an
319  * IDirectDraw7 interface for an IDirectDraw4 interface does not create a new
320  * IDirectDrawImpl object.
321  *
322  * That means all AddRef and Release implementations of IDirectDrawX work
323  * with their own counter, and IDirect3DX::AddRef thunk to IDirectDraw (1),
324  * except of IDirect3D7 which thunks to IDirectDraw7
325  *
326  * Returns: The new refcount
327  *
328  *****************************************************************************/
329 static ULONG WINAPI ddraw7_AddRef(IDirectDraw7 *iface)
330 {
331     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
332     ULONG ref = InterlockedIncrement(&This->ref7);
333
334     TRACE("%p increasing refcount to %u.\n", This, ref);
335
336     if(ref == 1) InterlockedIncrement(&This->numIfaces);
337
338     return ref;
339 }
340
341 static ULONG WINAPI ddraw4_AddRef(IDirectDraw4 *iface)
342 {
343     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
344     ULONG ref = InterlockedIncrement(&This->ref4);
345
346     TRACE("%p increasing refcount to %u.\n", This, ref);
347
348     if (ref == 1) InterlockedIncrement(&This->numIfaces);
349
350     return ref;
351 }
352
353 static ULONG WINAPI ddraw2_AddRef(IDirectDraw2 *iface)
354 {
355     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
356     ULONG ref = InterlockedIncrement(&This->ref2);
357
358     TRACE("%p increasing refcount to %u.\n", This, ref);
359
360     if (ref == 1) InterlockedIncrement(&This->numIfaces);
361
362     return ref;
363 }
364
365 static ULONG WINAPI ddraw1_AddRef(IDirectDraw *iface)
366 {
367     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
368     ULONG ref = InterlockedIncrement(&This->ref1);
369
370     TRACE("%p increasing refcount to %u.\n", This, ref);
371
372     if (ref == 1) InterlockedIncrement(&This->numIfaces);
373
374     return ref;
375 }
376
377 static ULONG WINAPI d3d7_AddRef(IDirect3D7 *iface)
378 {
379     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
380
381     TRACE("iface %p.\n", iface);
382
383     return ddraw7_AddRef(&This->IDirectDraw7_iface);
384 }
385
386 static ULONG WINAPI d3d3_AddRef(IDirect3D3 *iface)
387 {
388     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
389
390     TRACE("iface %p.\n", iface);
391
392     return ddraw1_AddRef(&This->IDirectDraw_iface);
393 }
394
395 static ULONG WINAPI d3d2_AddRef(IDirect3D2 *iface)
396 {
397     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
398
399     TRACE("iface %p.\n", iface);
400
401     return ddraw1_AddRef(&This->IDirectDraw_iface);
402 }
403
404 static ULONG WINAPI d3d1_AddRef(IDirect3D *iface)
405 {
406     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
407
408     TRACE("iface %p.\n", iface);
409
410     return ddraw1_AddRef(&This->IDirectDraw_iface);
411 }
412
413 /*****************************************************************************
414  * ddraw_destroy
415  *
416  * Destroys a ddraw object if all refcounts are 0. This is to share code
417  * between the IDirectDrawX::Release functions
418  *
419  * Params:
420  *  This: DirectDraw object to destroy
421  *
422  *****************************************************************************/
423 static void ddraw_destroy(IDirectDrawImpl *This)
424 {
425     IDirectDraw7_SetCooperativeLevel(&This->IDirectDraw7_iface, NULL, DDSCL_NORMAL);
426     IDirectDraw7_RestoreDisplayMode(&This->IDirectDraw7_iface);
427
428     /* Destroy the device window if we created one */
429     if(This->devicewindow != 0)
430     {
431         TRACE(" (%p) Destroying the device window %p\n", This, This->devicewindow);
432         DestroyWindow(This->devicewindow);
433         This->devicewindow = 0;
434     }
435
436     EnterCriticalSection(&ddraw_cs);
437     list_remove(&This->ddraw_list_entry);
438     LeaveCriticalSection(&ddraw_cs);
439
440     /* Release the attached WineD3D stuff */
441     wined3d_device_decref(This->wined3d_device);
442     wined3d_decref(This->wineD3D);
443
444     /* Now free the object */
445     HeapFree(GetProcessHeap(), 0, This);
446 }
447
448 /*****************************************************************************
449  * IDirectDraw7::Release
450  *
451  * Decreases the refcount. If the refcount falls to 0, the object is destroyed
452  *
453  * Returns: The new refcount
454  *****************************************************************************/
455 static ULONG WINAPI ddraw7_Release(IDirectDraw7 *iface)
456 {
457     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
458     ULONG ref = InterlockedDecrement(&This->ref7);
459
460     TRACE("%p decreasing refcount to %u.\n", This, ref);
461
462     if (!ref && !InterlockedDecrement(&This->numIfaces))
463         ddraw_destroy(This);
464
465     return ref;
466 }
467
468 static ULONG WINAPI ddraw4_Release(IDirectDraw4 *iface)
469 {
470     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
471     ULONG ref = InterlockedDecrement(&This->ref4);
472
473     TRACE("%p decreasing refcount to %u.\n", This, ref);
474
475     if (!ref && !InterlockedDecrement(&This->numIfaces))
476         ddraw_destroy(This);
477
478     return ref;
479 }
480
481 static ULONG WINAPI ddraw2_Release(IDirectDraw2 *iface)
482 {
483     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
484     ULONG ref = InterlockedDecrement(&This->ref2);
485
486     TRACE("%p decreasing refcount to %u.\n", This, ref);
487
488     if (!ref && !InterlockedDecrement(&This->numIfaces))
489         ddraw_destroy(This);
490
491     return ref;
492 }
493
494 static ULONG WINAPI ddraw1_Release(IDirectDraw *iface)
495 {
496     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
497     ULONG ref = InterlockedDecrement(&This->ref1);
498
499     TRACE("%p decreasing refcount to %u.\n", This, ref);
500
501     if (!ref && !InterlockedDecrement(&This->numIfaces))
502         ddraw_destroy(This);
503
504     return ref;
505 }
506
507 static ULONG WINAPI d3d7_Release(IDirect3D7 *iface)
508 {
509     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
510
511     TRACE("iface %p.\n", iface);
512
513     return ddraw7_Release(&This->IDirectDraw7_iface);
514 }
515
516 static ULONG WINAPI d3d3_Release(IDirect3D3 *iface)
517 {
518     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
519
520     TRACE("iface %p.\n", iface);
521
522     return ddraw1_Release(&This->IDirectDraw_iface);
523 }
524
525 static ULONG WINAPI d3d2_Release(IDirect3D2 *iface)
526 {
527     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
528
529     TRACE("iface %p.\n", iface);
530
531     return ddraw1_Release(&This->IDirectDraw_iface);
532 }
533
534 static ULONG WINAPI d3d1_Release(IDirect3D *iface)
535 {
536     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
537
538     TRACE("iface %p.\n", iface);
539
540     return ddraw1_Release(&This->IDirectDraw_iface);
541 }
542
543 /*****************************************************************************
544  * IDirectDraw methods
545  *****************************************************************************/
546
547 static HRESULT ddraw_set_focus_window(IDirectDrawImpl *ddraw, HWND window)
548 {
549     /* FIXME: This looks wrong, exclusive mode should imply a destination
550      * window. */
551     if ((ddraw->cooperative_level & DDSCL_EXCLUSIVE) && ddraw->dest_window)
552     {
553         TRACE("Setting DDSCL_SETFOCUSWINDOW with an already set window, returning DDERR_HWNDALREADYSET.\n");
554         return DDERR_HWNDALREADYSET;
555     }
556
557     ddraw->focuswindow = window;
558
559     /* Use the focus window for drawing too. */
560     ddraw->dest_window = ddraw->focuswindow;
561
562     /* Destroy the device window, if we have one. */
563     if (ddraw->devicewindow)
564     {
565         DestroyWindow(ddraw->devicewindow);
566         ddraw->devicewindow = NULL;
567     }
568
569     return DD_OK;
570 }
571
572 /*****************************************************************************
573  * IDirectDraw7::SetCooperativeLevel
574  *
575  * Sets the cooperative level for the DirectDraw object, and the window
576  * assigned to it. The cooperative level determines the general behavior
577  * of the DirectDraw application
578  *
579  * Warning: This is quite tricky, as it's not really documented which
580  * cooperative levels can be combined with each other. If a game fails
581  * after this function, try to check the cooperative levels passed on
582  * Windows, and if it returns something different.
583  *
584  * If you think that this function caused the failure because it writes a
585  * fixme, be sure to run again with a +ddraw trace.
586  *
587  * What is known about cooperative levels (See the ddraw modes test):
588  * DDSCL_EXCLUSIVE and DDSCL_FULLSCREEN must be used with each other
589  * DDSCL_NORMAL is not compatible with DDSCL_EXCLUSIVE or DDSCL_FULLSCREEN
590  * DDSCL_SETFOCUSWINDOW can be passed only in DDSCL_NORMAL mode, but after that
591  * DDSCL_FULLSCREEN can be activated
592  * DDSCL_SETFOCUSWINDOW may only be used with DDSCL_NOWINDOWCHANGES
593  *
594  * Handled flags: DDSCL_NORMAL, DDSCL_FULLSCREEN, DDSCL_EXCLUSIVE,
595  *                DDSCL_SETFOCUSWINDOW (partially),
596  *                DDSCL_MULTITHREADED (work in progress)
597  *
598  * Unhandled flags, which should be implemented
599  *  DDSCL_SETDEVICEWINDOW: Sets a window specially used for rendering (I don't
600  *  expect any difference to a normal window for wine)
601  *  DDSCL_CREATEDEVICEWINDOW: Tells ddraw to create its own window for
602  *  rendering (Possible test case: Half-Life)
603  *
604  * Unsure about these: DDSCL_FPUSETUP DDSCL_FPURESERVE
605  *
606  * These don't seem very important for wine:
607  *  DDSCL_ALLOWREBOOT, DDSCL_NOWINDOWCHANGES, DDSCL_ALLOWMODEX
608  *
609  * Returns:
610  *  DD_OK if the cooperative level was set successfully
611  *  DDERR_INVALIDPARAMS if the passed cooperative level combination is invalid
612  *  DDERR_HWNDALREADYSET if DDSCL_SETFOCUSWINDOW is passed in exclusive mode
613  *   (Probably others too, have to investigate)
614  *
615  *****************************************************************************/
616 static HRESULT WINAPI ddraw7_SetCooperativeLevel(IDirectDraw7 *iface, HWND hwnd, DWORD cooplevel)
617 {
618     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
619     HWND window;
620     HRESULT hr;
621
622     TRACE("iface %p, window %p, flags %#x.\n", iface, hwnd, cooplevel);
623     DDRAW_dump_cooperativelevel(cooplevel);
624
625     EnterCriticalSection(&ddraw_cs);
626
627     /* Get the old window */
628     window = This->dest_window;
629
630     /* Tests suggest that we need one of them: */
631     if(!(cooplevel & (DDSCL_SETFOCUSWINDOW |
632                       DDSCL_NORMAL         |
633                       DDSCL_EXCLUSIVE      )))
634     {
635         TRACE("Incorrect cooplevel flags, returning DDERR_INVALIDPARAMS\n");
636         LeaveCriticalSection(&ddraw_cs);
637         return DDERR_INVALIDPARAMS;
638     }
639
640     /* Handle those levels first which set various hwnds */
641     if(cooplevel & DDSCL_SETFOCUSWINDOW)
642     {
643         /* This isn't compatible with a lot of flags */
644         if(cooplevel & ( DDSCL_MULTITHREADED      |
645                          DDSCL_CREATEDEVICEWINDOW |
646                          DDSCL_FPUSETUP           |
647                          DDSCL_FPUPRESERVE        |
648                          DDSCL_ALLOWREBOOT        |
649                          DDSCL_ALLOWMODEX         |
650                          DDSCL_SETDEVICEWINDOW    |
651                          DDSCL_NORMAL             |
652                          DDSCL_EXCLUSIVE          |
653                          DDSCL_FULLSCREEN         ) )
654         {
655             TRACE("Called with incompatible flags, returning DDERR_INVALIDPARAMS\n");
656             LeaveCriticalSection(&ddraw_cs);
657             return DDERR_INVALIDPARAMS;
658         }
659
660         hr = ddraw_set_focus_window(This, hwnd);
661         LeaveCriticalSection(&ddraw_cs);
662         return hr;
663     }
664
665     if(cooplevel & DDSCL_EXCLUSIVE)
666     {
667         if( !(cooplevel & DDSCL_FULLSCREEN) || !hwnd )
668         {
669             TRACE("(%p) DDSCL_EXCLUSIVE needs DDSCL_FULLSCREEN and a window\n", This);
670             LeaveCriticalSection(&ddraw_cs);
671             return DDERR_INVALIDPARAMS;
672         }
673     }
674
675     if ((This->cooperative_level & DDSCL_EXCLUSIVE)
676             && (hwnd != window || !(cooplevel & DDSCL_EXCLUSIVE)))
677         wined3d_device_release_focus_window(This->wined3d_device);
678
679     if ((cooplevel & DDSCL_FULLSCREEN) != (This->cooperative_level & DDSCL_FULLSCREEN) || hwnd != window)
680     {
681         if (This->cooperative_level & DDSCL_FULLSCREEN)
682             wined3d_device_restore_fullscreen_window(This->wined3d_device, window);
683
684         if (cooplevel & DDSCL_FULLSCREEN)
685         {
686             WINED3DDISPLAYMODE display_mode;
687
688             wined3d_get_adapter_display_mode(This->wineD3D, WINED3DADAPTER_DEFAULT, &display_mode);
689             wined3d_device_setup_fullscreen_window(This->wined3d_device, hwnd,
690                     display_mode.Width, display_mode.Height);
691         }
692     }
693
694     if ((cooplevel & DDSCL_EXCLUSIVE)
695             && (hwnd != window || !(This->cooperative_level & DDSCL_EXCLUSIVE)))
696     {
697         hr = wined3d_device_acquire_focus_window(This->wined3d_device, hwnd);
698         if (FAILED(hr))
699         {
700             ERR("Failed to acquire focus window, hr %#x.\n", hr);
701             LeaveCriticalSection(&ddraw_cs);
702             return hr;
703         }
704     }
705
706     /* Don't override focus windows or private device windows */
707     if (hwnd && !This->focuswindow && !This->devicewindow && (hwnd != window))
708         This->dest_window = hwnd;
709
710     if(cooplevel & DDSCL_CREATEDEVICEWINDOW)
711     {
712         /* Don't create a device window if a focus window is set */
713         if( !(This->focuswindow) )
714         {
715             HWND devicewindow = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "DDraw device window",
716                     WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
717                     NULL, NULL, NULL, NULL);
718             if (!devicewindow)
719             {
720                 ERR("Failed to create window, last error %#x.\n", GetLastError());
721                 LeaveCriticalSection(&ddraw_cs);
722                 return E_FAIL;
723             }
724
725             ShowWindow(devicewindow, SW_SHOW);   /* Just to be sure */
726             TRACE("(%p) Created a DDraw device window. HWND=%p\n", This, devicewindow);
727
728             This->devicewindow = devicewindow;
729             This->dest_window = devicewindow;
730         }
731     }
732
733     if (cooplevel & DDSCL_MULTITHREADED && !(This->cooperative_level & DDSCL_MULTITHREADED))
734         wined3d_device_set_multithreaded(This->wined3d_device);
735
736     /* Unhandled flags */
737     if(cooplevel & DDSCL_ALLOWREBOOT)
738         WARN("(%p) Unhandled flag DDSCL_ALLOWREBOOT, harmless\n", This);
739     if(cooplevel & DDSCL_ALLOWMODEX)
740         WARN("(%p) Unhandled flag DDSCL_ALLOWMODEX, harmless\n", This);
741     if(cooplevel & DDSCL_FPUSETUP)
742         WARN("(%p) Unhandled flag DDSCL_FPUSETUP, harmless\n", This);
743
744     /* Store the cooperative_level */
745     This->cooperative_level = cooplevel;
746     TRACE("SetCooperativeLevel retuning DD_OK\n");
747     LeaveCriticalSection(&ddraw_cs);
748     return DD_OK;
749 }
750
751 static HRESULT WINAPI ddraw4_SetCooperativeLevel(IDirectDraw4 *iface, HWND window, DWORD flags)
752 {
753     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
754
755     TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
756
757     return ddraw7_SetCooperativeLevel(&This->IDirectDraw7_iface, window, flags);
758 }
759
760 static HRESULT WINAPI ddraw2_SetCooperativeLevel(IDirectDraw2 *iface, HWND window, DWORD flags)
761 {
762     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
763
764     TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
765
766     return ddraw7_SetCooperativeLevel(&This->IDirectDraw7_iface, window, flags);
767 }
768
769 static HRESULT WINAPI ddraw1_SetCooperativeLevel(IDirectDraw *iface, HWND window, DWORD flags)
770 {
771     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
772
773     TRACE("iface %p, window %p, flags %#x.\n", iface, window, flags);
774
775     return ddraw7_SetCooperativeLevel(&This->IDirectDraw7_iface, window, flags);
776 }
777
778 /*****************************************************************************
779  *
780  * Helper function for SetDisplayMode and RestoreDisplayMode
781  *
782  * Implements DirectDraw's SetDisplayMode, but ignores the value of
783  * ForceRefreshRate, since it is already handled by
784  * ddraw7_SetDisplayMode.  RestoreDisplayMode can use this function
785  * without worrying that ForceRefreshRate will override the refresh rate.  For
786  * argument and return value documentation, see
787  * ddraw7_SetDisplayMode.
788  *
789  *****************************************************************************/
790 static HRESULT ddraw_set_display_mode(IDirectDrawImpl *ddraw, DWORD Width, DWORD Height,
791         DWORD BPP, DWORD RefreshRate, DWORD Flags)
792 {
793     enum wined3d_format_id format;
794     WINED3DDISPLAYMODE Mode;
795     HRESULT hr;
796
797     TRACE("ddraw %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n", ddraw, Width,
798             Height, BPP, RefreshRate, Flags);
799
800     EnterCriticalSection(&ddraw_cs);
801     if( !Width || !Height )
802     {
803         ERR("Width %u, Height %u, what to do?\n", Width, Height);
804         /* It looks like Need for Speed Porsche Unleashed expects DD_OK here */
805         LeaveCriticalSection(&ddraw_cs);
806         return DD_OK;
807     }
808
809     switch(BPP)
810     {
811         case 8:  format = WINED3DFMT_P8_UINT;          break;
812         case 15: format = WINED3DFMT_B5G5R5X1_UNORM;   break;
813         case 16: format = WINED3DFMT_B5G6R5_UNORM;     break;
814         case 24: format = WINED3DFMT_B8G8R8_UNORM;     break;
815         case 32: format = WINED3DFMT_B8G8R8X8_UNORM;   break;
816         default: format = WINED3DFMT_UNKNOWN;          break;
817     }
818
819     if (FAILED(hr = wined3d_device_get_display_mode(ddraw->wined3d_device, 0, &Mode)))
820     {
821         ERR("Failed to get current display mode, hr %#x.\n", hr);
822     }
823     else if (Mode.Width == Width
824             && Mode.Height == Height
825             && Mode.Format == format
826             && Mode.RefreshRate == RefreshRate)
827     {
828         TRACE("Skipping redundant mode setting call.\n");
829         LeaveCriticalSection(&ddraw_cs);
830         return DD_OK;
831     }
832
833     /* Check the exclusive mode
834     if(!(ddraw->cooperative_level & DDSCL_EXCLUSIVE))
835         return DDERR_NOEXCLUSIVEMODE;
836      * This is WRONG. Don't know if the SDK is completely
837      * wrong and if there are any conditions when DDERR_NOEXCLUSIVE
838      * is returned, but Half-Life 1.1.1.1 (Steam version)
839      * depends on this
840      */
841
842     Mode.Width = Width;
843     Mode.Height = Height;
844     Mode.RefreshRate = RefreshRate;
845     Mode.Format = format;
846
847     /* TODO: The possible return values from msdn suggest that
848      * the screen mode can't be changed if a surface is locked
849      * or some drawing is in progress
850      */
851
852     /* TODO: Lose the primary surface */
853     hr = wined3d_device_set_display_mode(ddraw->wined3d_device, 0, &Mode);
854
855     if (ddraw->cooperative_level & DDSCL_EXCLUSIVE)
856         SetWindowPos(ddraw->dest_window, HWND_TOP, 0, 0, Width, Height, SWP_SHOWWINDOW | SWP_NOACTIVATE);
857
858     LeaveCriticalSection(&ddraw_cs);
859     switch(hr)
860     {
861         case WINED3DERR_NOTAVAILABLE:       return DDERR_UNSUPPORTED;
862         default:                            return hr;
863     }
864 }
865
866 /*****************************************************************************
867  * IDirectDraw7::SetDisplayMode
868  *
869  * Sets the display screen resolution, color depth and refresh frequency
870  * when in fullscreen mode (in theory).
871  * Possible return values listed in the SDK suggest that this method fails
872  * when not in fullscreen mode, but this is wrong. Windows 2000 happily sets
873  * the display mode in DDSCL_NORMAL mode without an hwnd specified.
874  * It seems to be valid to pass 0 for With and Height, this has to be tested
875  * It could mean that the current video mode should be left as-is. (But why
876  * call it then?)
877  *
878  * Params:
879  *  Height, Width: Screen dimension
880  *  BPP: Color depth in Bits per pixel
881  *  Refreshrate: Screen refresh rate
882  *  Flags: Other stuff
883  *
884  * Returns
885  *  DD_OK on success
886  *
887  *****************************************************************************/
888 static HRESULT WINAPI ddraw7_SetDisplayMode(IDirectDraw7 *iface, DWORD Width, DWORD Height,
889         DWORD BPP, DWORD RefreshRate, DWORD Flags)
890 {
891     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
892
893     TRACE("iface %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n",
894             iface, Width, Height, BPP, RefreshRate, Flags);
895
896     if (force_refresh_rate != 0)
897     {
898         TRACE("ForceRefreshRate overriding passed-in refresh rate (%u Hz) to %u Hz\n",
899                 RefreshRate, force_refresh_rate);
900         RefreshRate = force_refresh_rate;
901     }
902
903     return ddraw_set_display_mode(This, Width, Height, BPP, RefreshRate, Flags);
904 }
905
906 static HRESULT WINAPI ddraw4_SetDisplayMode(IDirectDraw4 *iface, DWORD width, DWORD height,
907         DWORD bpp, DWORD refresh_rate, DWORD flags)
908 {
909     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
910
911     TRACE("iface %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n",
912             iface, width, height, bpp, refresh_rate, flags);
913
914     return ddraw7_SetDisplayMode(&This->IDirectDraw7_iface, width, height, bpp, refresh_rate, flags);
915 }
916
917 static HRESULT WINAPI ddraw2_SetDisplayMode(IDirectDraw2 *iface,
918         DWORD width, DWORD height, DWORD bpp, DWORD refresh_rate, DWORD flags)
919 {
920     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
921
922     TRACE("iface %p, width %u, height %u, bpp %u, refresh_rate %u, flags %#x.\n",
923             iface, width, height, bpp, refresh_rate, flags);
924
925     return ddraw7_SetDisplayMode(&This->IDirectDraw7_iface, width, height, bpp, refresh_rate, flags);
926 }
927
928 static HRESULT WINAPI ddraw1_SetDisplayMode(IDirectDraw *iface, DWORD width, DWORD height, DWORD bpp)
929 {
930     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
931
932     TRACE("iface %p, width %u, height %u, bpp %u.\n", iface, width, height, bpp);
933
934     return ddraw7_SetDisplayMode(&This->IDirectDraw7_iface, width, height, bpp, 0, 0);
935 }
936
937 /*****************************************************************************
938  * IDirectDraw7::RestoreDisplayMode
939  *
940  * Restores the display mode to what it was at creation time. Basically.
941  *
942  * A problem arises when there are 2 DirectDraw objects using the same hwnd:
943  *  -> DD_1 finds the screen at 1400x1050x32 when created, sets it to 640x480x16
944  *  -> DD_2 is created, finds the screen at 640x480x16, sets it to 1024x768x32
945  *  -> DD_1 is released. The screen should be left at 1024x768x32.
946  *  -> DD_2 is released. The screen should be set to 1400x1050x32
947  * This case is unhandled right now, but Empire Earth does it this way.
948  * (But perhaps there is something in SetCooperativeLevel to prevent this)
949  *
950  * The msdn says that this method resets the display mode to what it was before
951  * SetDisplayMode was called. What if SetDisplayModes is called 2 times??
952  *
953  * Returns
954  *  DD_OK on success
955  *  DDERR_NOEXCLUSIVE mode if the device isn't in fullscreen mode
956  *
957  *****************************************************************************/
958 static HRESULT WINAPI ddraw7_RestoreDisplayMode(IDirectDraw7 *iface)
959 {
960     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
961
962     TRACE("iface %p.\n", iface);
963
964     return ddraw_set_display_mode(This, This->orig_width, This->orig_height, This->orig_bpp, 0, 0);
965 }
966
967 static HRESULT WINAPI ddraw4_RestoreDisplayMode(IDirectDraw4 *iface)
968 {
969     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
970
971     TRACE("iface %p.\n", iface);
972
973     return ddraw7_RestoreDisplayMode(&This->IDirectDraw7_iface);
974 }
975
976 static HRESULT WINAPI ddraw2_RestoreDisplayMode(IDirectDraw2 *iface)
977 {
978     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
979
980     TRACE("iface %p.\n", iface);
981
982     return ddraw7_RestoreDisplayMode(&This->IDirectDraw7_iface);
983 }
984
985 static HRESULT WINAPI ddraw1_RestoreDisplayMode(IDirectDraw *iface)
986 {
987     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
988
989     TRACE("iface %p.\n", iface);
990
991     return ddraw7_RestoreDisplayMode(&This->IDirectDraw7_iface);
992 }
993
994 /*****************************************************************************
995  * IDirectDraw7::GetCaps
996  *
997  * Returns the drives capabilities
998  *
999  * Used for version 1, 2, 4 and 7
1000  *
1001  * Params:
1002  *  DriverCaps: Structure to write the Hardware accelerated caps to
1003  *  HelCaps: Structure to write the emulation caps to
1004  *
1005  * Returns
1006  *  This implementation returns DD_OK only
1007  *
1008  *****************************************************************************/
1009 static HRESULT WINAPI ddraw7_GetCaps(IDirectDraw7 *iface, DDCAPS *DriverCaps, DDCAPS *HELCaps)
1010 {
1011     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1012     DDCAPS caps;
1013     WINED3DCAPS winecaps;
1014     HRESULT hr;
1015     DDSCAPS2 ddscaps = {0, 0, 0, 0};
1016
1017     TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, DriverCaps, HELCaps);
1018
1019     /* One structure must be != NULL */
1020     if( (!DriverCaps) && (!HELCaps) )
1021     {
1022         ERR("(%p) Invalid params to ddraw7_GetCaps\n", This);
1023         return DDERR_INVALIDPARAMS;
1024     }
1025
1026     memset(&caps, 0, sizeof(caps));
1027     memset(&winecaps, 0, sizeof(winecaps));
1028     caps.dwSize = sizeof(caps);
1029     EnterCriticalSection(&ddraw_cs);
1030     hr = wined3d_device_get_device_caps(This->wined3d_device, &winecaps);
1031     if (FAILED(hr))
1032     {
1033         WARN("IWineD3DDevice::GetDeviceCaps failed\n");
1034         LeaveCriticalSection(&ddraw_cs);
1035         return hr;
1036     }
1037
1038     hr = IDirectDraw7_GetAvailableVidMem(iface, &ddscaps, &caps.dwVidMemTotal, &caps.dwVidMemFree);
1039     LeaveCriticalSection(&ddraw_cs);
1040     if(FAILED(hr)) {
1041         WARN("IDirectDraw7::GetAvailableVidMem failed\n");
1042         return hr;
1043     }
1044
1045     caps.dwCaps = winecaps.DirectDrawCaps.Caps;
1046     caps.dwCaps2 = winecaps.DirectDrawCaps.Caps2;
1047     caps.dwCKeyCaps = winecaps.DirectDrawCaps.CKeyCaps;
1048     caps.dwFXCaps = winecaps.DirectDrawCaps.FXCaps;
1049     caps.dwPalCaps = winecaps.DirectDrawCaps.PalCaps;
1050     caps.ddsCaps.dwCaps = winecaps.DirectDrawCaps.ddsCaps;
1051     caps.dwSVBCaps = winecaps.DirectDrawCaps.SVBCaps;
1052     caps.dwSVBCKeyCaps = winecaps.DirectDrawCaps.SVBCKeyCaps;
1053     caps.dwSVBFXCaps = winecaps.DirectDrawCaps.SVBFXCaps;
1054     caps.dwVSBCaps = winecaps.DirectDrawCaps.VSBCaps;
1055     caps.dwVSBCKeyCaps = winecaps.DirectDrawCaps.VSBCKeyCaps;
1056     caps.dwVSBFXCaps = winecaps.DirectDrawCaps.VSBFXCaps;
1057     caps.dwSSBCaps = winecaps.DirectDrawCaps.SSBCaps;
1058     caps.dwSSBCKeyCaps = winecaps.DirectDrawCaps.SSBCKeyCaps;
1059     caps.dwSSBFXCaps = winecaps.DirectDrawCaps.SSBFXCaps;
1060
1061     /* Even if WineD3D supports 3D rendering, remove the cap if ddraw is configured
1062      * not to use it
1063      */
1064     if(DefaultSurfaceType == SURFACE_GDI) {
1065         caps.dwCaps &= ~DDCAPS_3D;
1066         caps.ddsCaps.dwCaps &= ~(DDSCAPS_3DDEVICE | DDSCAPS_MIPMAP | DDSCAPS_TEXTURE | DDSCAPS_ZBUFFER);
1067     }
1068     if(winecaps.DirectDrawCaps.StrideAlign != 0) {
1069         caps.dwCaps |= DDCAPS_ALIGNSTRIDE;
1070         caps.dwAlignStrideAlign = winecaps.DirectDrawCaps.StrideAlign;
1071     }
1072
1073     if(DriverCaps)
1074     {
1075         DD_STRUCT_COPY_BYSIZE(DriverCaps, &caps);
1076         if (TRACE_ON(ddraw))
1077         {
1078             TRACE("Driver Caps :\n");
1079             DDRAW_dump_DDCAPS(DriverCaps);
1080         }
1081
1082     }
1083     if(HELCaps)
1084     {
1085         DD_STRUCT_COPY_BYSIZE(HELCaps, &caps);
1086         if (TRACE_ON(ddraw))
1087         {
1088             TRACE("HEL Caps :\n");
1089             DDRAW_dump_DDCAPS(HELCaps);
1090         }
1091     }
1092
1093     return DD_OK;
1094 }
1095
1096 static HRESULT WINAPI ddraw4_GetCaps(IDirectDraw4 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1097 {
1098     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1099
1100     TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1101
1102     return ddraw7_GetCaps(&This->IDirectDraw7_iface, driver_caps, hel_caps);
1103 }
1104
1105 static HRESULT WINAPI ddraw2_GetCaps(IDirectDraw2 *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1106 {
1107     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1108
1109     TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1110
1111     return ddraw7_GetCaps(&This->IDirectDraw7_iface, driver_caps, hel_caps);
1112 }
1113
1114 static HRESULT WINAPI ddraw1_GetCaps(IDirectDraw *iface, DDCAPS *driver_caps, DDCAPS *hel_caps)
1115 {
1116     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1117
1118     TRACE("iface %p, driver_caps %p, hel_caps %p.\n", iface, driver_caps, hel_caps);
1119
1120     return ddraw7_GetCaps(&This->IDirectDraw7_iface, driver_caps, hel_caps);
1121 }
1122
1123 /*****************************************************************************
1124  * IDirectDraw7::Compact
1125  *
1126  * No idea what it does, MSDN says it's not implemented.
1127  *
1128  * Returns
1129  *  DD_OK, but this is unchecked
1130  *
1131  *****************************************************************************/
1132 static HRESULT WINAPI ddraw7_Compact(IDirectDraw7 *iface)
1133 {
1134     TRACE("iface %p.\n", iface);
1135
1136     return DD_OK;
1137 }
1138
1139 static HRESULT WINAPI ddraw4_Compact(IDirectDraw4 *iface)
1140 {
1141     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1142
1143     TRACE("iface %p.\n", iface);
1144
1145     return ddraw7_Compact(&This->IDirectDraw7_iface);
1146 }
1147
1148 static HRESULT WINAPI ddraw2_Compact(IDirectDraw2 *iface)
1149 {
1150     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1151
1152     TRACE("iface %p.\n", iface);
1153
1154     return ddraw7_Compact(&This->IDirectDraw7_iface);
1155 }
1156
1157 static HRESULT WINAPI ddraw1_Compact(IDirectDraw *iface)
1158 {
1159     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1160
1161     TRACE("iface %p.\n", iface);
1162
1163     return ddraw7_Compact(&This->IDirectDraw7_iface);
1164 }
1165
1166 /*****************************************************************************
1167  * IDirectDraw7::GetDisplayMode
1168  *
1169  * Returns information about the current display mode
1170  *
1171  * Exists in Version 1, 2, 4 and 7
1172  *
1173  * Params:
1174  *  DDSD: Address of a surface description structure to write the info to
1175  *
1176  * Returns
1177  *  DD_OK
1178  *
1179  *****************************************************************************/
1180 static HRESULT WINAPI ddraw7_GetDisplayMode(IDirectDraw7 *iface, DDSURFACEDESC2 *DDSD)
1181 {
1182     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1183     HRESULT hr;
1184     WINED3DDISPLAYMODE Mode;
1185     DWORD Size;
1186
1187     TRACE("iface %p, surface_desc %p.\n", iface, DDSD);
1188
1189     EnterCriticalSection(&ddraw_cs);
1190     /* This seems sane */
1191     if (!DDSD)
1192     {
1193         LeaveCriticalSection(&ddraw_cs);
1194         return DDERR_INVALIDPARAMS;
1195     }
1196
1197     /* The necessary members of LPDDSURFACEDESC and LPDDSURFACEDESC2 are equal,
1198      * so one method can be used for all versions (Hopefully) */
1199     hr = wined3d_device_get_display_mode(This->wined3d_device, 0, &Mode);
1200     if (FAILED(hr))
1201     {
1202         ERR(" (%p) IWineD3DDevice::GetDisplayMode returned %08x\n", This, hr);
1203         LeaveCriticalSection(&ddraw_cs);
1204         return hr;
1205     }
1206
1207     Size = DDSD->dwSize;
1208     memset(DDSD, 0, Size);
1209
1210     DDSD->dwSize = Size;
1211     DDSD->dwFlags |= DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_PITCH | DDSD_REFRESHRATE;
1212     DDSD->dwWidth = Mode.Width;
1213     DDSD->dwHeight = Mode.Height;
1214     DDSD->u2.dwRefreshRate = 60;
1215     DDSD->ddsCaps.dwCaps = 0;
1216     DDSD->u4.ddpfPixelFormat.dwSize = sizeof(DDSD->u4.ddpfPixelFormat);
1217     PixelFormat_WineD3DtoDD(&DDSD->u4.ddpfPixelFormat, Mode.Format);
1218     DDSD->u1.lPitch = Mode.Width * DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount / 8;
1219
1220     if(TRACE_ON(ddraw))
1221     {
1222         TRACE("Returning surface desc :\n");
1223         DDRAW_dump_surface_desc(DDSD);
1224     }
1225
1226     LeaveCriticalSection(&ddraw_cs);
1227     return DD_OK;
1228 }
1229
1230 static HRESULT WINAPI ddraw4_GetDisplayMode(IDirectDraw4 *iface, DDSURFACEDESC2 *surface_desc)
1231 {
1232     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1233
1234     TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1235
1236     return ddraw7_GetDisplayMode(&This->IDirectDraw7_iface, surface_desc);
1237 }
1238
1239 static HRESULT WINAPI ddraw2_GetDisplayMode(IDirectDraw2 *iface, DDSURFACEDESC *surface_desc)
1240 {
1241     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1242
1243     TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1244
1245     /* FIXME: Test sizes, properly convert surface_desc */
1246     return ddraw7_GetDisplayMode(&This->IDirectDraw7_iface, (DDSURFACEDESC2 *)surface_desc);
1247 }
1248
1249 static HRESULT WINAPI ddraw1_GetDisplayMode(IDirectDraw *iface, DDSURFACEDESC *surface_desc)
1250 {
1251     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1252
1253     TRACE("iface %p, surface_desc %p.\n", iface, surface_desc);
1254
1255     /* FIXME: Test sizes, properly convert surface_desc */
1256     return ddraw7_GetDisplayMode(&This->IDirectDraw7_iface, (DDSURFACEDESC2 *)surface_desc);
1257 }
1258
1259 /*****************************************************************************
1260  * IDirectDraw7::GetFourCCCodes
1261  *
1262  * Returns an array of supported FourCC codes.
1263  *
1264  * Exists in Version 1, 2, 4 and 7
1265  *
1266  * Params:
1267  *  NumCodes: Contains the number of Codes that Codes can carry. Returns the number
1268  *            of enumerated codes
1269  *  Codes: Pointer to an array of DWORDs where the supported codes are written
1270  *         to
1271  *
1272  * Returns
1273  *  Always returns DD_OK, as it's a stub for now
1274  *
1275  *****************************************************************************/
1276 static HRESULT WINAPI ddraw7_GetFourCCCodes(IDirectDraw7 *iface, DWORD *NumCodes, DWORD *Codes)
1277 {
1278     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1279     static const enum wined3d_format_id formats[] =
1280     {
1281         WINED3DFMT_YUY2, WINED3DFMT_UYVY, WINED3DFMT_YV12,
1282         WINED3DFMT_DXT1, WINED3DFMT_DXT2, WINED3DFMT_DXT3, WINED3DFMT_DXT4, WINED3DFMT_DXT5,
1283         WINED3DFMT_ATI2N, WINED3DFMT_NVHU, WINED3DFMT_NVHS
1284     };
1285     DWORD count = 0, i, outsize;
1286     HRESULT hr;
1287     WINED3DDISPLAYMODE d3ddm;
1288
1289     TRACE("iface %p, codes_count %p, codes %p.\n", iface, NumCodes, Codes);
1290
1291     wined3d_device_get_display_mode(This->wined3d_device, 0, &d3ddm);
1292
1293     outsize = NumCodes && Codes ? *NumCodes : 0;
1294
1295     for (i = 0; i < (sizeof(formats) / sizeof(formats[0])); ++i)
1296     {
1297         hr = wined3d_check_device_format(This->wineD3D, WINED3DADAPTER_DEFAULT, WINED3DDEVTYPE_HAL,
1298                 d3ddm.Format, 0, WINED3DRTYPE_SURFACE, formats[i], DefaultSurfaceType);
1299         if (SUCCEEDED(hr))
1300         {
1301             if (count < outsize)
1302                 Codes[count] = formats[i];
1303             ++count;
1304         }
1305     }
1306     if(NumCodes) {
1307         TRACE("Returning %u FourCC codes\n", count);
1308         *NumCodes = count;
1309     }
1310
1311     return DD_OK;
1312 }
1313
1314 static HRESULT WINAPI ddraw4_GetFourCCCodes(IDirectDraw4 *iface, DWORD *codes_count, DWORD *codes)
1315 {
1316     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1317
1318     TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1319
1320     return ddraw7_GetFourCCCodes(&This->IDirectDraw7_iface, codes_count, codes);
1321 }
1322
1323 static HRESULT WINAPI ddraw2_GetFourCCCodes(IDirectDraw2 *iface, DWORD *codes_count, DWORD *codes)
1324 {
1325     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1326
1327     TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1328
1329     return ddraw7_GetFourCCCodes(&This->IDirectDraw7_iface, codes_count, codes);
1330 }
1331
1332 static HRESULT WINAPI ddraw1_GetFourCCCodes(IDirectDraw *iface, DWORD *codes_count, DWORD *codes)
1333 {
1334     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1335
1336     TRACE("iface %p, codes_count %p, codes %p.\n", iface, codes_count, codes);
1337
1338     return ddraw7_GetFourCCCodes(&This->IDirectDraw7_iface, codes_count, codes);
1339 }
1340
1341 /*****************************************************************************
1342  * IDirectDraw7::GetMonitorFrequency
1343  *
1344  * Returns the monitor's frequency
1345  *
1346  * Exists in Version 1, 2, 4 and 7
1347  *
1348  * Params:
1349  *  Freq: Pointer to a DWORD to write the frequency to
1350  *
1351  * Returns
1352  *  Always returns DD_OK
1353  *
1354  *****************************************************************************/
1355 static HRESULT WINAPI ddraw7_GetMonitorFrequency(IDirectDraw7 *iface, DWORD *Freq)
1356 {
1357     FIXME("iface %p, frequency %p stub!\n", iface, Freq);
1358
1359     /* Ideally this should be in WineD3D, as it concerns the screen setup,
1360      * but for now this should make the games happy
1361      */
1362     *Freq = 60;
1363     return DD_OK;
1364 }
1365
1366 static HRESULT WINAPI ddraw4_GetMonitorFrequency(IDirectDraw4 *iface, DWORD *frequency)
1367 {
1368     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1369
1370     TRACE("iface %p, frequency %p.\n", iface, frequency);
1371
1372     return ddraw7_GetMonitorFrequency(&This->IDirectDraw7_iface, frequency);
1373 }
1374
1375 static HRESULT WINAPI ddraw2_GetMonitorFrequency(IDirectDraw2 *iface, DWORD *frequency)
1376 {
1377     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1378
1379     TRACE("iface %p, frequency %p.\n", iface, frequency);
1380
1381     return ddraw7_GetMonitorFrequency(&This->IDirectDraw7_iface, frequency);
1382 }
1383
1384 static HRESULT WINAPI ddraw1_GetMonitorFrequency(IDirectDraw *iface, DWORD *frequency)
1385 {
1386     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1387
1388     TRACE("iface %p, frequency %p.\n", iface, frequency);
1389
1390     return ddraw7_GetMonitorFrequency(&This->IDirectDraw7_iface, frequency);
1391 }
1392
1393 /*****************************************************************************
1394  * IDirectDraw7::GetVerticalBlankStatus
1395  *
1396  * Returns the Vertical blank status of the monitor. This should be in WineD3D
1397  * too basically, but as it's a semi stub, I didn't create a function there
1398  *
1399  * Params:
1400  *  status: Pointer to a BOOL to be filled with the vertical blank status
1401  *
1402  * Returns
1403  *  DD_OK on success
1404  *  DDERR_INVALIDPARAMS if status is NULL
1405  *
1406  *****************************************************************************/
1407 static HRESULT WINAPI ddraw7_GetVerticalBlankStatus(IDirectDraw7 *iface, BOOL *status)
1408 {
1409     static BOOL fake_vblank;
1410
1411     TRACE("iface %p, status %p.\n", iface, status);
1412
1413     if(!status)
1414         return DDERR_INVALIDPARAMS;
1415
1416     *status = fake_vblank;
1417     fake_vblank = !fake_vblank;
1418
1419     return DD_OK;
1420 }
1421
1422 static HRESULT WINAPI ddraw4_GetVerticalBlankStatus(IDirectDraw4 *iface, BOOL *status)
1423 {
1424     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1425
1426     TRACE("iface %p, status %p.\n", iface, status);
1427
1428     return ddraw7_GetVerticalBlankStatus(&This->IDirectDraw7_iface, status);
1429 }
1430
1431 static HRESULT WINAPI ddraw2_GetVerticalBlankStatus(IDirectDraw2 *iface, BOOL *status)
1432 {
1433     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1434
1435     TRACE("iface %p, status %p.\n", iface, status);
1436
1437     return ddraw7_GetVerticalBlankStatus(&This->IDirectDraw7_iface, status);
1438 }
1439
1440 static HRESULT WINAPI ddraw1_GetVerticalBlankStatus(IDirectDraw *iface, BOOL *status)
1441 {
1442     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1443
1444     TRACE("iface %p, status %p.\n", iface, status);
1445
1446     return ddraw7_GetVerticalBlankStatus(&This->IDirectDraw7_iface, status);
1447 }
1448
1449 /*****************************************************************************
1450  * IDirectDraw7::GetAvailableVidMem
1451  *
1452  * Returns the total and free video memory
1453  *
1454  * Params:
1455  *  Caps: Specifies the memory type asked for
1456  *  total: Pointer to a DWORD to be filled with the total memory
1457  *  free: Pointer to a DWORD to be filled with the free memory
1458  *
1459  * Returns
1460  *  DD_OK on success
1461  *  DDERR_INVALIDPARAMS of free and total are NULL
1462  *
1463  *****************************************************************************/
1464 static HRESULT WINAPI ddraw7_GetAvailableVidMem(IDirectDraw7 *iface, DDSCAPS2 *Caps, DWORD *total,
1465         DWORD *free)
1466 {
1467     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1468     HRESULT hr = DD_OK;
1469
1470     TRACE("iface %p, caps %p, total %p, free %p.\n", iface, Caps, total, free);
1471
1472     if(TRACE_ON(ddraw))
1473     {
1474         TRACE("(%p) Asked for memory with description: ", This);
1475         DDRAW_dump_DDSCAPS2(Caps);
1476     }
1477     EnterCriticalSection(&ddraw_cs);
1478
1479     /* Todo: System memory vs local video memory vs non-local video memory
1480      * The MSDN also mentions differences between texture memory and other
1481      * resources, but that's not important
1482      */
1483
1484     if( (!total) && (!free) )
1485     {
1486         LeaveCriticalSection(&ddraw_cs);
1487         return DDERR_INVALIDPARAMS;
1488     }
1489
1490     if (free)
1491         *free = wined3d_device_get_available_texture_mem(This->wined3d_device);
1492     if (total)
1493     {
1494         WINED3DADAPTER_IDENTIFIER desc = {0};
1495
1496         hr = wined3d_get_adapter_identifier(This->wineD3D, WINED3DADAPTER_DEFAULT, 0, &desc);
1497         *total = desc.video_memory;
1498     }
1499
1500     LeaveCriticalSection(&ddraw_cs);
1501     return hr;
1502 }
1503
1504 static HRESULT WINAPI ddraw4_GetAvailableVidMem(IDirectDraw4 *iface,
1505         DDSCAPS2 *caps, DWORD *total, DWORD *free)
1506 {
1507     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1508
1509     TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1510
1511     return ddraw7_GetAvailableVidMem(&This->IDirectDraw7_iface, caps, total, free);
1512 }
1513
1514 static HRESULT WINAPI ddraw2_GetAvailableVidMem(IDirectDraw2 *iface,
1515         DDSCAPS *caps, DWORD *total, DWORD *free)
1516 {
1517     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1518     DDSCAPS2 caps2;
1519
1520     TRACE("iface %p, caps %p, total %p, free %p.\n", iface, caps, total, free);
1521
1522     DDRAW_Convert_DDSCAPS_1_To_2(caps, &caps2);
1523     return ddraw7_GetAvailableVidMem(&This->IDirectDraw7_iface, &caps2, total, free);
1524 }
1525
1526 /*****************************************************************************
1527  * IDirectDraw7::Initialize
1528  *
1529  * Initializes a DirectDraw interface.
1530  *
1531  * Params:
1532  *  GUID: Interface identifier. Well, don't know what this is really good
1533  *   for
1534  *
1535  * Returns
1536  *  Returns DD_OK on the first call,
1537  *  DDERR_ALREADYINITIALIZED on repeated calls
1538  *
1539  *****************************************************************************/
1540 static HRESULT WINAPI ddraw7_Initialize(IDirectDraw7 *iface, GUID *Guid)
1541 {
1542     FIXME("iface %p, guid %s stub!\n", iface, debugstr_guid(Guid));
1543
1544     return DDERR_ALREADYINITIALIZED;
1545 }
1546
1547 static HRESULT WINAPI ddraw4_Initialize(IDirectDraw4 *iface, GUID *guid)
1548 {
1549     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1550
1551     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1552
1553     return ddraw7_Initialize(&This->IDirectDraw7_iface, guid);
1554 }
1555
1556 static HRESULT WINAPI ddraw2_Initialize(IDirectDraw2 *iface, GUID *guid)
1557 {
1558     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1559
1560     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1561
1562     return ddraw7_Initialize(&This->IDirectDraw7_iface, guid);
1563 }
1564
1565 static HRESULT WINAPI ddraw1_Initialize(IDirectDraw *iface, GUID *guid)
1566 {
1567     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1568
1569     TRACE("iface %p, guid %s.\n", iface, debugstr_guid(guid));
1570
1571     return ddraw7_Initialize(&This->IDirectDraw7_iface, guid);
1572 }
1573
1574 static HRESULT WINAPI d3d1_Initialize(IDirect3D *iface, REFIID riid)
1575 {
1576     TRACE("iface %p, riid %s.\n", iface, debugstr_guid(riid));
1577
1578     return D3D_OK;
1579 }
1580
1581 /*****************************************************************************
1582  * IDirectDraw7::FlipToGDISurface
1583  *
1584  * "Makes the surface that the GDI writes to the primary surface"
1585  * Looks like some windows specific thing we don't have to care about.
1586  * According to MSDN it permits GDI dialog boxes in FULLSCREEN mode. Good to
1587  * show error boxes ;)
1588  * Well, just return DD_OK.
1589  *
1590  * Returns:
1591  *  Always returns DD_OK
1592  *
1593  *****************************************************************************/
1594 static HRESULT WINAPI ddraw7_FlipToGDISurface(IDirectDraw7 *iface)
1595 {
1596     FIXME("iface %p stub!\n", iface);
1597
1598     return DD_OK;
1599 }
1600
1601 static HRESULT WINAPI ddraw4_FlipToGDISurface(IDirectDraw4 *iface)
1602 {
1603     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1604
1605     TRACE("iface %p.\n", iface);
1606
1607     return ddraw7_FlipToGDISurface(&This->IDirectDraw7_iface);
1608 }
1609
1610 static HRESULT WINAPI ddraw2_FlipToGDISurface(IDirectDraw2 *iface)
1611 {
1612     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1613
1614     TRACE("iface %p.\n", iface);
1615
1616     return ddraw7_FlipToGDISurface(&This->IDirectDraw7_iface);
1617 }
1618
1619 static HRESULT WINAPI ddraw1_FlipToGDISurface(IDirectDraw *iface)
1620 {
1621     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1622
1623     TRACE("iface %p.\n", iface);
1624
1625     return ddraw7_FlipToGDISurface(&This->IDirectDraw7_iface);
1626 }
1627
1628 /*****************************************************************************
1629  * IDirectDraw7::WaitForVerticalBlank
1630  *
1631  * This method allows applications to get in sync with the vertical blank
1632  * interval.
1633  * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
1634  * redraw the screen, most likely because of this stub
1635  *
1636  * Parameters:
1637  *  Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
1638  *         or DDWAITVB_BLOCKEND
1639  *  h: Not used, according to MSDN
1640  *
1641  * Returns:
1642  *  Always returns DD_OK
1643  *
1644  *****************************************************************************/
1645 static HRESULT WINAPI ddraw7_WaitForVerticalBlank(IDirectDraw7 *iface, DWORD Flags, HANDLE event)
1646 {
1647     static BOOL hide;
1648
1649     TRACE("iface %p, flags %#x, event %p.\n", iface, Flags, event);
1650
1651     /* This function is called often, so print the fixme only once */
1652     if(!hide)
1653     {
1654         FIXME("iface %p, flags %#x, event %p stub!\n", iface, Flags, event);
1655         hide = TRUE;
1656     }
1657
1658     /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
1659     if(Flags & DDWAITVB_BLOCKBEGINEVENT)
1660         return DDERR_UNSUPPORTED; /* unchecked */
1661
1662     return DD_OK;
1663 }
1664
1665 static HRESULT WINAPI ddraw4_WaitForVerticalBlank(IDirectDraw4 *iface, DWORD flags, HANDLE event)
1666 {
1667     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1668
1669     TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1670
1671     return ddraw7_WaitForVerticalBlank(&This->IDirectDraw7_iface, flags, event);
1672 }
1673
1674 static HRESULT WINAPI ddraw2_WaitForVerticalBlank(IDirectDraw2 *iface, DWORD flags, HANDLE event)
1675 {
1676     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1677
1678     TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1679
1680     return ddraw7_WaitForVerticalBlank(&This->IDirectDraw7_iface, flags, event);
1681 }
1682
1683 static HRESULT WINAPI ddraw1_WaitForVerticalBlank(IDirectDraw *iface, DWORD flags, HANDLE event)
1684 {
1685     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1686
1687     TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
1688
1689     return ddraw7_WaitForVerticalBlank(&This->IDirectDraw7_iface, flags, event);
1690 }
1691
1692 /*****************************************************************************
1693  * IDirectDraw7::GetScanLine
1694  *
1695  * Returns the scan line that is being drawn on the monitor
1696  *
1697  * Parameters:
1698  *  Scanline: Address to write the scan line value to
1699  *
1700  * Returns:
1701  *  Always returns DD_OK
1702  *
1703  *****************************************************************************/
1704 static HRESULT WINAPI ddraw7_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
1705 {
1706     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1707     static DWORD cur_scanline;
1708     static BOOL hide = FALSE;
1709     WINED3DDISPLAYMODE Mode;
1710
1711     TRACE("iface %p, line %p.\n", iface, Scanline);
1712
1713     /* This function is called often, so print the fixme only once */
1714     if(!hide)
1715     {
1716         FIXME("iface %p, line %p partial stub!\n", iface, Scanline);
1717         hide = TRUE;
1718     }
1719
1720     EnterCriticalSection(&ddraw_cs);
1721     wined3d_device_get_display_mode(This->wined3d_device, 0, &Mode);
1722     LeaveCriticalSection(&ddraw_cs);
1723
1724     /* Fake the line sweeping of the monitor */
1725     /* FIXME: We should synchronize with a source to keep the refresh rate */
1726     *Scanline = cur_scanline++;
1727     /* Assume 20 scan lines in the vertical blank */
1728     if (cur_scanline >= Mode.Height + 20)
1729         cur_scanline = 0;
1730
1731     return DD_OK;
1732 }
1733
1734 static HRESULT WINAPI ddraw4_GetScanLine(IDirectDraw4 *iface, DWORD *line)
1735 {
1736     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1737
1738     TRACE("iface %p, line %p.\n", iface, line);
1739
1740     return ddraw7_GetScanLine(&This->IDirectDraw7_iface, line);
1741 }
1742
1743 static HRESULT WINAPI ddraw2_GetScanLine(IDirectDraw2 *iface, DWORD *line)
1744 {
1745     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1746
1747     TRACE("iface %p, line %p.\n", iface, line);
1748
1749     return ddraw7_GetScanLine(&This->IDirectDraw7_iface, line);
1750 }
1751
1752 static HRESULT WINAPI ddraw1_GetScanLine(IDirectDraw *iface, DWORD *line)
1753 {
1754     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1755
1756     TRACE("iface %p, line %p.\n", iface, line);
1757
1758     return ddraw7_GetScanLine(&This->IDirectDraw7_iface, line);
1759 }
1760
1761 /*****************************************************************************
1762  * IDirectDraw7::TestCooperativeLevel
1763  *
1764  * Informs the application about the state of the video adapter, depending
1765  * on the cooperative level
1766  *
1767  * Returns:
1768  *  DD_OK if the device is in a sane state
1769  *  DDERR_NOEXCLUSIVEMODE or DDERR_EXCLUSIVEMODEALREADYSET
1770  *  if the state is not correct(See below)
1771  *
1772  *****************************************************************************/
1773 static HRESULT WINAPI ddraw7_TestCooperativeLevel(IDirectDraw7 *iface)
1774 {
1775     TRACE("iface %p.\n", iface);
1776
1777     return DD_OK;
1778 }
1779
1780 static HRESULT WINAPI ddraw4_TestCooperativeLevel(IDirectDraw4 *iface)
1781 {
1782     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1783
1784     TRACE("iface %p.\n", iface);
1785
1786     return ddraw7_TestCooperativeLevel(&This->IDirectDraw7_iface);
1787 }
1788
1789 /*****************************************************************************
1790  * IDirectDraw7::GetGDISurface
1791  *
1792  * Returns the surface that GDI is treating as the primary surface.
1793  * For Wine this is the front buffer
1794  *
1795  * Params:
1796  *  GDISurface: Address to write the surface pointer to
1797  *
1798  * Returns:
1799  *  DD_OK if the surface was found
1800  *  DDERR_NOTFOUND if the GDI surface wasn't found
1801  *
1802  *****************************************************************************/
1803 static HRESULT WINAPI ddraw7_GetGDISurface(IDirectDraw7 *iface, IDirectDrawSurface7 **GDISurface)
1804 {
1805     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1806
1807     TRACE("iface %p, surface %p.\n", iface, GDISurface);
1808
1809     EnterCriticalSection(&ddraw_cs);
1810
1811     if (!(*GDISurface = &This->primary->IDirectDrawSurface7_iface))
1812     {
1813         WARN("Primary not created yet.\n");
1814         LeaveCriticalSection(&ddraw_cs);
1815         return DDERR_NOTFOUND;
1816     }
1817     IDirectDrawSurface7_AddRef(*GDISurface);
1818
1819     LeaveCriticalSection(&ddraw_cs);
1820     return DD_OK;
1821 }
1822
1823 static HRESULT WINAPI ddraw4_GetGDISurface(IDirectDraw4 *iface, IDirectDrawSurface4 **surface)
1824 {
1825     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
1826     IDirectDrawSurface7 *surface7;
1827     IDirectDrawSurfaceImpl *surface_impl;
1828     HRESULT hr;
1829
1830     TRACE("iface %p, surface %p.\n", iface, surface);
1831
1832     hr = ddraw7_GetGDISurface(&This->IDirectDraw7_iface, &surface7);
1833     if (FAILED(hr))
1834     {
1835         *surface = NULL;
1836         return hr;
1837     }
1838     surface_impl = impl_from_IDirectDrawSurface7(surface7);
1839     *surface = &surface_impl->IDirectDrawSurface4_iface;
1840     IDirectDrawSurface4_AddRef(*surface);
1841     IDirectDrawSurface7_Release(surface7);
1842
1843     return hr;
1844 }
1845
1846 static HRESULT WINAPI ddraw2_GetGDISurface(IDirectDraw2 *iface, IDirectDrawSurface **surface)
1847 {
1848     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
1849     IDirectDrawSurface7 *surface7;
1850     IDirectDrawSurfaceImpl *surface_impl;
1851     HRESULT hr;
1852
1853     TRACE("iface %p, surface %p.\n", iface, surface);
1854
1855     hr = ddraw7_GetGDISurface(&This->IDirectDraw7_iface, &surface7);
1856     if (FAILED(hr))
1857     {
1858         *surface = NULL;
1859         return hr;
1860     }
1861     surface_impl = impl_from_IDirectDrawSurface7(surface7);
1862     *surface = &surface_impl->IDirectDrawSurface_iface;
1863     IDirectDrawSurface_AddRef(*surface);
1864     IDirectDrawSurface7_Release(surface7);
1865
1866     return hr;
1867 }
1868
1869 static HRESULT WINAPI ddraw1_GetGDISurface(IDirectDraw *iface, IDirectDrawSurface **surface)
1870 {
1871     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
1872     IDirectDrawSurface7 *surface7;
1873     IDirectDrawSurfaceImpl *surface_impl;
1874     HRESULT hr;
1875
1876     TRACE("iface %p, surface %p.\n", iface, surface);
1877
1878     hr = ddraw7_GetGDISurface(&This->IDirectDraw7_iface, &surface7);
1879     if (FAILED(hr))
1880     {
1881         *surface = NULL;
1882         return hr;
1883     }
1884     surface_impl = impl_from_IDirectDrawSurface7(surface7);
1885     *surface = &surface_impl->IDirectDrawSurface_iface;
1886     IDirectDrawSurface_AddRef(*surface);
1887     IDirectDrawSurface7_Release(surface7);
1888
1889     return hr;
1890 }
1891
1892 struct displaymodescallback_context
1893 {
1894     LPDDENUMMODESCALLBACK func;
1895     void *context;
1896 };
1897
1898 static HRESULT CALLBACK EnumDisplayModesCallbackThunk(DDSURFACEDESC2 *surface_desc, void *context)
1899 {
1900     struct displaymodescallback_context *cbcontext = context;
1901     DDSURFACEDESC desc;
1902
1903     DDSD2_to_DDSD(surface_desc, &desc);
1904     return cbcontext->func(&desc, cbcontext->context);
1905 }
1906
1907 /*****************************************************************************
1908  * IDirectDraw7::EnumDisplayModes
1909  *
1910  * Enumerates the supported Display modes. The modes can be filtered with
1911  * the DDSD parameter.
1912  *
1913  * Params:
1914  *  Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES. For old ddraw
1915  *         versions (3 and older?) this is reserved and must be 0.
1916  *  DDSD: Surface description to filter the modes
1917  *  Context: Pointer passed back to the callback function
1918  *  cb: Application-provided callback function
1919  *
1920  * Returns:
1921  *  DD_OK on success
1922  *  DDERR_INVALIDPARAMS if the callback wasn't set
1923  *
1924  *****************************************************************************/
1925 static HRESULT WINAPI ddraw7_EnumDisplayModes(IDirectDraw7 *iface, DWORD Flags,
1926         DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMMODESCALLBACK2 cb)
1927 {
1928     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
1929     unsigned int modenum, fmt;
1930     WINED3DDISPLAYMODE mode;
1931     DDSURFACEDESC2 callback_sd;
1932     WINED3DDISPLAYMODE *enum_modes = NULL;
1933     unsigned enum_mode_count = 0, enum_mode_array_size = 0;
1934     DDPIXELFORMAT pixelformat;
1935
1936     static const enum wined3d_format_id checkFormatList[] =
1937     {
1938         WINED3DFMT_B8G8R8X8_UNORM,
1939         WINED3DFMT_B5G6R5_UNORM,
1940         WINED3DFMT_P8_UINT,
1941     };
1942
1943     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
1944             iface, Flags, DDSD, Context, cb);
1945
1946     EnterCriticalSection(&ddraw_cs);
1947     /* This looks sane */
1948     if(!cb)
1949     {
1950         LeaveCriticalSection(&ddraw_cs);
1951         return DDERR_INVALIDPARAMS;
1952     }
1953
1954     if(!(Flags & DDEDM_REFRESHRATES))
1955     {
1956         enum_mode_array_size = 16;
1957         enum_modes = HeapAlloc(GetProcessHeap(), 0, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
1958         if (!enum_modes)
1959         {
1960             ERR("Out of memory\n");
1961             LeaveCriticalSection(&ddraw_cs);
1962             return DDERR_OUTOFMEMORY;
1963         }
1964     }
1965
1966     pixelformat.dwSize = sizeof(pixelformat);
1967     for(fmt = 0; fmt < (sizeof(checkFormatList) / sizeof(checkFormatList[0])); fmt++)
1968     {
1969         modenum = 0;
1970         while (wined3d_enum_adapter_modes(This->wineD3D, WINED3DADAPTER_DEFAULT,
1971                 checkFormatList[fmt], modenum++, &mode) == WINED3D_OK)
1972         {
1973             PixelFormat_WineD3DtoDD(&pixelformat, mode.Format);
1974             if(DDSD)
1975             {
1976                 if(DDSD->dwFlags & DDSD_WIDTH && mode.Width != DDSD->dwWidth) continue;
1977                 if(DDSD->dwFlags & DDSD_HEIGHT && mode.Height != DDSD->dwHeight) continue;
1978                 if(DDSD->dwFlags & DDSD_REFRESHRATE && mode.RefreshRate != DDSD->u2.dwRefreshRate) continue;
1979                 if (DDSD->dwFlags & DDSD_PIXELFORMAT &&
1980                         pixelformat.u1.dwRGBBitCount != DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount) continue;
1981             }
1982
1983             if(!(Flags & DDEDM_REFRESHRATES))
1984             {
1985                 /* DX docs state EnumDisplayMode should return only unique modes. If DDEDM_REFRESHRATES is not set, refresh
1986                  * rate doesn't matter when determining if the mode is unique. So modes only differing in refresh rate have
1987                  * to be reduced to a single unique result in such case.
1988                  */
1989                 BOOL found = FALSE;
1990                 unsigned i;
1991
1992                 for (i = 0; i < enum_mode_count; i++)
1993                 {
1994                     if(enum_modes[i].Width == mode.Width && enum_modes[i].Height == mode.Height &&
1995                        enum_modes[i].Format == mode.Format)
1996                     {
1997                         found = TRUE;
1998                         break;
1999                     }
2000                 }
2001
2002                 if(found) continue;
2003             }
2004
2005             memset(&callback_sd, 0, sizeof(callback_sd));
2006             callback_sd.dwSize = sizeof(callback_sd);
2007             callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
2008
2009             callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH|DDSD_REFRESHRATE;
2010             if(Flags & DDEDM_REFRESHRATES)
2011             {
2012                 callback_sd.u2.dwRefreshRate = mode.RefreshRate;
2013             }
2014
2015             callback_sd.dwWidth = mode.Width;
2016             callback_sd.dwHeight = mode.Height;
2017
2018             callback_sd.u4.ddpfPixelFormat=pixelformat;
2019
2020             /* Calc pitch and DWORD align like MSDN says */
2021             callback_sd.u1.lPitch = (callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8) * mode.Width;
2022             callback_sd.u1.lPitch = (callback_sd.u1.lPitch + 3) & ~3;
2023
2024             TRACE("Enumerating %dx%dx%d @%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
2025               callback_sd.u2.dwRefreshRate);
2026
2027             if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
2028             {
2029                 TRACE("Application asked to terminate the enumeration\n");
2030                 HeapFree(GetProcessHeap(), 0, enum_modes);
2031                 LeaveCriticalSection(&ddraw_cs);
2032                 return DD_OK;
2033             }
2034
2035             if(!(Flags & DDEDM_REFRESHRATES))
2036             {
2037                 if (enum_mode_count == enum_mode_array_size)
2038                 {
2039                     WINED3DDISPLAYMODE *new_enum_modes;
2040
2041                     enum_mode_array_size *= 2;
2042                     new_enum_modes = HeapReAlloc(GetProcessHeap(), 0, enum_modes, sizeof(WINED3DDISPLAYMODE) * enum_mode_array_size);
2043
2044                     if (!new_enum_modes)
2045                     {
2046                         ERR("Out of memory\n");
2047                         HeapFree(GetProcessHeap(), 0, enum_modes);
2048                         LeaveCriticalSection(&ddraw_cs);
2049                         return DDERR_OUTOFMEMORY;
2050                     }
2051
2052                     enum_modes = new_enum_modes;
2053                 }
2054
2055                 enum_modes[enum_mode_count++] = mode;
2056             }
2057         }
2058     }
2059
2060     TRACE("End of enumeration\n");
2061     HeapFree(GetProcessHeap(), 0, enum_modes);
2062     LeaveCriticalSection(&ddraw_cs);
2063     return DD_OK;
2064 }
2065
2066 static HRESULT WINAPI ddraw4_EnumDisplayModes(IDirectDraw4 *iface, DWORD flags,
2067         DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMMODESCALLBACK2 callback)
2068 {
2069     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
2070
2071     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2072             iface, flags, surface_desc, context, callback);
2073
2074     return ddraw7_EnumDisplayModes(&This->IDirectDraw7_iface, flags, surface_desc, context, callback);
2075 }
2076
2077 static HRESULT WINAPI ddraw2_EnumDisplayModes(IDirectDraw2 *iface, DWORD flags,
2078         DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2079 {
2080     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
2081     struct displaymodescallback_context cbcontext;
2082     DDSURFACEDESC2 surface_desc2;
2083
2084     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2085             iface, flags, surface_desc, context, callback);
2086
2087     cbcontext.func = callback;
2088     cbcontext.context = context;
2089
2090     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
2091     return ddraw7_EnumDisplayModes(&This->IDirectDraw7_iface, flags,
2092             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumDisplayModesCallbackThunk);
2093 }
2094
2095 static HRESULT WINAPI ddraw1_EnumDisplayModes(IDirectDraw *iface, DWORD flags,
2096         DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2097 {
2098     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
2099     struct displaymodescallback_context cbcontext;
2100     DDSURFACEDESC2 surface_desc2;
2101
2102     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2103             iface, flags, surface_desc, context, callback);
2104
2105     cbcontext.func = callback;
2106     cbcontext.context = context;
2107
2108     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
2109     return ddraw7_EnumDisplayModes(&This->IDirectDraw7_iface, flags,
2110             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumDisplayModesCallbackThunk);
2111 }
2112
2113 /*****************************************************************************
2114  * IDirectDraw7::EvaluateMode
2115  *
2116  * Used with IDirectDraw7::StartModeTest to test video modes.
2117  * EvaluateMode is used to pass or fail a mode, and continue with the next
2118  * mode
2119  *
2120  * Params:
2121  *  Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
2122  *  Timeout: Returns the amount of seconds left before the mode would have
2123  *           been failed automatically
2124  *
2125  * Returns:
2126  *  This implementation always DD_OK, because it's a stub
2127  *
2128  *****************************************************************************/
2129 static HRESULT WINAPI ddraw7_EvaluateMode(IDirectDraw7 *iface, DWORD Flags, DWORD *Timeout)
2130 {
2131     FIXME("iface %p, flags %#x, timeout %p stub!\n", iface, Flags, Timeout);
2132
2133     /* When implementing this, implement it in WineD3D */
2134
2135     return DD_OK;
2136 }
2137
2138 /*****************************************************************************
2139  * IDirectDraw7::GetDeviceIdentifier
2140  *
2141  * Returns the device identifier, which gives information about the driver
2142  * Our device identifier is defined at the beginning of this file.
2143  *
2144  * Params:
2145  *  DDDI: Address for the returned structure
2146  *  Flags: Can be DDGDI_GETHOSTIDENTIFIER
2147  *
2148  * Returns:
2149  *  On success it returns DD_OK
2150  *  DDERR_INVALIDPARAMS if DDDI is NULL
2151  *
2152  *****************************************************************************/
2153 static HRESULT WINAPI ddraw7_GetDeviceIdentifier(IDirectDraw7 *iface,
2154         DDDEVICEIDENTIFIER2 *DDDI, DWORD Flags)
2155 {
2156     TRACE("iface %p, device_identifier %p, flags %#x.\n", iface, DDDI, Flags);
2157
2158     if(!DDDI)
2159         return DDERR_INVALIDPARAMS;
2160
2161     /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
2162      * host adapter, if there's a secondary 3D adapter. This doesn't apply
2163      * to any modern hardware, nor is it interesting for Wine, so ignore it.
2164      * Size of DDDEVICEIDENTIFIER2 may be aligned to 8 bytes and thus 4
2165      * bytes too long. So only copy the relevant part of the structure
2166      */
2167
2168     memcpy(DDDI, &deviceidentifier, FIELD_OFFSET(DDDEVICEIDENTIFIER2, dwWHQLLevel) + sizeof(DWORD));
2169     return DD_OK;
2170 }
2171
2172 static HRESULT WINAPI ddraw4_GetDeviceIdentifier(IDirectDraw4 *iface,
2173         DDDEVICEIDENTIFIER *identifier, DWORD flags)
2174 {
2175     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
2176     DDDEVICEIDENTIFIER2 identifier2;
2177     HRESULT hr;
2178
2179     TRACE("iface %p, identifier %p, flags %#x.\n", iface, identifier, flags);
2180
2181     hr = ddraw7_GetDeviceIdentifier(&This->IDirectDraw7_iface, &identifier2, flags);
2182     DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(&identifier2, identifier);
2183
2184     return hr;
2185 }
2186
2187 /*****************************************************************************
2188  * IDirectDraw7::GetSurfaceFromDC
2189  *
2190  * Returns the Surface for a GDI device context handle.
2191  * Is this related to IDirectDrawSurface::GetDC ???
2192  *
2193  * Params:
2194  *  hdc: hdc to return the surface for
2195  *  Surface: Address to write the surface pointer to
2196  *
2197  * Returns:
2198  *  Always returns DD_OK because it's a stub
2199  *
2200  *****************************************************************************/
2201 static HRESULT WINAPI ddraw7_GetSurfaceFromDC(IDirectDraw7 *iface, HDC hdc,
2202         IDirectDrawSurface7 **Surface)
2203 {
2204     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
2205     struct wined3d_surface *wined3d_surface;
2206     HRESULT hr;
2207
2208     TRACE("iface %p, dc %p, surface %p.\n", iface, hdc, Surface);
2209
2210     if (!Surface) return E_INVALIDARG;
2211
2212     hr = wined3d_device_get_surface_from_dc(This->wined3d_device, hdc, &wined3d_surface);
2213     if (FAILED(hr))
2214     {
2215         TRACE("No surface found for dc %p.\n", hdc);
2216         *Surface = NULL;
2217         return DDERR_NOTFOUND;
2218     }
2219
2220     *Surface = wined3d_surface_get_parent(wined3d_surface);
2221     IDirectDrawSurface7_AddRef(*Surface);
2222     TRACE("Returning surface %p.\n", Surface);
2223     return DD_OK;
2224 }
2225
2226 static HRESULT WINAPI ddraw4_GetSurfaceFromDC(IDirectDraw4 *iface, HDC dc,
2227         IDirectDrawSurface4 **surface)
2228 {
2229     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
2230     IDirectDrawSurface7 *surface7;
2231     IDirectDrawSurfaceImpl *surface_impl;
2232     HRESULT hr;
2233
2234     TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2235
2236     if (!surface) return E_INVALIDARG;
2237
2238     hr = ddraw7_GetSurfaceFromDC(&This->IDirectDraw7_iface, dc, &surface7);
2239     if (FAILED(hr))
2240     {
2241         *surface = NULL;
2242         return hr;
2243     }
2244     surface_impl = impl_from_IDirectDrawSurface7(surface7);
2245     /* Tests say this is true */
2246     *surface = (IDirectDrawSurface4 *)&surface_impl->IDirectDrawSurface_iface;
2247     IDirectDrawSurface_AddRef(&surface_impl->IDirectDrawSurface_iface);
2248     IDirectDrawSurface7_Release(surface7);
2249
2250     return hr;
2251 }
2252
2253 /*****************************************************************************
2254  * IDirectDraw7::RestoreAllSurfaces
2255  *
2256  * Calls the restore method of all surfaces
2257  *
2258  * Params:
2259  *
2260  * Returns:
2261  *  Always returns DD_OK because it's a stub
2262  *
2263  *****************************************************************************/
2264 static HRESULT WINAPI ddraw7_RestoreAllSurfaces(IDirectDraw7 *iface)
2265 {
2266     FIXME("iface %p stub!\n", iface);
2267
2268     /* This isn't hard to implement: Enumerate all WineD3D surfaces,
2269      * get their parent and call their restore method. Do not implement
2270      * it in WineD3D, as restoring a surface means re-creating the
2271      * WineD3DDSurface
2272      */
2273     return DD_OK;
2274 }
2275
2276 static HRESULT WINAPI ddraw4_RestoreAllSurfaces(IDirectDraw4 *iface)
2277 {
2278     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
2279
2280     TRACE("iface %p.\n", iface);
2281
2282     return ddraw7_RestoreAllSurfaces(&This->IDirectDraw7_iface);
2283 }
2284
2285 /*****************************************************************************
2286  * IDirectDraw7::StartModeTest
2287  *
2288  * Tests the specified video modes to update the system registry with
2289  * refresh rate information. StartModeTest starts the mode test,
2290  * EvaluateMode is used to fail or pass a mode. If EvaluateMode
2291  * isn't called within 15 seconds, the mode is failed automatically
2292  *
2293  * As refresh rates are handled by the X server, I don't think this
2294  * Method is important
2295  *
2296  * Params:
2297  *  Modes: An array of mode specifications
2298  *  NumModes: The number of modes in Modes
2299  *  Flags: Some flags...
2300  *
2301  * Returns:
2302  *  Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
2303  *  if no modes are passed, DDERR_INVALIDPARAMS is returned,
2304  *  otherwise DD_OK
2305  *
2306  *****************************************************************************/
2307 static HRESULT WINAPI ddraw7_StartModeTest(IDirectDraw7 *iface, SIZE *Modes, DWORD NumModes, DWORD Flags)
2308 {
2309     FIXME("iface %p, modes %p, mode_count %u, flags %#x partial stub!\n",
2310             iface, Modes, NumModes, Flags);
2311
2312     /* This looks sane */
2313     if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
2314
2315     /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
2316      * As it is not, DDERR_TESTFINISHED is returned
2317      * (hopefully that's correct
2318      *
2319     if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
2320      * well, that value doesn't (yet) exist in the wine headers, so ignore it
2321      */
2322
2323     return DD_OK;
2324 }
2325
2326 /*****************************************************************************
2327  * ddraw_create_surface
2328  *
2329  * A helper function for IDirectDraw7::CreateSurface. It creates a new surface
2330  * with the passed parameters.
2331  *
2332  * Params:
2333  *  DDSD: Description of the surface to create
2334  *  Surf: Address to store the interface pointer at
2335  *
2336  * Returns:
2337  *  DD_OK on success
2338  *
2339  *****************************************************************************/
2340 static HRESULT ddraw_create_surface(IDirectDrawImpl *This, DDSURFACEDESC2 *pDDSD,
2341         IDirectDrawSurfaceImpl **ppSurf, UINT level, UINT version)
2342 {
2343     HRESULT hr;
2344
2345     TRACE("ddraw %p, surface_desc %p, surface %p, level %u.\n",
2346             This, pDDSD, ppSurf, level);
2347
2348     if (TRACE_ON(ddraw))
2349     {
2350         TRACE(" (%p) Requesting surface desc :\n", This);
2351         DDRAW_dump_surface_desc(pDDSD);
2352     }
2353
2354     if ((pDDSD->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) && DefaultSurfaceType != SURFACE_OPENGL)
2355     {
2356         WARN("The application requests a 3D capable surface, but a non-OpenGL surface type was set in the registry.\n");
2357         /* Do not fail surface creation, only fail 3D device creation. */
2358     }
2359
2360     /* Create the Surface object */
2361     *ppSurf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawSurfaceImpl));
2362     if(!*ppSurf)
2363     {
2364         ERR("(%p) Error allocating memory for a surface\n", This);
2365         return DDERR_OUTOFVIDEOMEMORY;
2366     }
2367
2368     hr = ddraw_surface_init(*ppSurf, This, pDDSD, level, version);
2369     if (FAILED(hr))
2370     {
2371         WARN("Failed to initialize surface, hr %#x.\n", hr);
2372         HeapFree(GetProcessHeap(), 0, *ppSurf);
2373         return hr;
2374     }
2375
2376     /* Increase the surface counter, and attach the surface */
2377     list_add_head(&This->surface_list, &(*ppSurf)->surface_list_entry);
2378
2379     TRACE("Created surface %p.\n", *ppSurf);
2380
2381     return DD_OK;
2382 }
2383 /*****************************************************************************
2384  * CreateAdditionalSurfaces
2385  *
2386  * Creates a new mipmap chain.
2387  *
2388  * Params:
2389  *  root: Root surface to attach the newly created chain to
2390  *  count: number of surfaces to create
2391  *  DDSD: Description of the surface. Intentionally not a pointer to avoid side
2392  *        effects on the caller
2393  *  CubeFaceRoot: Whether the new surface is a root of a cube map face. This
2394  *                creates an additional surface without the mipmapping flags
2395  *
2396  *****************************************************************************/
2397 static HRESULT
2398 CreateAdditionalSurfaces(IDirectDrawImpl *This,
2399                          IDirectDrawSurfaceImpl *root,
2400                          UINT count,
2401                          DDSURFACEDESC2 DDSD,
2402                          BOOL CubeFaceRoot, UINT version)
2403 {
2404     UINT i, j, level = 0;
2405     HRESULT hr;
2406     IDirectDrawSurfaceImpl *last = root;
2407
2408     for(i = 0; i < count; i++)
2409     {
2410         IDirectDrawSurfaceImpl *object2 = NULL;
2411
2412         /* increase the mipmap level, but only if a mipmap is created
2413          * In this case, also halve the size
2414          */
2415         if(DDSD.ddsCaps.dwCaps & DDSCAPS_MIPMAP && !CubeFaceRoot)
2416         {
2417             level++;
2418             if(DDSD.dwWidth > 1) DDSD.dwWidth /= 2;
2419             if(DDSD.dwHeight > 1) DDSD.dwHeight /= 2;
2420             /* Set the mipmap sublevel flag according to msdn */
2421             DDSD.ddsCaps.dwCaps2 |= DDSCAPS2_MIPMAPSUBLEVEL;
2422         }
2423         else
2424         {
2425             DDSD.ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2426         }
2427         CubeFaceRoot = FALSE;
2428
2429         hr = ddraw_create_surface(This, &DDSD, &object2, level, version);
2430         if(hr != DD_OK)
2431         {
2432             return hr;
2433         }
2434
2435         /* Add the new surface to the complex attachment array */
2436         for(j = 0; j < MAX_COMPLEX_ATTACHED; j++)
2437         {
2438             if(last->complex_array[j]) continue;
2439             last->complex_array[j] = object2;
2440             break;
2441         }
2442         last = object2;
2443
2444         /* Remove the (possible) back buffer cap from the new surface description,
2445          * because only one surface in the flipping chain is a back buffer, one
2446          * is a front buffer, the others are just primary surfaces.
2447          */
2448         DDSD.ddsCaps.dwCaps &= ~DDSCAPS_BACKBUFFER;
2449     }
2450     return DD_OK;
2451 }
2452
2453 /*****************************************************************************
2454  * ddraw_attach_d3d_device
2455  *
2456  * Initializes the D3D capabilities of WineD3D
2457  *
2458  * Params:
2459  *  primary: The primary surface for D3D
2460  *
2461  * Returns
2462  *  DD_OK on success,
2463  *  DDERR_* otherwise
2464  *
2465  *****************************************************************************/
2466 static HRESULT ddraw_attach_d3d_device(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *primary,
2467         WINED3DPRESENT_PARAMETERS *presentation_parameters)
2468 {
2469     HWND window = presentation_parameters->hDeviceWindow;
2470     HRESULT hr;
2471
2472     TRACE("ddraw %p, primary %p.\n", ddraw, primary);
2473
2474     if (!window || window == GetDesktopWindow())
2475     {
2476         window = CreateWindowExA(0, DDRAW_WINDOW_CLASS_NAME, "Hidden D3D Window",
2477                 WS_DISABLED, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN),
2478                 NULL, NULL, NULL, NULL);
2479         if (!window)
2480         {
2481             ERR("Failed to create window, last error %#x.\n", GetLastError());
2482             return E_FAIL;
2483         }
2484
2485         ShowWindow(window, SW_HIDE);   /* Just to be sure */
2486         WARN("No window for the Direct3DDevice, created hidden window %p.\n", window);
2487
2488         presentation_parameters->hDeviceWindow = window;
2489     }
2490     else
2491     {
2492         TRACE("Using existing window %p for Direct3D rendering.\n", window);
2493     }
2494     ddraw->d3d_window = window;
2495
2496     /* Store the future Render Target surface */
2497     ddraw->d3d_target = primary;
2498
2499     /* Set this NOW, otherwise creating the depth stencil surface will cause a
2500      * recursive loop until ram or emulated video memory is full. */
2501     ddraw->d3d_initialized = TRUE;
2502     hr = wined3d_device_init_3d(ddraw->wined3d_device, presentation_parameters);
2503     if (FAILED(hr))
2504     {
2505         ddraw->d3d_target = NULL;
2506         ddraw->d3d_initialized = FALSE;
2507         return hr;
2508     }
2509
2510     ddraw->declArraySize = 2;
2511     ddraw->decls = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ddraw->decls) * ddraw->declArraySize);
2512     if (!ddraw->decls)
2513     {
2514         ERR("Error allocating an array for the converted vertex decls.\n");
2515         ddraw->declArraySize = 0;
2516         hr = wined3d_device_uninit_3d(ddraw->wined3d_device);
2517         return E_OUTOFMEMORY;
2518     }
2519
2520     TRACE("Successfully initialized 3D.\n");
2521
2522     return DD_OK;
2523 }
2524
2525 static HRESULT ddraw_create_gdi_swapchain(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *primary,
2526         WINED3DPRESENT_PARAMETERS *presentation_parameters)
2527 {
2528     HRESULT hr;
2529
2530     ddraw->d3d_target = primary;
2531     hr = wined3d_device_init_gdi(ddraw->wined3d_device, presentation_parameters);
2532     ddraw->d3d_target = NULL;
2533     if (FAILED(hr))
2534     {
2535         WARN("Failed to initialize GDI ddraw implementation, hr %#x.\n", hr);
2536         primary->wined3d_swapchain = NULL;
2537     }
2538
2539     return hr;
2540 }
2541
2542 static HRESULT ddraw_create_swapchain(IDirectDrawImpl *ddraw, IDirectDrawSurfaceImpl *surface)
2543 {
2544     WINED3DPRESENT_PARAMETERS presentation_parameters;
2545     IDirectDrawSurfaceImpl *target = surface;
2546     HRESULT hr = WINED3D_OK;
2547
2548     if (ddraw->primary)
2549     {
2550         TRACE("Using primary %p.\n", ddraw->primary);
2551         target = ddraw->primary;
2552     }
2553
2554     memset(&presentation_parameters, 0, sizeof(presentation_parameters));
2555     presentation_parameters.BackBufferWidth = target->surface_desc.dwWidth;
2556     presentation_parameters.BackBufferHeight = target->surface_desc.dwHeight;
2557     presentation_parameters.BackBufferFormat = PixelFormat_DD2WineD3D(&target->surface_desc.u4.ddpfPixelFormat);
2558     presentation_parameters.SwapEffect = WINED3DSWAPEFFECT_COPY;
2559     presentation_parameters.hDeviceWindow = ddraw->dest_window;
2560     presentation_parameters.Windowed = !(ddraw->cooperative_level & DDSCL_FULLSCREEN);
2561
2562     /* If the implementation is OpenGL and there's no d3ddevice, attach a
2563      * d3ddevice. But attach the d3ddevice only if the currently created
2564      * surface was a primary surface (2D app in 3D mode) or a 3DDEVICE surface
2565      * (3D app). The only case I can think of where this doesn't apply is when
2566      * a 2D app was configured by the user to run with OpenGL and it didn't
2567      * create the render target as first surface. In this case the render
2568      * target creation will cause the 3D init. */
2569     if (DefaultSurfaceType == SURFACE_OPENGL)
2570     {
2571         TRACE("Attaching a D3DDevice, rendertarget = %p.\n", target);
2572         hr = ddraw_attach_d3d_device(ddraw, target, &presentation_parameters);
2573     }
2574     else if (surface->surface_desc.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
2575     {
2576         hr = ddraw_create_gdi_swapchain(ddraw, target, &presentation_parameters);
2577     }
2578
2579     return hr;
2580
2581 }
2582
2583 /*****************************************************************************
2584  * IDirectDraw7::CreateSurface
2585  *
2586  * Creates a new IDirectDrawSurface object and returns its interface.
2587  *
2588  * The surface connections with wined3d are a bit tricky. Basically it works
2589  * like this:
2590  *
2591  * |------------------------|               |-----------------|
2592  * | DDraw surface          |               | WineD3DSurface  |
2593  * |                        |               |                 |
2594  * |        WineD3DSurface  |-------------->|                 |
2595  * |        Child           |<------------->| Parent          |
2596  * |------------------------|               |-----------------|
2597  *
2598  * The DDraw surface is the parent of the wined3d surface, and it releases
2599  * the WineD3DSurface when the ddraw surface is destroyed.
2600  *
2601  * However, for all surfaces which can be in a container in WineD3D,
2602  * we have to do this. These surfaces are usually complex surfaces,
2603  * so this concerns primary surfaces with a front and a back buffer,
2604  * and textures.
2605  *
2606  * |------------------------|               |-----------------|
2607  * | DDraw surface          |               | Container       |
2608  * |                        |               |                 |
2609  * |                  Child |<------------->| Parent          |
2610  * |                Texture |<------------->|                 |
2611  * |         WineD3DSurface |<----|         |          Levels |<--|
2612  * | Complex connection     |     |         |                 |   |
2613  * |------------------------|     |         |-----------------|   |
2614  *  ^                             |                               |
2615  *  |                             |                               |
2616  *  |                             |                               |
2617  *  |    |------------------|     |         |-----------------|   |
2618  *  |    | IParent          |     |-------->| WineD3DSurface  |   |
2619  *  |    |                  |               |                 |   |
2620  *  |    |            Child |<------------->| Parent          |   |
2621  *  |    |                  |               |       Container |<--|
2622  *  |    |------------------|               |-----------------|   |
2623  *  |                                                             |
2624  *  |   |----------------------|                                  |
2625  *  |   | DDraw surface 2      |                                  |
2626  *  |   |                      |                                  |
2627  *  |<->| Complex root   Child |                                  |
2628  *  |   |              Texture |                                  |
2629  *  |   |       WineD3DSurface |<----|                            |
2630  *  |   |----------------------|     |                            |
2631  *  |                                |                            |
2632  *  |    |---------------------|     |      |-----------------|   |
2633  *  |    | IParent             |     |----->| WineD3DSurface  |   |
2634  *  |    |                     |            |                 |   |
2635  *  |    |               Child |<---------->| Parent          |   |
2636  *  |    |---------------------|            |       Container |<--|
2637  *  |                                       |-----------------|   |
2638  *  |                                                             |
2639  *  |             ---More surfaces can follow---                  |
2640  *
2641  * The reason is that the IWineD3DSwapchain(render target container)
2642  * and the IWineD3DTexure(Texture container) release the parents
2643  * of their surface's children, but by releasing the complex root
2644  * the surfaces which are complexly attached to it are destroyed
2645  * too. See IDirectDrawSurface::Release for a more detailed
2646  * explanation.
2647  *
2648  * Params:
2649  *  DDSD: Description of the surface to create
2650  *  Surf: Address to store the interface pointer at
2651  *  UnkOuter: Basically for aggregation support, but ddraw doesn't support
2652  *            aggregation, so it has to be NULL
2653  *
2654  * Returns:
2655  *  DD_OK on success
2656  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
2657  *  DDERR_* if an error occurs
2658  *
2659  *****************************************************************************/
2660 static HRESULT CreateSurface(IDirectDrawImpl *ddraw, DDSURFACEDESC2 *DDSD,
2661         IDirectDrawSurfaceImpl **Surf, IUnknown *UnkOuter, UINT version)
2662 {
2663     IDirectDrawSurfaceImpl *object = NULL;
2664     HRESULT hr;
2665     LONG extra_surfaces = 0;
2666     DDSURFACEDESC2 desc2;
2667     WINED3DDISPLAYMODE Mode;
2668     const DWORD sysvidmem = DDSCAPS_VIDEOMEMORY | DDSCAPS_SYSTEMMEMORY;
2669
2670     TRACE("ddraw %p, surface_desc %p, surface %p, outer_unknown %p.\n", ddraw, DDSD, Surf, UnkOuter);
2671
2672     /* Some checks before we start */
2673     if (TRACE_ON(ddraw))
2674     {
2675         TRACE(" (%p) Requesting surface desc :\n", ddraw);
2676         DDRAW_dump_surface_desc(DDSD);
2677     }
2678     EnterCriticalSection(&ddraw_cs);
2679
2680     if (UnkOuter != NULL)
2681     {
2682         FIXME("(%p) : outer != NULL?\n", ddraw);
2683         LeaveCriticalSection(&ddraw_cs);
2684         return CLASS_E_NOAGGREGATION; /* unchecked */
2685     }
2686
2687     if (Surf == NULL)
2688     {
2689         FIXME("(%p) You want to get back a surface? Don't give NULL ptrs!\n", ddraw);
2690         LeaveCriticalSection(&ddraw_cs);
2691         return E_POINTER; /* unchecked */
2692     }
2693
2694     if (!(DDSD->dwFlags & DDSD_CAPS))
2695     {
2696         /* DVIDEO.DLL does forget the DDSD_CAPS flag ... *sigh* */
2697         DDSD->dwFlags |= DDSD_CAPS;
2698     }
2699
2700     if (DDSD->ddsCaps.dwCaps & DDSCAPS_ALLOCONLOAD)
2701     {
2702         /* If the surface is of the 'alloconload' type, ignore the LPSURFACE field */
2703         DDSD->dwFlags &= ~DDSD_LPSURFACE;
2704     }
2705
2706     if ((DDSD->dwFlags & DDSD_LPSURFACE) && (DDSD->lpSurface == NULL))
2707     {
2708         /* Frank Herbert's Dune specifies a null pointer for the surface, ignore the LPSURFACE field */
2709         WARN("(%p) Null surface pointer specified, ignore it!\n", ddraw);
2710         DDSD->dwFlags &= ~DDSD_LPSURFACE;
2711     }
2712
2713     if((DDSD->ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE)) == (DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE) &&
2714        !(ddraw->cooperative_level & DDSCL_EXCLUSIVE))
2715     {
2716         TRACE("(%p): Attempt to create a flipable primary surface without DDSCL_EXCLUSIVE set\n",
2717                 ddraw);
2718         *Surf = NULL;
2719         LeaveCriticalSection(&ddraw_cs);
2720         return DDERR_NOEXCLUSIVEMODE;
2721     }
2722
2723     if((DDSD->ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER | DDSCAPS_PRIMARYSURFACE)) == (DDSCAPS_BACKBUFFER | DDSCAPS_PRIMARYSURFACE))
2724     {
2725         WARN("Application wanted to create back buffer primary surface\n");
2726         LeaveCriticalSection(&ddraw_cs);
2727         return DDERR_INVALIDCAPS;
2728     }
2729
2730     if((DDSD->ddsCaps.dwCaps & sysvidmem) == sysvidmem)
2731     {
2732         /* This is a special switch in ddrawex.dll, but not allowed in ddraw.dll */
2733         WARN("Application tries to put the surface in both system and video memory\n");
2734         LeaveCriticalSection(&ddraw_cs);
2735         *Surf = NULL;
2736         return DDERR_INVALIDCAPS;
2737     }
2738
2739     /* Check cube maps but only if the size includes them */
2740     if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
2741     {
2742         if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES &&
2743            !(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP))
2744         {
2745             WARN("Cube map faces requested without cube map flag\n");
2746             LeaveCriticalSection(&ddraw_cs);
2747             return DDERR_INVALIDCAPS;
2748         }
2749         if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
2750            (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) == 0)
2751         {
2752             WARN("Cube map without faces requested\n");
2753             LeaveCriticalSection(&ddraw_cs);
2754             return DDERR_INVALIDPARAMS;
2755         }
2756
2757         /* Quick tests confirm those can be created, but we don't do that yet */
2758         if(DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP &&
2759            (DDSD->ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP_ALLFACES) != DDSCAPS2_CUBEMAP_ALLFACES)
2760         {
2761             FIXME("Partial cube maps not supported yet\n");
2762         }
2763     }
2764
2765     /* According to the msdn this flag is ignored by CreateSurface */
2766     if (DDSD->dwSize >= sizeof(DDSURFACEDESC2))
2767         DDSD->ddsCaps.dwCaps2 &= ~DDSCAPS2_MIPMAPSUBLEVEL;
2768
2769     /* Modify some flags */
2770     copy_to_surfacedesc2(&desc2, DDSD);
2771     desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT); /* Just to be sure */
2772
2773     /* Get the video mode from WineD3D - we will need it */
2774     hr = wined3d_device_get_display_mode(ddraw->wined3d_device, 0, &Mode);
2775     if (FAILED(hr))
2776     {
2777         ERR("Failed to read display mode from wined3d\n");
2778         switch(ddraw->orig_bpp)
2779         {
2780             case 8:
2781                 Mode.Format = WINED3DFMT_P8_UINT;
2782                 break;
2783
2784             case 15:
2785                 Mode.Format = WINED3DFMT_B5G5R5X1_UNORM;
2786                 break;
2787
2788             case 16:
2789                 Mode.Format = WINED3DFMT_B5G6R5_UNORM;
2790                 break;
2791
2792             case 24:
2793                 Mode.Format = WINED3DFMT_B8G8R8_UNORM;
2794                 break;
2795
2796             case 32:
2797                 Mode.Format = WINED3DFMT_B8G8R8X8_UNORM;
2798                 break;
2799         }
2800         Mode.Width = ddraw->orig_width;
2801         Mode.Height = ddraw->orig_height;
2802     }
2803
2804     /* No pixelformat given? Use the current screen format */
2805     if(!(desc2.dwFlags & DDSD_PIXELFORMAT))
2806     {
2807         desc2.dwFlags |= DDSD_PIXELFORMAT;
2808         desc2.u4.ddpfPixelFormat.dwSize=sizeof(DDPIXELFORMAT);
2809
2810         PixelFormat_WineD3DtoDD(&desc2.u4.ddpfPixelFormat, Mode.Format);
2811     }
2812
2813     /* No Width or no Height? Use the original screen size
2814      */
2815     if(!(desc2.dwFlags & DDSD_WIDTH) ||
2816        !(desc2.dwFlags & DDSD_HEIGHT) )
2817     {
2818         /* Invalid for non-render targets */
2819         if(!(desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE))
2820         {
2821             WARN("Creating a non-Primary surface without Width or Height info, returning DDERR_INVALIDPARAMS\n");
2822             *Surf = NULL;
2823             LeaveCriticalSection(&ddraw_cs);
2824             return DDERR_INVALIDPARAMS;
2825         }
2826
2827         desc2.dwFlags |= DDSD_WIDTH | DDSD_HEIGHT;
2828         desc2.dwWidth = Mode.Width;
2829         desc2.dwHeight = Mode.Height;
2830     }
2831
2832     if (!desc2.dwWidth || !desc2.dwHeight)
2833     {
2834         LeaveCriticalSection(&ddraw_cs);
2835         return DDERR_INVALIDPARAMS;
2836     }
2837
2838     /* Mipmap count fixes */
2839     if(desc2.ddsCaps.dwCaps & DDSCAPS_MIPMAP)
2840     {
2841         if(desc2.ddsCaps.dwCaps & DDSCAPS_COMPLEX)
2842         {
2843             if(desc2.dwFlags & DDSD_MIPMAPCOUNT)
2844             {
2845                 /* Mipmap count is given, should not be 0 */
2846                 if( desc2.u2.dwMipMapCount == 0 )
2847                 {
2848                     LeaveCriticalSection(&ddraw_cs);
2849                     return DDERR_INVALIDPARAMS;
2850                 }
2851             }
2852             else
2853             {
2854                 /* Undocumented feature: Create sublevels until
2855                  * either the width or the height is 1
2856                  */
2857                 DWORD min = desc2.dwWidth < desc2.dwHeight ?
2858                             desc2.dwWidth : desc2.dwHeight;
2859                 desc2.u2.dwMipMapCount = 0;
2860                 while( min )
2861                 {
2862                     desc2.u2.dwMipMapCount += 1;
2863                     min >>= 1;
2864                 }
2865             }
2866         }
2867         else
2868         {
2869             /* Not-complex mipmap -> Mipmapcount = 1 */
2870             desc2.u2.dwMipMapCount = 1;
2871         }
2872         extra_surfaces = desc2.u2.dwMipMapCount - 1;
2873
2874         /* There's a mipmap count in the created surface in any case */
2875         desc2.dwFlags |= DDSD_MIPMAPCOUNT;
2876     }
2877     /* If no mipmap is given, the texture has only one level */
2878
2879     /* The first surface is a front buffer, the back buffer is created afterwards */
2880     if( (desc2.dwFlags & DDSD_CAPS) && (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) )
2881     {
2882         desc2.ddsCaps.dwCaps |= DDSCAPS_FRONTBUFFER;
2883     }
2884
2885     /* The root surface in a cube map is positive x */
2886     if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2887     {
2888         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
2889         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
2890     }
2891
2892     /* Create the first surface */
2893     hr = ddraw_create_surface(ddraw, &desc2, &object, 0, version);
2894     if (FAILED(hr))
2895     {
2896         WARN("ddraw_create_surface failed, hr %#x.\n", hr);
2897         LeaveCriticalSection(&ddraw_cs);
2898         return hr;
2899     }
2900     object->is_complex_root = TRUE;
2901
2902     *Surf = object;
2903
2904     /* Create Additional surfaces if necessary
2905      * This applies to Primary surfaces which have a back buffer count
2906      * set, but not to mipmap textures. In case of Mipmap textures,
2907      * wineD3D takes care of the creation of additional surfaces
2908      */
2909     if(DDSD->dwFlags & DDSD_BACKBUFFERCOUNT)
2910     {
2911         extra_surfaces = DDSD->dwBackBufferCount;
2912         desc2.ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER; /* It's not a front buffer */
2913         desc2.ddsCaps.dwCaps |= DDSCAPS_BACKBUFFER;
2914         desc2.dwBackBufferCount = 0;
2915     }
2916
2917     hr = DD_OK;
2918     if(desc2.ddsCaps.dwCaps2 & DDSCAPS2_CUBEMAP)
2919     {
2920         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
2921         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEZ;
2922         hr |= CreateAdditionalSurfaces(ddraw, object, extra_surfaces + 1, desc2, TRUE, version);
2923         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEZ;
2924         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEZ;
2925         hr |= CreateAdditionalSurfaces(ddraw, object, extra_surfaces + 1, desc2, TRUE, version);
2926         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEZ;
2927         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEY;
2928         hr |= CreateAdditionalSurfaces(ddraw, object, extra_surfaces + 1, desc2, TRUE, version);
2929         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEY;
2930         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEY;
2931         hr |= CreateAdditionalSurfaces(ddraw, object, extra_surfaces + 1, desc2, TRUE, version);
2932         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_POSITIVEY;
2933         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_NEGATIVEX;
2934         hr |= CreateAdditionalSurfaces(ddraw, object, extra_surfaces + 1, desc2, TRUE, version);
2935         desc2.ddsCaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_NEGATIVEX;
2936         desc2.ddsCaps.dwCaps2 |=  DDSCAPS2_CUBEMAP_POSITIVEX;
2937     }
2938
2939     hr |= CreateAdditionalSurfaces(ddraw, object, extra_surfaces, desc2, FALSE, version);
2940     if(hr != DD_OK)
2941     {
2942         /* This destroys and possibly created surfaces too */
2943         if (version == 7)
2944         {
2945             IDirectDrawSurface7_Release(&object->IDirectDrawSurface7_iface);
2946         }
2947         else if (version == 4)
2948         {
2949             IDirectDrawSurface4_Release(&object->IDirectDrawSurface4_iface);
2950         }
2951         else
2952         {
2953             IDirectDrawSurface_Release(&object->IDirectDrawSurface_iface);
2954         }
2955         LeaveCriticalSection(&ddraw_cs);
2956         return hr;
2957     }
2958
2959     if (!ddraw->d3d_initialized && desc2.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_3DDEVICE))
2960     {
2961         if (FAILED(hr = ddraw_create_swapchain(ddraw, object)))
2962         {
2963             IDirectDrawSurfaceImpl *release_surf;
2964             ERR("Failed to create swapchain, hr %#x.\n", hr);
2965             *Surf = NULL;
2966
2967             /* The earlier created surface structures are in an incomplete
2968              * state here. Wined3d holds the reference on the parents, and it
2969              * released them on the failure already. So the regular release
2970              * method implementation would fail on the attempt to destroy
2971              * either the parents or the swapchain. So free the surface here.
2972              * The surface structure here is a list, not a tree, because
2973              * onscreen targets cannot be cube textures. */
2974             while (object)
2975             {
2976                 release_surf = object;
2977                 object = object->complex_array[0];
2978                 ddraw_surface_destroy(release_surf);
2979             }
2980             LeaveCriticalSection(&ddraw_cs);
2981             return hr;
2982         }
2983     }
2984
2985     if (desc2.ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE)
2986         ddraw->primary = object;
2987
2988     /* Create a WineD3DTexture if a texture was requested */
2989     if (desc2.ddsCaps.dwCaps & DDSCAPS_TEXTURE)
2990     {
2991         ddraw->tex_root = object;
2992         ddraw_surface_create_texture(object);
2993         ddraw->tex_root = NULL;
2994     }
2995
2996     LeaveCriticalSection(&ddraw_cs);
2997     return hr;
2998 }
2999
3000 static HRESULT WINAPI ddraw7_CreateSurface(IDirectDraw7 *iface, DDSURFACEDESC2 *surface_desc,
3001         IDirectDrawSurface7 **surface, IUnknown *outer_unknown)
3002 {
3003     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
3004     IDirectDrawSurfaceImpl *impl;
3005     HRESULT hr;
3006
3007     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3008             iface, surface_desc, surface, outer_unknown);
3009
3010     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC2))
3011     {
3012         WARN("Application supplied invalid surface descriptor\n");
3013         return DDERR_INVALIDPARAMS;
3014     }
3015
3016     if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
3017     {
3018         if (TRACE_ON(ddraw))
3019         {
3020             TRACE(" (%p) Requesting surface desc :\n", iface);
3021             DDRAW_dump_surface_desc(surface_desc);
3022         }
3023
3024         WARN("Application tried to create an explicit front or back buffer\n");
3025         return DDERR_INVALIDCAPS;
3026     }
3027
3028     hr = CreateSurface(This, surface_desc, &impl, outer_unknown, 7);
3029     if (FAILED(hr))
3030     {
3031         *surface = NULL;
3032         return hr;
3033     }
3034
3035     *surface = &impl->IDirectDrawSurface7_iface;
3036     IDirectDraw7_AddRef(iface);
3037     impl->ifaceToRelease = (IUnknown *)iface;
3038
3039     return hr;
3040 }
3041
3042 static HRESULT WINAPI ddraw4_CreateSurface(IDirectDraw4 *iface,
3043         DDSURFACEDESC2 *surface_desc, IDirectDrawSurface4 **surface, IUnknown *outer_unknown)
3044 {
3045     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
3046     IDirectDrawSurfaceImpl *impl;
3047     HRESULT hr;
3048
3049     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3050             iface, surface_desc, surface, outer_unknown);
3051
3052     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC2))
3053     {
3054         WARN("Application supplied invalid surface descriptor\n");
3055         return DDERR_INVALIDPARAMS;
3056     }
3057
3058     if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
3059     {
3060         if (TRACE_ON(ddraw))
3061         {
3062             TRACE(" (%p) Requesting surface desc :\n", iface);
3063             DDRAW_dump_surface_desc(surface_desc);
3064         }
3065
3066         WARN("Application tried to create an explicit front or back buffer\n");
3067         return DDERR_INVALIDCAPS;
3068     }
3069
3070     hr = CreateSurface(This, surface_desc, &impl, outer_unknown, 4);
3071     if (FAILED(hr))
3072     {
3073         *surface = NULL;
3074         return hr;
3075     }
3076
3077     *surface = &impl->IDirectDrawSurface4_iface;
3078     IDirectDraw4_AddRef(iface);
3079     impl->ifaceToRelease = (IUnknown *)iface;
3080
3081     return hr;
3082 }
3083
3084 static HRESULT WINAPI ddraw2_CreateSurface(IDirectDraw2 *iface,
3085         DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3086 {
3087     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
3088     IDirectDrawSurfaceImpl *impl;
3089     HRESULT hr;
3090     DDSURFACEDESC2 surface_desc2;
3091
3092     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3093             iface, surface_desc, surface, outer_unknown);
3094
3095     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC))
3096     {
3097         WARN("Application supplied invalid surface descriptor\n");
3098         return DDERR_INVALIDPARAMS;
3099     }
3100
3101     DDSD_to_DDSD2(surface_desc, &surface_desc2);
3102     if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
3103     {
3104         if (TRACE_ON(ddraw))
3105         {
3106             TRACE(" (%p) Requesting surface desc :\n", iface);
3107             DDRAW_dump_surface_desc((LPDDSURFACEDESC2)surface_desc);
3108         }
3109
3110         WARN("Application tried to create an explicit front or back buffer\n");
3111         return DDERR_INVALIDCAPS;
3112     }
3113
3114     hr = CreateSurface(This, &surface_desc2, &impl, outer_unknown, 2);
3115     if (FAILED(hr))
3116     {
3117         *surface = NULL;
3118         return hr;
3119     }
3120
3121     *surface = &impl->IDirectDrawSurface_iface;
3122     impl->ifaceToRelease = NULL;
3123
3124     return hr;
3125 }
3126
3127 static HRESULT WINAPI ddraw1_CreateSurface(IDirectDraw *iface,
3128         DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3129 {
3130     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
3131     IDirectDrawSurfaceImpl *impl;
3132     HRESULT hr;
3133     DDSURFACEDESC2 surface_desc2;
3134
3135     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3136             iface, surface_desc, surface, outer_unknown);
3137
3138     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC))
3139     {
3140         WARN("Application supplied invalid surface descriptor\n");
3141         return DDERR_INVALIDPARAMS;
3142     }
3143
3144     /* Remove front buffer flag, this causes failure in v7, and its added to normal
3145      * primaries anyway. */
3146     surface_desc->ddsCaps.dwCaps &= ~DDSCAPS_FRONTBUFFER;
3147     DDSD_to_DDSD2(surface_desc, &surface_desc2);
3148     hr = CreateSurface(This, &surface_desc2, &impl, outer_unknown, 1);
3149     if (FAILED(hr))
3150     {
3151         *surface = NULL;
3152         return hr;
3153     }
3154
3155     *surface = &impl->IDirectDrawSurface_iface;
3156     impl->ifaceToRelease = NULL;
3157
3158     return hr;
3159 }
3160
3161 #define DDENUMSURFACES_SEARCHTYPE (DDENUMSURFACES_CANBECREATED|DDENUMSURFACES_DOESEXIST)
3162 #define DDENUMSURFACES_MATCHTYPE (DDENUMSURFACES_ALL|DDENUMSURFACES_MATCH|DDENUMSURFACES_NOMATCH)
3163
3164 static BOOL
3165 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
3166                                     const DDPIXELFORMAT *provided)
3167 {
3168     /* Some flags must be present in both or neither for a match. */
3169     static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
3170         | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
3171         | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
3172
3173     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3174         return FALSE;
3175
3176     if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
3177         return FALSE;
3178
3179     if (requested->dwFlags & DDPF_FOURCC)
3180         if (requested->dwFourCC != provided->dwFourCC)
3181             return FALSE;
3182
3183     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
3184                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3185         if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
3186             return FALSE;
3187
3188     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3189                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3190         if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
3191             return FALSE;
3192
3193     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
3194         if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
3195             return FALSE;
3196
3197     /* I could be wrong about the bumpmapping. MSDN docs are vague. */
3198     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3199                               |DDPF_BUMPDUDV))
3200         if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
3201             return FALSE;
3202
3203     if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
3204         if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
3205             return FALSE;
3206
3207     return TRUE;
3208 }
3209
3210 static BOOL ddraw_match_surface_desc(const DDSURFACEDESC2 *requested, const DDSURFACEDESC2 *provided)
3211 {
3212     struct compare_info
3213     {
3214         DWORD flag;
3215         ptrdiff_t offset;
3216         size_t size;
3217     };
3218
3219 #define CMP(FLAG, FIELD)                                \
3220         { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
3221           sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
3222
3223     static const struct compare_info compare[] =
3224     {
3225         CMP(ALPHABITDEPTH, dwAlphaBitDepth),
3226         CMP(BACKBUFFERCOUNT, dwBackBufferCount),
3227         CMP(CAPS, ddsCaps),
3228         CMP(CKDESTBLT, ddckCKDestBlt),
3229         CMP(CKDESTOVERLAY, u3 /* ddckCKDestOverlay */),
3230         CMP(CKSRCBLT, ddckCKSrcBlt),
3231         CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
3232         CMP(HEIGHT, dwHeight),
3233         CMP(LINEARSIZE, u1 /* dwLinearSize */),
3234         CMP(LPSURFACE, lpSurface),
3235         CMP(MIPMAPCOUNT, u2 /* dwMipMapCount */),
3236         CMP(PITCH, u1 /* lPitch */),
3237         /* PIXELFORMAT: manual */
3238         CMP(REFRESHRATE, u2 /* dwRefreshRate */),
3239         CMP(TEXTURESTAGE, dwTextureStage),
3240         CMP(WIDTH, dwWidth),
3241         /* ZBUFFERBITDEPTH: "obsolete" */
3242     };
3243
3244 #undef CMP
3245
3246     unsigned int i;
3247
3248     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3249         return FALSE;
3250
3251     for (i=0; i < sizeof(compare)/sizeof(compare[0]); i++)
3252     {
3253         if (requested->dwFlags & compare[i].flag
3254             && memcmp((const char *)provided + compare[i].offset,
3255                       (const char *)requested + compare[i].offset,
3256                       compare[i].size) != 0)
3257             return FALSE;
3258     }
3259
3260     if (requested->dwFlags & DDSD_PIXELFORMAT)
3261     {
3262         if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
3263                                                 &provided->u4.ddpfPixelFormat))
3264             return FALSE;
3265     }
3266
3267     return TRUE;
3268 }
3269
3270 #undef DDENUMSURFACES_SEARCHTYPE
3271 #undef DDENUMSURFACES_MATCHTYPE
3272
3273 struct surfacescallback2_context
3274 {
3275     LPDDENUMSURFACESCALLBACK2 func;
3276     void *context;
3277 };
3278
3279 struct surfacescallback_context
3280 {
3281     LPDDENUMSURFACESCALLBACK func;
3282     void *context;
3283 };
3284
3285 static HRESULT CALLBACK EnumSurfacesCallback2Thunk(IDirectDrawSurface7 *surface,
3286         DDSURFACEDESC2 *surface_desc, void *context)
3287 {
3288     IDirectDrawSurfaceImpl *surface_impl = impl_from_IDirectDrawSurface7(surface);
3289     struct surfacescallback2_context *cbcontext = context;
3290
3291     IDirectDrawSurface4_AddRef(&surface_impl->IDirectDrawSurface4_iface);
3292     IDirectDrawSurface7_Release(surface);
3293
3294     return cbcontext->func(&surface_impl->IDirectDrawSurface4_iface,
3295             surface_desc, cbcontext->context);
3296 }
3297
3298 static HRESULT CALLBACK EnumSurfacesCallbackThunk(IDirectDrawSurface7 *surface,
3299         DDSURFACEDESC2 *surface_desc, void *context)
3300 {
3301     IDirectDrawSurfaceImpl *surface_impl = impl_from_IDirectDrawSurface7(surface);
3302     struct surfacescallback_context *cbcontext = context;
3303
3304     IDirectDrawSurface_AddRef(&surface_impl->IDirectDrawSurface_iface);
3305     IDirectDrawSurface7_Release(surface);
3306
3307     return cbcontext->func(&surface_impl->IDirectDrawSurface_iface,
3308             (DDSURFACEDESC *)surface_desc, cbcontext->context);
3309 }
3310
3311 /*****************************************************************************
3312  * IDirectDraw7::EnumSurfaces
3313  *
3314  * Loops through all surfaces attached to this device and calls the
3315  * application callback. This can't be relayed to WineD3DDevice,
3316  * because some WineD3DSurfaces' parents are IParent objects
3317  *
3318  * Params:
3319  *  Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
3320  *  DDSD: Description to filter for
3321  *  Context: Application-provided pointer, it's passed unmodified to the
3322  *           Callback function
3323  *  Callback: Address to call for each surface
3324  *
3325  * Returns:
3326  *  DDERR_INVALIDPARAMS if the callback is NULL
3327  *  DD_OK on success
3328  *
3329  *****************************************************************************/
3330 static HRESULT WINAPI ddraw7_EnumSurfaces(IDirectDraw7 *iface, DWORD Flags,
3331         DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMSURFACESCALLBACK7 Callback)
3332 {
3333     /* The surface enumeration is handled by WineDDraw,
3334      * because it keeps track of all surfaces attached to
3335      * it. The filtering is done by our callback function,
3336      * because WineDDraw doesn't handle ddraw-like surface
3337      * caps structures
3338      */
3339     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
3340     IDirectDrawSurfaceImpl *surf;
3341     BOOL all, nomatch;
3342     DDSURFACEDESC2 desc;
3343     struct list *entry, *entry2;
3344
3345     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3346             iface, Flags, DDSD, Context, Callback);
3347
3348     all = Flags & DDENUMSURFACES_ALL;
3349     nomatch = Flags & DDENUMSURFACES_NOMATCH;
3350
3351     EnterCriticalSection(&ddraw_cs);
3352
3353     if(!Callback)
3354     {
3355         LeaveCriticalSection(&ddraw_cs);
3356         return DDERR_INVALIDPARAMS;
3357     }
3358
3359     /* Use the _SAFE enumeration, the app may destroy enumerated surfaces */
3360     LIST_FOR_EACH_SAFE(entry, entry2, &This->surface_list)
3361     {
3362         surf = LIST_ENTRY(entry, IDirectDrawSurfaceImpl, surface_list_entry);
3363         if (all || (nomatch != ddraw_match_surface_desc(DDSD, &surf->surface_desc)))
3364         {
3365             TRACE("Enumerating surface %p.\n", surf);
3366             desc = surf->surface_desc;
3367             IDirectDrawSurface7_AddRef(&surf->IDirectDrawSurface7_iface);
3368             if (Callback(&surf->IDirectDrawSurface7_iface, &desc, Context) != DDENUMRET_OK)
3369             {
3370                 LeaveCriticalSection(&ddraw_cs);
3371                 return DD_OK;
3372             }
3373         }
3374     }
3375     LeaveCriticalSection(&ddraw_cs);
3376     return DD_OK;
3377 }
3378
3379 static HRESULT WINAPI ddraw4_EnumSurfaces(IDirectDraw4 *iface, DWORD flags,
3380         DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMSURFACESCALLBACK2 callback)
3381 {
3382     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
3383     struct surfacescallback2_context cbcontext;
3384
3385     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3386             iface, flags, surface_desc, context, callback);
3387
3388     cbcontext.func = callback;
3389     cbcontext.context = context;
3390
3391     return ddraw7_EnumSurfaces(&This->IDirectDraw7_iface, flags, surface_desc,
3392             &cbcontext, EnumSurfacesCallback2Thunk);
3393 }
3394
3395 static HRESULT WINAPI ddraw2_EnumSurfaces(IDirectDraw2 *iface, DWORD flags,
3396         DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3397 {
3398     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
3399     struct surfacescallback_context cbcontext;
3400     DDSURFACEDESC2 surface_desc2;
3401
3402     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3403             iface, flags, surface_desc, context, callback);
3404
3405     cbcontext.func = callback;
3406     cbcontext.context = context;
3407
3408     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
3409     return ddraw7_EnumSurfaces(&This->IDirectDraw7_iface, flags,
3410             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumSurfacesCallbackThunk);
3411 }
3412
3413 static HRESULT WINAPI ddraw1_EnumSurfaces(IDirectDraw *iface, DWORD flags,
3414         DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3415 {
3416     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
3417     struct surfacescallback_context cbcontext;
3418     DDSURFACEDESC2 surface_desc2;
3419
3420     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3421             iface, flags, surface_desc, context, callback);
3422
3423     cbcontext.func = callback;
3424     cbcontext.context = context;
3425
3426     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
3427     return ddraw7_EnumSurfaces(&This->IDirectDraw7_iface, flags,
3428             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumSurfacesCallbackThunk);
3429 }
3430
3431 /*****************************************************************************
3432  * DirectDrawCreateClipper (DDRAW.@)
3433  *
3434  * Creates a new IDirectDrawClipper object.
3435  *
3436  * Params:
3437  *  Clipper: Address to write the interface pointer to
3438  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3439  *            NULL
3440  *
3441  * Returns:
3442  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
3443  *  E_OUTOFMEMORY if allocating the object failed
3444  *
3445  *****************************************************************************/
3446 HRESULT WINAPI
3447 DirectDrawCreateClipper(DWORD Flags,
3448                         LPDIRECTDRAWCLIPPER *Clipper,
3449                         IUnknown *UnkOuter)
3450 {
3451     IDirectDrawClipperImpl* object;
3452     HRESULT hr;
3453
3454     TRACE("flags %#x, clipper %p, outer_unknown %p.\n",
3455             Flags, Clipper, UnkOuter);
3456
3457     EnterCriticalSection(&ddraw_cs);
3458     if (UnkOuter != NULL)
3459     {
3460         LeaveCriticalSection(&ddraw_cs);
3461         return CLASS_E_NOAGGREGATION;
3462     }
3463
3464     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3465                      sizeof(IDirectDrawClipperImpl));
3466     if (object == NULL)
3467     {
3468         LeaveCriticalSection(&ddraw_cs);
3469         return E_OUTOFMEMORY;
3470     }
3471
3472     hr = ddraw_clipper_init(object);
3473     if (FAILED(hr))
3474     {
3475         WARN("Failed to initialize clipper, hr %#x.\n", hr);
3476         HeapFree(GetProcessHeap(), 0, object);
3477         LeaveCriticalSection(&ddraw_cs);
3478         return hr;
3479     }
3480
3481     TRACE("Created clipper %p.\n", object);
3482     *Clipper = &object->IDirectDrawClipper_iface;
3483     LeaveCriticalSection(&ddraw_cs);
3484     return DD_OK;
3485 }
3486
3487 /*****************************************************************************
3488  * IDirectDraw7::CreateClipper
3489  *
3490  * Creates a DDraw clipper. See DirectDrawCreateClipper for details
3491  *
3492  *****************************************************************************/
3493 static HRESULT WINAPI ddraw7_CreateClipper(IDirectDraw7 *iface, DWORD Flags,
3494         IDirectDrawClipper **Clipper, IUnknown *UnkOuter)
3495 {
3496     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3497             iface, Flags, Clipper, UnkOuter);
3498
3499     return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
3500 }
3501
3502 static HRESULT WINAPI ddraw4_CreateClipper(IDirectDraw4 *iface, DWORD flags,
3503         IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3504 {
3505     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
3506
3507     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3508             iface, flags, clipper, outer_unknown);
3509
3510     return ddraw7_CreateClipper(&This->IDirectDraw7_iface, flags, clipper, outer_unknown);
3511 }
3512
3513 static HRESULT WINAPI ddraw2_CreateClipper(IDirectDraw2 *iface,
3514         DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3515 {
3516     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
3517
3518     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3519             iface, flags, clipper, outer_unknown);
3520
3521     return ddraw7_CreateClipper(&This->IDirectDraw7_iface, flags, clipper, outer_unknown);
3522 }
3523
3524 static HRESULT WINAPI ddraw1_CreateClipper(IDirectDraw *iface,
3525         DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3526 {
3527     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
3528
3529     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3530             iface, flags, clipper, outer_unknown);
3531
3532     return ddraw7_CreateClipper(&This->IDirectDraw7_iface, flags, clipper, outer_unknown);
3533 }
3534
3535 /*****************************************************************************
3536  * IDirectDraw7::CreatePalette
3537  *
3538  * Creates a new IDirectDrawPalette object
3539  *
3540  * Params:
3541  *  Flags: The flags for the new clipper
3542  *  ColorTable: Color table to assign to the new clipper
3543  *  Palette: Address to write the interface pointer to
3544  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3545  *            NULL
3546  *
3547  * Returns:
3548  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
3549  *  E_OUTOFMEMORY if allocating the object failed
3550  *
3551  *****************************************************************************/
3552 static HRESULT WINAPI ddraw7_CreatePalette(IDirectDraw7 *iface, DWORD Flags,
3553         PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *pUnkOuter)
3554 {
3555     IDirectDrawImpl *This = impl_from_IDirectDraw7(iface);
3556     IDirectDrawPaletteImpl *object;
3557     HRESULT hr;
3558
3559     TRACE("iface %p, flags %#x, color_table %p, palette %p, outer_unknown %p.\n",
3560             iface, Flags, ColorTable, Palette, pUnkOuter);
3561
3562     EnterCriticalSection(&ddraw_cs);
3563     if(pUnkOuter != NULL)
3564     {
3565         WARN("pUnkOuter is %p, returning CLASS_E_NOAGGREGATION\n", pUnkOuter);
3566         LeaveCriticalSection(&ddraw_cs);
3567         return CLASS_E_NOAGGREGATION;
3568     }
3569
3570     /* The refcount test shows that a cooplevel is required for this */
3571     if(!This->cooperative_level)
3572     {
3573         WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
3574         LeaveCriticalSection(&ddraw_cs);
3575         return DDERR_NOCOOPERATIVELEVELSET;
3576     }
3577
3578     object = HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectDrawPaletteImpl));
3579     if(!object)
3580     {
3581         ERR("Out of memory when allocating memory for a palette implementation\n");
3582         LeaveCriticalSection(&ddraw_cs);
3583         return E_OUTOFMEMORY;
3584     }
3585
3586     hr = ddraw_palette_init(object, This, Flags, ColorTable);
3587     if (FAILED(hr))
3588     {
3589         WARN("Failed to initialize palette, hr %#x.\n", hr);
3590         HeapFree(GetProcessHeap(), 0, object);
3591         LeaveCriticalSection(&ddraw_cs);
3592         return hr;
3593     }
3594
3595     TRACE("Created palette %p.\n", object);
3596     *Palette = (IDirectDrawPalette *)object;
3597     LeaveCriticalSection(&ddraw_cs);
3598     return DD_OK;
3599 }
3600
3601 static HRESULT WINAPI ddraw4_CreatePalette(IDirectDraw4 *iface, DWORD flags, PALETTEENTRY *entries,
3602         IDirectDrawPalette **palette, IUnknown *outer_unknown)
3603 {
3604     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
3605     HRESULT hr;
3606
3607     TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3608             iface, flags, entries, palette, outer_unknown);
3609
3610     hr = ddraw7_CreatePalette(&This->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3611     if (SUCCEEDED(hr) && *palette)
3612     {
3613         IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
3614         IDirectDraw7_Release(&This->IDirectDraw7_iface);
3615         IDirectDraw4_AddRef(iface);
3616         impl->ifaceToRelease = (IUnknown *)iface;
3617     }
3618     return hr;
3619 }
3620
3621 static HRESULT WINAPI ddraw2_CreatePalette(IDirectDraw2 *iface, DWORD flags,
3622         PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3623 {
3624     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
3625     HRESULT hr;
3626
3627     TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3628             iface, flags, entries, palette, outer_unknown);
3629
3630     hr = ddraw7_CreatePalette(&This->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3631     if (SUCCEEDED(hr) && *palette)
3632     {
3633         IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
3634         IDirectDraw7_Release(&This->IDirectDraw7_iface);
3635         impl->ifaceToRelease = NULL;
3636     }
3637
3638     return hr;
3639 }
3640
3641 static HRESULT WINAPI ddraw1_CreatePalette(IDirectDraw *iface, DWORD flags,
3642         PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3643 {
3644     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
3645     HRESULT hr;
3646
3647     TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3648             iface, flags, entries, palette, outer_unknown);
3649
3650     hr = ddraw7_CreatePalette(&This->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3651     if (SUCCEEDED(hr) && *palette)
3652     {
3653         IDirectDrawPaletteImpl *impl = (IDirectDrawPaletteImpl *)*palette;
3654         IDirectDraw7_Release(&This->IDirectDraw7_iface);
3655         impl->ifaceToRelease = NULL;
3656     }
3657
3658     return hr;
3659 }
3660
3661 /*****************************************************************************
3662  * IDirectDraw7::DuplicateSurface
3663  *
3664  * Duplicates a surface. The surface memory points to the same memory as
3665  * the original surface, and it's released when the last surface referencing
3666  * it is released. I guess that's beyond Wine's surface management right now
3667  * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
3668  * test application to implement this)
3669  *
3670  * Params:
3671  *  Src: Address of the source surface
3672  *  Dest: Address to write the new surface pointer to
3673  *
3674  * Returns:
3675  *  See IDirectDraw7::CreateSurface
3676  *
3677  *****************************************************************************/
3678 static HRESULT WINAPI ddraw7_DuplicateSurface(IDirectDraw7 *iface,
3679         IDirectDrawSurface7 *Src, IDirectDrawSurface7 **Dest)
3680 {
3681     IDirectDrawSurfaceImpl *Surf = unsafe_impl_from_IDirectDrawSurface7(Src);
3682
3683     FIXME("iface %p, src %p, dst %p partial stub!\n", iface, Src, Dest);
3684
3685     /* For now, simply create a new, independent surface */
3686     return IDirectDraw7_CreateSurface(iface,
3687                                       &Surf->surface_desc,
3688                                       Dest,
3689                                       NULL);
3690 }
3691
3692 static HRESULT WINAPI ddraw4_DuplicateSurface(IDirectDraw4 *iface, IDirectDrawSurface4 *src,
3693         IDirectDrawSurface4 **dst)
3694 {
3695     IDirectDrawImpl *This = impl_from_IDirectDraw4(iface);
3696     IDirectDrawSurfaceImpl *src_impl = unsafe_impl_from_IDirectDrawSurface4(src);
3697     IDirectDrawSurface7 *dst7;
3698     IDirectDrawSurfaceImpl *dst_impl;
3699     HRESULT hr;
3700
3701     TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3702     hr = ddraw7_DuplicateSurface(&This->IDirectDraw7_iface,
3703             src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3704     if (FAILED(hr))
3705     {
3706         *dst = NULL;
3707         return hr;
3708     }
3709     dst_impl = impl_from_IDirectDrawSurface7(dst7);
3710     *dst = &dst_impl->IDirectDrawSurface4_iface;
3711     IDirectDrawSurface4_AddRef(*dst);
3712     IDirectDrawSurface7_Release(dst7);
3713
3714     return hr;
3715 }
3716
3717 static HRESULT WINAPI ddraw2_DuplicateSurface(IDirectDraw2 *iface,
3718         IDirectDrawSurface *src, IDirectDrawSurface **dst)
3719 {
3720     IDirectDrawImpl *This = impl_from_IDirectDraw2(iface);
3721     IDirectDrawSurfaceImpl *src_impl = unsafe_impl_from_IDirectDrawSurface(src);
3722     IDirectDrawSurface7 *dst7;
3723     IDirectDrawSurfaceImpl *dst_impl;
3724     HRESULT hr;
3725
3726     TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3727     hr = ddraw7_DuplicateSurface(&This->IDirectDraw7_iface,
3728             src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3729     if (FAILED(hr))
3730         return hr;
3731     dst_impl = impl_from_IDirectDrawSurface7(dst7);
3732     *dst = &dst_impl->IDirectDrawSurface_iface;
3733     IDirectDrawSurface_AddRef(*dst);
3734     IDirectDrawSurface7_Release(dst7);
3735
3736     return hr;
3737 }
3738
3739 static HRESULT WINAPI ddraw1_DuplicateSurface(IDirectDraw *iface, IDirectDrawSurface *src,
3740         IDirectDrawSurface **dst)
3741 {
3742     IDirectDrawImpl *This = impl_from_IDirectDraw(iface);
3743     IDirectDrawSurfaceImpl *src_impl = unsafe_impl_from_IDirectDrawSurface(src);
3744     IDirectDrawSurface7 *dst7;
3745     IDirectDrawSurfaceImpl *dst_impl;
3746     HRESULT hr;
3747
3748     TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3749     hr = ddraw7_DuplicateSurface(&This->IDirectDraw7_iface,
3750             src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3751     if (FAILED(hr))
3752         return hr;
3753     dst_impl = impl_from_IDirectDrawSurface7(dst7);
3754     *dst = &dst_impl->IDirectDrawSurface_iface;
3755     IDirectDrawSurface_AddRef(*dst);
3756     IDirectDrawSurface7_Release(dst7);
3757
3758     return hr;
3759 }
3760
3761 /*****************************************************************************
3762  * IDirect3D7::EnumDevices
3763  *
3764  * The EnumDevices method for IDirect3D7. It enumerates all supported
3765  * D3D7 devices. Currently the T&L, HAL and RGB devices are enumerated.
3766  *
3767  * Params:
3768  *  callback: Function to call for each enumerated device
3769  *  context: Pointer to pass back to the app
3770  *
3771  * Returns:
3772  *  D3D_OK, or the return value of the GetCaps call
3773  *
3774  *****************************************************************************/
3775 static HRESULT WINAPI d3d7_EnumDevices(IDirect3D7 *iface, LPD3DENUMDEVICESCALLBACK7 callback, void *context)
3776 {
3777     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
3778     D3DDEVICEDESC7 device_desc7;
3779     D3DDEVICEDESC device_desc1;
3780     HRESULT hr;
3781     size_t i;
3782
3783     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3784
3785     if (!callback)
3786         return DDERR_INVALIDPARAMS;
3787
3788     EnterCriticalSection(&ddraw_cs);
3789
3790     hr = IDirect3DImpl_GetCaps(This->wineD3D, &device_desc1, &device_desc7);
3791     if (hr != D3D_OK)
3792     {
3793         LeaveCriticalSection(&ddraw_cs);
3794         return hr;
3795     }
3796
3797     for (i = 0; i < sizeof(device_list7)/sizeof(device_list7[0]); i++)
3798     {
3799         HRESULT ret;
3800
3801         device_desc7.deviceGUID = *device_list7[i].device_guid;
3802         ret = callback(device_list7[i].interface_name, device_list7[i].device_name, &device_desc7, context);
3803         if (ret != DDENUMRET_OK)
3804         {
3805             TRACE("Application cancelled the enumeration.\n");
3806             LeaveCriticalSection(&ddraw_cs);
3807             return D3D_OK;
3808         }
3809     }
3810
3811     TRACE("End of enumeration.\n");
3812
3813     LeaveCriticalSection(&ddraw_cs);
3814
3815     return D3D_OK;
3816 }
3817
3818 /*****************************************************************************
3819  * IDirect3D3::EnumDevices
3820  *
3821  * Enumerates all supported Direct3DDevice interfaces. This is the
3822  * implementation for Direct3D 1 to Direc3D 3, Version 7 has its own.
3823  *
3824  * Version 1, 2 and 3
3825  *
3826  * Params:
3827  *  callback: Application-provided routine to call for each enumerated device
3828  *  Context: Pointer to pass to the callback
3829  *
3830  * Returns:
3831  *  D3D_OK on success,
3832  *  The result of IDirect3DImpl_GetCaps if it failed
3833  *
3834  *****************************************************************************/
3835 static HRESULT WINAPI d3d3_EnumDevices(IDirect3D3 *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3836 {
3837     static CHAR wined3d_description[] = "Wine D3DDevice using WineD3D and OpenGL";
3838
3839     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
3840     D3DDEVICEDESC device_desc1, hal_desc, hel_desc;
3841     D3DDEVICEDESC7 device_desc7;
3842     HRESULT hr;
3843
3844     /* Some games (Motoracer 2 demo) have the bad idea to modify the device
3845      * name string. Let's put the string in a sufficiently sized array in
3846      * writable memory. */
3847     char device_name[50];
3848     strcpy(device_name,"Direct3D HEL");
3849
3850     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3851
3852     if (!callback)
3853         return DDERR_INVALIDPARAMS;
3854
3855     EnterCriticalSection(&ddraw_cs);
3856
3857     hr = IDirect3DImpl_GetCaps(This->wineD3D, &device_desc1, &device_desc7);
3858     if (hr != D3D_OK)
3859     {
3860         LeaveCriticalSection(&ddraw_cs);
3861         return hr;
3862     }
3863
3864     /* Do I have to enumerate the reference id? Note from old d3d7:
3865      * "It seems that enumerating the reference IID on Direct3D 1 games
3866      * (AvP / Motoracer2) breaks them". So do not enumerate this iid in V1
3867      *
3868      * There's a registry key HKLM\Software\Microsoft\Direct3D\Drivers,
3869      * EnumReference which enables / disables enumerating the reference
3870      * rasterizer. It's a DWORD, 0 means disabled, 2 means enabled. The
3871      * enablerefrast.reg and disablerefrast.reg files in the DirectX 7.0 sdk
3872      * demo directory suggest this.
3873      *
3874      * Some games(GTA 2) seem to use the second enumerated device, so I have
3875      * to enumerate at least 2 devices. So enumerate the reference device to
3876      * have 2 devices.
3877      *
3878      * Other games (Rollcage) tell emulation and hal device apart by certain
3879      * flags. Rollcage expects D3DPTEXTURECAPS_POW2 to be set (yeah, it is a
3880      * limitation flag), and it refuses all devices that have the perspective
3881      * flag set. This way it refuses the emulation device, and HAL devices
3882      * never have POW2 unset in d3d7 on windows. */
3883     if (This->d3dversion != 1)
3884     {
3885         static CHAR reference_description[] = "RGB Direct3D emulation";
3886
3887         TRACE("Enumerating WineD3D D3DDevice interface.\n");
3888         hal_desc = device_desc1;
3889         hel_desc = device_desc1;
3890         /* The rgb device has the pow2 flag set in the hel caps, but not in the hal caps. */
3891         hal_desc.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3892                 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3893         hal_desc.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3894                 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3895         hr = callback((GUID *)&IID_IDirect3DRGBDevice, reference_description,
3896                 device_name, &hal_desc, &hel_desc, context);
3897         if (hr != D3DENUMRET_OK)
3898         {
3899             TRACE("Application cancelled the enumeration.\n");
3900             LeaveCriticalSection(&ddraw_cs);
3901             return D3D_OK;
3902         }
3903     }
3904
3905     strcpy(device_name,"Direct3D HAL");
3906
3907     TRACE("Enumerating HAL Direct3D device.\n");
3908     hal_desc = device_desc1;
3909     hel_desc = device_desc1;
3910     /* The hal device does not have the pow2 flag set in hel, but in hal. */
3911     hel_desc.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3912             | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3913     hel_desc.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3914             | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3915     hr = callback((GUID *)&IID_IDirect3DHALDevice, wined3d_description,
3916             device_name, &hal_desc, &hel_desc, context);
3917     if (hr != D3DENUMRET_OK)
3918     {
3919         TRACE("Application cancelled the enumeration.\n");
3920         LeaveCriticalSection(&ddraw_cs);
3921         return D3D_OK;
3922     }
3923
3924     TRACE("End of enumeration.\n");
3925
3926     LeaveCriticalSection(&ddraw_cs);
3927     return D3D_OK;
3928 }
3929
3930 static HRESULT WINAPI d3d2_EnumDevices(IDirect3D2 *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3931 {
3932     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
3933
3934     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3935
3936     return d3d3_EnumDevices(&This->IDirect3D3_iface, callback, context);
3937 }
3938
3939 static HRESULT WINAPI d3d1_EnumDevices(IDirect3D *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3940 {
3941     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
3942
3943     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3944
3945     return d3d3_EnumDevices(&This->IDirect3D3_iface, callback, context);
3946 }
3947
3948 /*****************************************************************************
3949  * IDirect3D3::CreateLight
3950  *
3951  * Creates an IDirect3DLight interface. This interface is used in
3952  * Direct3D3 or earlier for lighting. In Direct3D7 it has been replaced
3953  * by the DIRECT3DLIGHT7 structure. Wine's Direct3DLight implementation
3954  * uses the IDirect3DDevice7 interface with D3D7 lights.
3955  *
3956  * Version 1, 2 and 3
3957  *
3958  * Params:
3959  *  light: Address to store the new interface pointer
3960  *  outer_unknown: Basically for aggregation, but ddraw doesn't support it.
3961  *                 Must be NULL
3962  *
3963  * Returns:
3964  *  D3D_OK on success
3965  *  DDERR_OUTOFMEMORY if memory allocation failed
3966  *  CLASS_E_NOAGGREGATION if outer_unknown != NULL
3967  *
3968  *****************************************************************************/
3969 static HRESULT WINAPI d3d3_CreateLight(IDirect3D3 *iface, IDirect3DLight **light,
3970         IUnknown *outer_unknown)
3971 {
3972     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
3973     IDirect3DLightImpl *object;
3974
3975     TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
3976
3977     if (outer_unknown) return CLASS_E_NOAGGREGATION;
3978
3979     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
3980     if (!object)
3981     {
3982         ERR("Failed to allocate light memory.\n");
3983         return DDERR_OUTOFMEMORY;
3984     }
3985
3986     d3d_light_init(object, This);
3987
3988     TRACE("Created light %p.\n", object);
3989     *light = &object->IDirect3DLight_iface;
3990
3991     return D3D_OK;
3992 }
3993
3994 static HRESULT WINAPI d3d2_CreateLight(IDirect3D2 *iface, IDirect3DLight **light, IUnknown *outer_unknown)
3995 {
3996     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
3997
3998     TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
3999
4000     return d3d3_CreateLight(&This->IDirect3D3_iface, light, outer_unknown);
4001 }
4002
4003 static HRESULT WINAPI d3d1_CreateLight(IDirect3D *iface, IDirect3DLight **light, IUnknown *outer_unknown)
4004 {
4005     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
4006
4007     TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
4008
4009     return d3d3_CreateLight(&This->IDirect3D3_iface, light, outer_unknown);
4010 }
4011
4012 /*****************************************************************************
4013  * IDirect3D3::CreateMaterial
4014  *
4015  * Creates an IDirect3DMaterial interface. This interface is used by Direct3D3
4016  * and older versions. The IDirect3DMaterial implementation wraps its
4017  * functionality to IDirect3DDevice7::SetMaterial and friends.
4018  *
4019  * Version 1, 2 and 3
4020  *
4021  * Params:
4022  *  material: Address to store the new interface's pointer to
4023  *  outer_unknown: Basically for aggregation, but ddraw doesn't support it.
4024  *                 Must be NULL
4025  *
4026  * Returns:
4027  *  D3D_OK on success
4028  *  DDERR_OUTOFMEMORY if memory allocation failed
4029  *  CLASS_E_NOAGGREGATION if outer_unknown != NULL
4030  *
4031  *****************************************************************************/
4032 static HRESULT WINAPI d3d3_CreateMaterial(IDirect3D3 *iface, IDirect3DMaterial3 **material,
4033         IUnknown *outer_unknown)
4034 {
4035     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4036     IDirect3DMaterialImpl *object;
4037
4038     TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4039
4040     if (outer_unknown) return CLASS_E_NOAGGREGATION;
4041
4042     object = d3d_material_create(This);
4043     if (!object)
4044     {
4045         ERR("Failed to allocate material memory.\n");
4046         return DDERR_OUTOFMEMORY;
4047     }
4048
4049     TRACE("Created material %p.\n", object);
4050     *material = &object->IDirect3DMaterial3_iface;
4051
4052     return D3D_OK;
4053 }
4054
4055 static HRESULT WINAPI d3d2_CreateMaterial(IDirect3D2 *iface, IDirect3DMaterial2 **material,
4056         IUnknown *outer_unknown)
4057 {
4058     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
4059     IDirect3DMaterialImpl *object;
4060
4061     TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4062
4063     object = d3d_material_create(This);
4064     if (!object)
4065     {
4066         ERR("Failed to allocate material memory.\n");
4067         return DDERR_OUTOFMEMORY;
4068     }
4069
4070     TRACE("Created material %p.\n", object);
4071     *material = &object->IDirect3DMaterial2_iface;
4072
4073     return D3D_OK;
4074 }
4075
4076 static HRESULT WINAPI d3d1_CreateMaterial(IDirect3D *iface, IDirect3DMaterial **material,
4077         IUnknown *outer_unknown)
4078 {
4079     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
4080     IDirect3DMaterialImpl *object;
4081
4082     TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4083
4084     object = d3d_material_create(This);
4085     if (!object)
4086     {
4087         ERR("Failed to allocate material memory.\n");
4088         return DDERR_OUTOFMEMORY;
4089     }
4090
4091     TRACE("Created material %p.\n", object);
4092     *material = &object->IDirect3DMaterial_iface;
4093
4094     return D3D_OK;
4095 }
4096
4097 /*****************************************************************************
4098  * IDirect3D3::CreateViewport
4099  *
4100  * Creates an IDirect3DViewport interface. This interface is used
4101  * by Direct3D and earlier versions for Viewport management. In Direct3D7
4102  * it has been replaced by a viewport structure and
4103  * IDirect3DDevice7::*Viewport. Wine's IDirect3DViewport implementation
4104  * uses the IDirect3DDevice7 methods for its functionality
4105  *
4106  * Params:
4107  *  Viewport: Address to store the new interface pointer
4108  *  outer_unknown: Basically for aggregation, but ddraw doesn't support it.
4109  *                 Must be NULL
4110  *
4111  * Returns:
4112  *  D3D_OK on success
4113  *  DDERR_OUTOFMEMORY if memory allocation failed
4114  *  CLASS_E_NOAGGREGATION if outer_unknown != NULL
4115  *
4116  *****************************************************************************/
4117 static HRESULT WINAPI d3d3_CreateViewport(IDirect3D3 *iface, IDirect3DViewport3 **viewport,
4118         IUnknown *outer_unknown)
4119 {
4120     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4121     IDirect3DViewportImpl *object;
4122
4123     TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4124
4125     if (outer_unknown) return CLASS_E_NOAGGREGATION;
4126
4127     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
4128     if (!object)
4129     {
4130         ERR("Failed to allocate viewport memory.\n");
4131         return DDERR_OUTOFMEMORY;
4132     }
4133
4134     d3d_viewport_init(object, This);
4135
4136     TRACE("Created viewport %p.\n", object);
4137     *viewport = (IDirect3DViewport3 *)object;
4138
4139     return D3D_OK;
4140 }
4141
4142 static HRESULT WINAPI d3d2_CreateViewport(IDirect3D2 *iface, IDirect3DViewport2 **viewport, IUnknown *outer_unknown)
4143 {
4144     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
4145
4146     TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4147
4148     return d3d3_CreateViewport(&This->IDirect3D3_iface, (IDirect3DViewport3 **)viewport,
4149             outer_unknown);
4150 }
4151
4152 static HRESULT WINAPI d3d1_CreateViewport(IDirect3D *iface, IDirect3DViewport **viewport, IUnknown *outer_unknown)
4153 {
4154     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
4155
4156     TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4157
4158     return d3d3_CreateViewport(&This->IDirect3D3_iface, (IDirect3DViewport3 **)viewport,
4159             outer_unknown);
4160 }
4161
4162 /*****************************************************************************
4163  * IDirect3D3::FindDevice
4164  *
4165  * This method finds a device with the requested properties and returns a
4166  * device description
4167  *
4168  * Verion 1, 2 and 3
4169  * Params:
4170  *  fds: Describes the requested device characteristics
4171  *  fdr: Returns the device description
4172  *
4173  * Returns:
4174  *  D3D_OK on success
4175  *  DDERR_INVALIDPARAMS if no device was found
4176  *
4177  *****************************************************************************/
4178 static HRESULT WINAPI d3d3_FindDevice(IDirect3D3 *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4179 {
4180     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4181     D3DDEVICEDESC7 desc7;
4182     D3DDEVICEDESC desc1;
4183     HRESULT hr;
4184
4185     TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4186
4187     if (!fds || !fdr) return DDERR_INVALIDPARAMS;
4188
4189     if (fds->dwSize != sizeof(D3DFINDDEVICESEARCH)
4190             || fdr->dwSize != sizeof(D3DFINDDEVICERESULT))
4191         return DDERR_INVALIDPARAMS;
4192
4193     if ((fds->dwFlags & D3DFDS_COLORMODEL)
4194             && fds->dcmColorModel != D3DCOLOR_RGB)
4195     {
4196         WARN("Trying to request a non-RGB D3D color model. Not supported.\n");
4197         return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
4198     }
4199
4200     if (fds->dwFlags & D3DFDS_GUID)
4201     {
4202         TRACE("Trying to match guid %s.\n", debugstr_guid(&(fds->guid)));
4203         if (!IsEqualGUID(&IID_D3DDEVICE_WineD3D, &fds->guid)
4204                 && !IsEqualGUID(&IID_IDirect3DHALDevice, &fds->guid)
4205                 && !IsEqualGUID(&IID_IDirect3DRGBDevice, &fds->guid))
4206         {
4207             WARN("No match for this GUID.\n");
4208             return DDERR_NOTFOUND;
4209         }
4210     }
4211
4212     /* Get the caps */
4213     hr = IDirect3DImpl_GetCaps(This->wineD3D, &desc1, &desc7);
4214     if (hr != D3D_OK) return hr;
4215
4216     /* Now return our own GUID */
4217     fdr->guid = IID_D3DDEVICE_WineD3D;
4218     fdr->ddHwDesc = desc1;
4219     fdr->ddSwDesc = desc1;
4220
4221     TRACE("Returning Wine's wined3d device with (undumped) capabilities.\n");
4222
4223     return D3D_OK;
4224 }
4225
4226 static HRESULT WINAPI d3d2_FindDevice(IDirect3D2 *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4227 {
4228     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
4229
4230     TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4231
4232     return d3d3_FindDevice(&This->IDirect3D3_iface, fds, fdr);
4233 }
4234
4235 static HRESULT WINAPI d3d1_FindDevice(IDirect3D *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4236 {
4237     IDirectDrawImpl *This = impl_from_IDirect3D(iface);
4238
4239     TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4240
4241     return d3d3_FindDevice(&This->IDirect3D3_iface, fds, fdr);
4242 }
4243
4244 /*****************************************************************************
4245  * IDirect3D7::CreateDevice
4246  *
4247  * Creates an IDirect3DDevice7 interface.
4248  *
4249  * Version 2, 3 and 7. IDirect3DDevice 1 interfaces are interfaces to
4250  * DirectDraw surfaces and are created with
4251  * IDirectDrawSurface::QueryInterface. This method uses CreateDevice to
4252  * create the device object and QueryInterfaces for IDirect3DDevice
4253  *
4254  * Params:
4255  *  refiid: IID of the device to create
4256  *  Surface: Initial rendertarget
4257  *  Device: Address to return the interface pointer
4258  *
4259  * Returns:
4260  *  D3D_OK on success
4261  *  DDERR_OUTOFMEMORY if memory allocation failed
4262  *  DDERR_INVALIDPARAMS if a device exists already
4263  *
4264  *****************************************************************************/
4265 static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid,
4266         IDirectDrawSurface7 *surface, IDirect3DDevice7 **device)
4267 {
4268     IDirectDrawSurfaceImpl *target = unsafe_impl_from_IDirectDrawSurface7(surface);
4269     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
4270     IDirect3DDeviceImpl *object;
4271     HRESULT hr;
4272
4273     TRACE("iface %p, riid %s, surface %p, device %p.\n", iface, debugstr_guid(riid), surface, device);
4274
4275     EnterCriticalSection(&ddraw_cs);
4276     *device = NULL;
4277
4278     /* Fail device creation if non-opengl surfaces are used. */
4279     if (DefaultSurfaceType != SURFACE_OPENGL)
4280     {
4281         ERR("The application wants to create a Direct3D device, but non-opengl surfaces are set in the registry.\n");
4282         ERR("Please set the surface implementation to opengl or autodetection to allow 3D rendering.\n");
4283
4284         /* We only hit this path if a default surface is set in the registry. Incorrect autodetection
4285          * is caught in CreateSurface or QueryInterface. */
4286         LeaveCriticalSection(&ddraw_cs);
4287         return DDERR_NO3D;
4288     }
4289
4290     if (This->d3ddevice)
4291     {
4292         FIXME("Only one Direct3D device per DirectDraw object supported.\n");
4293         LeaveCriticalSection(&ddraw_cs);
4294         return DDERR_INVALIDPARAMS;
4295     }
4296
4297     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
4298     if (!object)
4299     {
4300         ERR("Failed to allocate device memory.\n");
4301         LeaveCriticalSection(&ddraw_cs);
4302         return DDERR_OUTOFMEMORY;
4303     }
4304
4305     hr = d3d_device_init(object, This, target);
4306     if (FAILED(hr))
4307     {
4308         WARN("Failed to initialize device, hr %#x.\n", hr);
4309         HeapFree(GetProcessHeap(), 0, object);
4310         LeaveCriticalSection(&ddraw_cs);
4311         return hr;
4312     }
4313
4314     TRACE("Created device %p.\n", object);
4315     *device = (IDirect3DDevice7 *)object;
4316
4317     LeaveCriticalSection(&ddraw_cs);
4318     return D3D_OK;
4319 }
4320
4321 static HRESULT WINAPI d3d3_CreateDevice(IDirect3D3 *iface, REFCLSID riid,
4322         IDirectDrawSurface4 *surface, IDirect3DDevice3 **device, IUnknown *outer_unknown)
4323 {
4324     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4325     IDirectDrawSurfaceImpl *surface_impl = unsafe_impl_from_IDirectDrawSurface4(surface);
4326     HRESULT hr;
4327
4328     TRACE("iface %p, riid %s, surface %p, device %p, outer_unknown %p.\n",
4329             iface, debugstr_guid(riid), surface, device, outer_unknown);
4330
4331     if (outer_unknown) return CLASS_E_NOAGGREGATION;
4332
4333     hr = d3d7_CreateDevice(&This->IDirect3D7_iface, riid,
4334             surface_impl ? &surface_impl->IDirectDrawSurface7_iface : NULL,
4335             (IDirect3DDevice7 **)device);
4336     if (*device) *device = (IDirect3DDevice3 *)&((IDirect3DDeviceImpl *)*device)->IDirect3DDevice3_vtbl;
4337
4338     return hr;
4339 }
4340
4341 static HRESULT WINAPI d3d2_CreateDevice(IDirect3D2 *iface, REFCLSID riid,
4342         IDirectDrawSurface *surface, IDirect3DDevice2 **device)
4343 {
4344     IDirectDrawImpl *This = impl_from_IDirect3D2(iface);
4345     IDirectDrawSurfaceImpl *surface_impl = unsafe_impl_from_IDirectDrawSurface(surface);
4346     HRESULT hr;
4347
4348     TRACE("iface %p, riid %s, surface %p, device %p.\n",
4349             iface, debugstr_guid(riid), surface, device);
4350
4351     hr = d3d7_CreateDevice(&This->IDirect3D7_iface, riid,
4352             surface_impl ? &surface_impl->IDirectDrawSurface7_iface : NULL,
4353             (IDirect3DDevice7 **)device);
4354     if (*device) *device = (IDirect3DDevice2 *)&((IDirect3DDeviceImpl *)*device)->IDirect3DDevice2_vtbl;
4355
4356     return hr;
4357 }
4358
4359 /*****************************************************************************
4360  * IDirect3D7::CreateVertexBuffer
4361  *
4362  * Creates a new vertex buffer object and returns a IDirect3DVertexBuffer7
4363  * interface.
4364  *
4365  * Version 3 and 7
4366  *
4367  * Params:
4368  *  desc: Requested Vertex buffer properties
4369  *  vertex_buffer: Address to return the interface pointer at
4370  *  flags: Some flags, should be 0
4371  *
4372  * Returns
4373  *  D3D_OK on success
4374  *  DDERR_OUTOFMEMORY if memory allocation failed
4375  *  The return value of IWineD3DDevice::CreateVertexBuffer if this call fails
4376  *  DDERR_INVALIDPARAMS if desc or vertex_buffer are NULL
4377  *
4378  *****************************************************************************/
4379 static HRESULT WINAPI d3d7_CreateVertexBuffer(IDirect3D7 *iface, D3DVERTEXBUFFERDESC *desc,
4380         IDirect3DVertexBuffer7 **vertex_buffer, DWORD flags)
4381 {
4382     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
4383     IDirect3DVertexBufferImpl *object;
4384     HRESULT hr;
4385
4386     TRACE("iface %p, desc %p, vertex_buffer %p, flags %#x.\n",
4387             iface, desc, vertex_buffer, flags);
4388
4389     if (!vertex_buffer || !desc) return DDERR_INVALIDPARAMS;
4390
4391     hr = d3d_vertex_buffer_create(&object, This, desc);
4392     if (hr == D3D_OK)
4393     {
4394         TRACE("Created vertex buffer %p.\n", object);
4395         *vertex_buffer = &object->IDirect3DVertexBuffer7_iface;
4396     }
4397     else
4398         WARN("Failed to create vertex buffer, hr %#x.\n", hr);
4399
4400     return hr;
4401 }
4402
4403 static HRESULT WINAPI d3d3_CreateVertexBuffer(IDirect3D3 *iface, D3DVERTEXBUFFERDESC *desc,
4404         IDirect3DVertexBuffer **vertex_buffer, DWORD flags, IUnknown *outer_unknown)
4405 {
4406     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4407     IDirect3DVertexBufferImpl *object;
4408     HRESULT hr;
4409
4410     TRACE("iface %p, desc %p, vertex_buffer %p, flags %#x, outer_unknown %p.\n",
4411             iface, desc, vertex_buffer, flags, outer_unknown);
4412
4413     if (outer_unknown)
4414         return CLASS_E_NOAGGREGATION;
4415     if (!vertex_buffer || !desc)
4416         return DDERR_INVALIDPARAMS;
4417
4418     hr = d3d_vertex_buffer_create(&object, This, desc);
4419     if (hr == D3D_OK)
4420     {
4421         TRACE("Created vertex buffer %p.\n", object);
4422         *vertex_buffer = &object->IDirect3DVertexBuffer_iface;
4423     }
4424     else
4425         WARN("Failed to create vertex buffer, hr %#x.\n", hr);
4426
4427     return hr;
4428 }
4429
4430 /*****************************************************************************
4431  * IDirect3D7::EnumZBufferFormats
4432  *
4433  * Enumerates all supported Z buffer pixel formats
4434  *
4435  * Version 3 and 7
4436  *
4437  * Params:
4438  *  device_iid:
4439  *  callback: callback to call for each pixel format
4440  *  context: Pointer to pass back to the callback
4441  *
4442  * Returns:
4443  *  D3D_OK on success
4444  *  DDERR_INVALIDPARAMS if callback is NULL
4445  *  For details, see IWineD3DDevice::EnumZBufferFormats
4446  *
4447  *****************************************************************************/
4448 static HRESULT WINAPI d3d7_EnumZBufferFormats(IDirect3D7 *iface, REFCLSID device_iid,
4449         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
4450 {
4451     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
4452     WINED3DDISPLAYMODE d3ddm;
4453     WINED3DDEVTYPE type;
4454     unsigned int i;
4455     HRESULT hr;
4456
4457     /* Order matters. Specifically, BattleZone II (full version) expects the
4458      * 16-bit depth formats to be listed before the 24 and 32 ones. */
4459     static const enum wined3d_format_id formats[] =
4460     {
4461         WINED3DFMT_S1_UINT_D15_UNORM,
4462         WINED3DFMT_D16_UNORM,
4463         WINED3DFMT_X8D24_UNORM,
4464         WINED3DFMT_S4X4_UINT_D24_UNORM,
4465         WINED3DFMT_D24_UNORM_S8_UINT,
4466         WINED3DFMT_D32_UNORM,
4467     };
4468
4469     TRACE("iface %p, device_iid %s, callback %p, context %p.\n",
4470             iface, debugstr_guid(device_iid), callback, context);
4471
4472     if (!callback) return DDERR_INVALIDPARAMS;
4473
4474     if (IsEqualGUID(device_iid, &IID_IDirect3DHALDevice)
4475             || IsEqualGUID(device_iid, &IID_IDirect3DTnLHalDevice)
4476             || IsEqualGUID(device_iid, &IID_D3DDEVICE_WineD3D))
4477     {
4478         TRACE("Asked for HAL device.\n");
4479         type = WINED3DDEVTYPE_HAL;
4480     }
4481     else if (IsEqualGUID(device_iid, &IID_IDirect3DRGBDevice)
4482             || IsEqualGUID(device_iid, &IID_IDirect3DMMXDevice))
4483     {
4484         TRACE("Asked for SW device.\n");
4485         type = WINED3DDEVTYPE_SW;
4486     }
4487     else if (IsEqualGUID(device_iid, &IID_IDirect3DRefDevice))
4488     {
4489         TRACE("Asked for REF device.\n");
4490         type = WINED3DDEVTYPE_REF;
4491     }
4492     else if (IsEqualGUID(device_iid, &IID_IDirect3DNullDevice))
4493     {
4494         TRACE("Asked for NULLREF device.\n");
4495         type = WINED3DDEVTYPE_NULLREF;
4496     }
4497     else
4498     {
4499         FIXME("Unexpected device GUID %s.\n", debugstr_guid(device_iid));
4500         type = WINED3DDEVTYPE_HAL;
4501     }
4502
4503     EnterCriticalSection(&ddraw_cs);
4504     /* We need an adapter format from somewhere to please wined3d and WGL.
4505      * Use the current display mode. So far all cards offer the same depth
4506      * stencil format for all modes, but if some do not and applications do
4507      * not like that we'll have to find some workaround, like iterating over
4508      * all imaginable formats and collecting all the depth stencil formats we
4509      * can get. */
4510     hr = wined3d_device_get_display_mode(This->wined3d_device, 0, &d3ddm);
4511
4512     for (i = 0; i < (sizeof(formats) / sizeof(*formats)); ++i)
4513     {
4514         hr = wined3d_check_device_format(This->wineD3D, WINED3DADAPTER_DEFAULT, type, d3ddm.Format,
4515                 WINED3DUSAGE_DEPTHSTENCIL, WINED3DRTYPE_SURFACE, formats[i], SURFACE_OPENGL);
4516         if (SUCCEEDED(hr))
4517         {
4518             DDPIXELFORMAT pformat;
4519
4520             memset(&pformat, 0, sizeof(pformat));
4521             pformat.dwSize = sizeof(pformat);
4522             PixelFormat_WineD3DtoDD(&pformat, formats[i]);
4523
4524             TRACE("Enumerating wined3d format %#x.\n", formats[i]);
4525             hr = callback(&pformat, context);
4526             if (hr != DDENUMRET_OK)
4527             {
4528                 TRACE("Format enumeration cancelled by application.\n");
4529                 LeaveCriticalSection(&ddraw_cs);
4530                 return D3D_OK;
4531             }
4532         }
4533     }
4534
4535     /* Historically some windows drivers used dwZBufferBitDepth=24 for WINED3DFMT_X8D24_UNORM,
4536      * while others used dwZBufferBitDepth=32. In either case the pitch matches a 32 bits per
4537      * pixel format, so we use dwZBufferBitDepth=32. Some games expect 24. Windows Vista and
4538      * newer enumerate both versions, so we do the same(bug 22434) */
4539     hr = wined3d_check_device_format(This->wineD3D, WINED3DADAPTER_DEFAULT, type, d3ddm.Format,
4540             WINED3DUSAGE_DEPTHSTENCIL, WINED3DRTYPE_SURFACE, WINED3DFMT_X8D24_UNORM, SURFACE_OPENGL);
4541     if (SUCCEEDED(hr))
4542     {
4543         DDPIXELFORMAT x8d24 =
4544         {
4545             sizeof(x8d24), DDPF_ZBUFFER, 0,
4546             {24}, {0x00000000}, {0x00ffffff}, {0x00000000}
4547         };
4548         TRACE("Enumerating WINED3DFMT_X8D24_UNORM, dwZBufferBitDepth=24 version\n");
4549         callback(&x8d24, context);
4550     }
4551
4552     TRACE("End of enumeration.\n");
4553
4554     LeaveCriticalSection(&ddraw_cs);
4555     return D3D_OK;
4556 }
4557
4558 static HRESULT WINAPI d3d3_EnumZBufferFormats(IDirect3D3 *iface, REFCLSID device_iid,
4559         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
4560 {
4561     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4562
4563     TRACE("iface %p, device_iid %s, callback %p, context %p.\n",
4564             iface, debugstr_guid(device_iid), callback, context);
4565
4566     return d3d7_EnumZBufferFormats(&This->IDirect3D7_iface, device_iid, callback, context);
4567 }
4568
4569 /*****************************************************************************
4570  * IDirect3D7::EvictManagedTextures
4571  *
4572  * Removes all managed textures (=surfaces with DDSCAPS2_TEXTUREMANAGE or
4573  * DDSCAPS2_D3DTEXTUREMANAGE caps) to be removed from video memory.
4574  *
4575  * Version 3 and 7
4576  *
4577  * Returns:
4578  *  D3D_OK, because it's a stub
4579  *
4580  *****************************************************************************/
4581 static HRESULT WINAPI d3d7_EvictManagedTextures(IDirect3D7 *iface)
4582 {
4583     IDirectDrawImpl *This = impl_from_IDirect3D7(iface);
4584
4585     TRACE("iface %p!\n", iface);
4586
4587     EnterCriticalSection(&ddraw_cs);
4588     if (This->d3d_initialized)
4589         wined3d_device_evict_managed_resources(This->wined3d_device);
4590     LeaveCriticalSection(&ddraw_cs);
4591
4592     return D3D_OK;
4593 }
4594
4595 static HRESULT WINAPI d3d3_EvictManagedTextures(IDirect3D3 *iface)
4596 {
4597     IDirectDrawImpl *This = impl_from_IDirect3D3(iface);
4598
4599     TRACE("iface %p.\n", iface);
4600
4601     return d3d7_EvictManagedTextures(&This->IDirect3D7_iface);
4602 }
4603
4604 /*****************************************************************************
4605  * IDirect3DImpl_GetCaps
4606  *
4607  * This function retrieves the device caps from wined3d
4608  * and converts it into a D3D7 and D3D - D3D3 structure
4609  * This is a helper function called from various places in ddraw
4610  *
4611  * Params:
4612  *  wined3d: The interface to get the caps from
4613  *  desc1: Old D3D <3 structure to fill (needed)
4614  *  desc7: D3D7 device desc structure to fill (needed)
4615  *
4616  * Returns
4617  *  D3D_OK on success, or the return value of IWineD3D::GetCaps
4618  *
4619  *****************************************************************************/
4620 HRESULT IDirect3DImpl_GetCaps(const struct wined3d *wined3d, D3DDEVICEDESC *desc1, D3DDEVICEDESC7 *desc7)
4621 {
4622     WINED3DCAPS wined3d_caps;
4623     HRESULT hr;
4624
4625     TRACE("wined3d %p, desc1 %p, desc7 %p.\n", wined3d, desc1, desc7);
4626
4627     memset(&wined3d_caps, 0, sizeof(wined3d_caps));
4628
4629     EnterCriticalSection(&ddraw_cs);
4630     hr = wined3d_get_device_caps(wined3d, 0, WINED3DDEVTYPE_HAL, &wined3d_caps);
4631     LeaveCriticalSection(&ddraw_cs);
4632     if (FAILED(hr))
4633     {
4634         WARN("Failed to get device caps, hr %#x.\n", hr);
4635         return hr;
4636     }
4637
4638     /* Copy the results into the d3d7 and d3d3 structures */
4639     desc7->dwDevCaps = wined3d_caps.DevCaps;
4640     desc7->dpcLineCaps.dwMiscCaps = wined3d_caps.PrimitiveMiscCaps;
4641     desc7->dpcLineCaps.dwRasterCaps = wined3d_caps.RasterCaps;
4642     desc7->dpcLineCaps.dwZCmpCaps = wined3d_caps.ZCmpCaps;
4643     desc7->dpcLineCaps.dwSrcBlendCaps = wined3d_caps.SrcBlendCaps;
4644     desc7->dpcLineCaps.dwDestBlendCaps = wined3d_caps.DestBlendCaps;
4645     desc7->dpcLineCaps.dwAlphaCmpCaps = wined3d_caps.AlphaCmpCaps;
4646     desc7->dpcLineCaps.dwShadeCaps = wined3d_caps.ShadeCaps;
4647     desc7->dpcLineCaps.dwTextureCaps = wined3d_caps.TextureCaps;
4648     desc7->dpcLineCaps.dwTextureFilterCaps = wined3d_caps.TextureFilterCaps;
4649     desc7->dpcLineCaps.dwTextureAddressCaps = wined3d_caps.TextureAddressCaps;
4650
4651     desc7->dwMaxTextureWidth = wined3d_caps.MaxTextureWidth;
4652     desc7->dwMaxTextureHeight = wined3d_caps.MaxTextureHeight;
4653
4654     desc7->dwMaxTextureRepeat = wined3d_caps.MaxTextureRepeat;
4655     desc7->dwMaxTextureAspectRatio = wined3d_caps.MaxTextureAspectRatio;
4656     desc7->dwMaxAnisotropy = wined3d_caps.MaxAnisotropy;
4657     desc7->dvMaxVertexW = wined3d_caps.MaxVertexW;
4658
4659     desc7->dvGuardBandLeft = wined3d_caps.GuardBandLeft;
4660     desc7->dvGuardBandTop = wined3d_caps.GuardBandTop;
4661     desc7->dvGuardBandRight = wined3d_caps.GuardBandRight;
4662     desc7->dvGuardBandBottom = wined3d_caps.GuardBandBottom;
4663
4664     desc7->dvExtentsAdjust = wined3d_caps.ExtentsAdjust;
4665     desc7->dwStencilCaps = wined3d_caps.StencilCaps;
4666
4667     desc7->dwFVFCaps = wined3d_caps.FVFCaps;
4668     desc7->dwTextureOpCaps = wined3d_caps.TextureOpCaps;
4669
4670     desc7->dwVertexProcessingCaps = wined3d_caps.VertexProcessingCaps;
4671     desc7->dwMaxActiveLights = wined3d_caps.MaxActiveLights;
4672
4673     /* Remove all non-d3d7 caps */
4674     desc7->dwDevCaps &= (
4675         D3DDEVCAPS_FLOATTLVERTEX         | D3DDEVCAPS_SORTINCREASINGZ          | D3DDEVCAPS_SORTDECREASINGZ          |
4676         D3DDEVCAPS_SORTEXACT             | D3DDEVCAPS_EXECUTESYSTEMMEMORY      | D3DDEVCAPS_EXECUTEVIDEOMEMORY       |
4677         D3DDEVCAPS_TLVERTEXSYSTEMMEMORY  | D3DDEVCAPS_TLVERTEXVIDEOMEMORY      | D3DDEVCAPS_TEXTURESYSTEMMEMORY      |
4678         D3DDEVCAPS_TEXTUREVIDEOMEMORY    | D3DDEVCAPS_DRAWPRIMTLVERTEX         | D3DDEVCAPS_CANRENDERAFTERFLIP       |
4679         D3DDEVCAPS_TEXTURENONLOCALVIDMEM | D3DDEVCAPS_DRAWPRIMITIVES2          | D3DDEVCAPS_SEPARATETEXTUREMEMORIES  |
4680         D3DDEVCAPS_DRAWPRIMITIVES2EX     | D3DDEVCAPS_HWTRANSFORMANDLIGHT      | D3DDEVCAPS_CANBLTSYSTONONLOCAL      |
4681         D3DDEVCAPS_HWRASTERIZATION);
4682
4683     desc7->dwStencilCaps &= (
4684         D3DSTENCILCAPS_KEEP              | D3DSTENCILCAPS_ZERO                 | D3DSTENCILCAPS_REPLACE              |
4685         D3DSTENCILCAPS_INCRSAT           | D3DSTENCILCAPS_DECRSAT              | D3DSTENCILCAPS_INVERT               |
4686         D3DSTENCILCAPS_INCR              | D3DSTENCILCAPS_DECR);
4687
4688     /* FVF caps ?*/
4689
4690     desc7->dwTextureOpCaps &= (
4691         D3DTEXOPCAPS_DISABLE             | D3DTEXOPCAPS_SELECTARG1             | D3DTEXOPCAPS_SELECTARG2             |
4692         D3DTEXOPCAPS_MODULATE            | D3DTEXOPCAPS_MODULATE2X             | D3DTEXOPCAPS_MODULATE4X             |
4693         D3DTEXOPCAPS_ADD                 | D3DTEXOPCAPS_ADDSIGNED              | D3DTEXOPCAPS_ADDSIGNED2X            |
4694         D3DTEXOPCAPS_SUBTRACT            | D3DTEXOPCAPS_ADDSMOOTH              | D3DTEXOPCAPS_BLENDTEXTUREALPHA      |
4695         D3DTEXOPCAPS_BLENDFACTORALPHA    | D3DTEXOPCAPS_BLENDTEXTUREALPHAPM    | D3DTEXOPCAPS_BLENDCURRENTALPHA      |
4696         D3DTEXOPCAPS_PREMODULATE         | D3DTEXOPCAPS_MODULATEALPHA_ADDCOLOR | D3DTEXOPCAPS_MODULATECOLOR_ADDALPHA |
4697         D3DTEXOPCAPS_MODULATEINVALPHA_ADDCOLOR | D3DTEXOPCAPS_MODULATEINVCOLOR_ADDALPHA | D3DTEXOPCAPS_BUMPENVMAP    |
4698         D3DTEXOPCAPS_BUMPENVMAPLUMINANCE | D3DTEXOPCAPS_DOTPRODUCT3);
4699
4700     desc7->dwVertexProcessingCaps &= (
4701         D3DVTXPCAPS_TEXGEN               | D3DVTXPCAPS_MATERIALSOURCE7         | D3DVTXPCAPS_VERTEXFOG               |
4702         D3DVTXPCAPS_DIRECTIONALLIGHTS    | D3DVTXPCAPS_POSITIONALLIGHTS        | D3DVTXPCAPS_LOCALVIEWER);
4703
4704     desc7->dpcLineCaps.dwMiscCaps &= (
4705         D3DPMISCCAPS_MASKPLANES          | D3DPMISCCAPS_MASKZ                  | D3DPMISCCAPS_LINEPATTERNREP         |
4706         D3DPMISCCAPS_CONFORMANT          | D3DPMISCCAPS_CULLNONE               | D3DPMISCCAPS_CULLCW                 |
4707         D3DPMISCCAPS_CULLCCW);
4708
4709     desc7->dpcLineCaps.dwRasterCaps &= (
4710         D3DPRASTERCAPS_DITHER            | D3DPRASTERCAPS_ROP2                 | D3DPRASTERCAPS_XOR                  |
4711         D3DPRASTERCAPS_PAT               | D3DPRASTERCAPS_ZTEST                | D3DPRASTERCAPS_SUBPIXEL             |
4712         D3DPRASTERCAPS_SUBPIXELX         | D3DPRASTERCAPS_FOGVERTEX            | D3DPRASTERCAPS_FOGTABLE             |
4713         D3DPRASTERCAPS_STIPPLE           | D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT | D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT |
4714         D3DPRASTERCAPS_ANTIALIASEDGES    | D3DPRASTERCAPS_MIPMAPLODBIAS        | D3DPRASTERCAPS_ZBIAS                |
4715         D3DPRASTERCAPS_ZBUFFERLESSHSR    | D3DPRASTERCAPS_FOGRANGE             | D3DPRASTERCAPS_ANISOTROPY           |
4716         D3DPRASTERCAPS_WBUFFER           | D3DPRASTERCAPS_TRANSLUCENTSORTINDEPENDENT | D3DPRASTERCAPS_WFOG           |
4717         D3DPRASTERCAPS_ZFOG);
4718
4719     desc7->dpcLineCaps.dwZCmpCaps &= (
4720         D3DPCMPCAPS_NEVER                | D3DPCMPCAPS_LESS                    | D3DPCMPCAPS_EQUAL                   |
4721         D3DPCMPCAPS_LESSEQUAL            | D3DPCMPCAPS_GREATER                 | D3DPCMPCAPS_NOTEQUAL                |
4722         D3DPCMPCAPS_GREATEREQUAL         | D3DPCMPCAPS_ALWAYS);
4723
4724     desc7->dpcLineCaps.dwSrcBlendCaps &= (
4725         D3DPBLENDCAPS_ZERO               | D3DPBLENDCAPS_ONE                   | D3DPBLENDCAPS_SRCCOLOR              |
4726         D3DPBLENDCAPS_INVSRCCOLOR        | D3DPBLENDCAPS_SRCALPHA              | D3DPBLENDCAPS_INVSRCALPHA           |
4727         D3DPBLENDCAPS_DESTALPHA          | D3DPBLENDCAPS_INVDESTALPHA          | D3DPBLENDCAPS_DESTCOLOR             |
4728         D3DPBLENDCAPS_INVDESTCOLOR       | D3DPBLENDCAPS_SRCALPHASAT           | D3DPBLENDCAPS_BOTHSRCALPHA          |
4729         D3DPBLENDCAPS_BOTHINVSRCALPHA);
4730
4731     desc7->dpcLineCaps.dwDestBlendCaps &= (
4732         D3DPBLENDCAPS_ZERO               | D3DPBLENDCAPS_ONE                   | D3DPBLENDCAPS_SRCCOLOR              |
4733         D3DPBLENDCAPS_INVSRCCOLOR        | D3DPBLENDCAPS_SRCALPHA              | D3DPBLENDCAPS_INVSRCALPHA           |
4734         D3DPBLENDCAPS_DESTALPHA          | D3DPBLENDCAPS_INVDESTALPHA          | D3DPBLENDCAPS_DESTCOLOR             |
4735         D3DPBLENDCAPS_INVDESTCOLOR       | D3DPBLENDCAPS_SRCALPHASAT           | D3DPBLENDCAPS_BOTHSRCALPHA          |
4736         D3DPBLENDCAPS_BOTHINVSRCALPHA);
4737
4738     desc7->dpcLineCaps.dwAlphaCmpCaps &= (
4739         D3DPCMPCAPS_NEVER                | D3DPCMPCAPS_LESS                    | D3DPCMPCAPS_EQUAL                   |
4740         D3DPCMPCAPS_LESSEQUAL            | D3DPCMPCAPS_GREATER                 | D3DPCMPCAPS_NOTEQUAL                |
4741         D3DPCMPCAPS_GREATEREQUAL         | D3DPCMPCAPS_ALWAYS);
4742
4743     desc7->dpcLineCaps.dwShadeCaps &= (
4744         D3DPSHADECAPS_COLORFLATMONO      | D3DPSHADECAPS_COLORFLATRGB          | D3DPSHADECAPS_COLORGOURAUDMONO      |
4745         D3DPSHADECAPS_COLORGOURAUDRGB    | D3DPSHADECAPS_COLORPHONGMONO        | D3DPSHADECAPS_COLORPHONGRGB         |
4746         D3DPSHADECAPS_SPECULARFLATMONO   | D3DPSHADECAPS_SPECULARFLATRGB       | D3DPSHADECAPS_SPECULARGOURAUDMONO   |
4747         D3DPSHADECAPS_SPECULARGOURAUDRGB | D3DPSHADECAPS_SPECULARPHONGMONO     | D3DPSHADECAPS_SPECULARPHONGRGB      |
4748         D3DPSHADECAPS_ALPHAFLATBLEND     | D3DPSHADECAPS_ALPHAFLATSTIPPLED     | D3DPSHADECAPS_ALPHAGOURAUDBLEND     |
4749         D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED | D3DPSHADECAPS_ALPHAPHONGBLEND     | D3DPSHADECAPS_ALPHAPHONGSTIPPLED    |
4750         D3DPSHADECAPS_FOGFLAT            | D3DPSHADECAPS_FOGGOURAUD            | D3DPSHADECAPS_FOGPHONG);
4751
4752     desc7->dpcLineCaps.dwTextureCaps &= (
4753         D3DPTEXTURECAPS_PERSPECTIVE      | D3DPTEXTURECAPS_POW2                | D3DPTEXTURECAPS_ALPHA               |
4754         D3DPTEXTURECAPS_TRANSPARENCY     | D3DPTEXTURECAPS_BORDER              | D3DPTEXTURECAPS_SQUAREONLY          |
4755         D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE | D3DPTEXTURECAPS_ALPHAPALETTE| D3DPTEXTURECAPS_NONPOW2CONDITIONAL  |
4756         D3DPTEXTURECAPS_PROJECTED        | D3DPTEXTURECAPS_CUBEMAP             | D3DPTEXTURECAPS_COLORKEYBLEND);
4757
4758     desc7->dpcLineCaps.dwTextureFilterCaps &= (
4759         D3DPTFILTERCAPS_NEAREST          | D3DPTFILTERCAPS_LINEAR              | D3DPTFILTERCAPS_MIPNEAREST          |
4760         D3DPTFILTERCAPS_MIPLINEAR        | D3DPTFILTERCAPS_LINEARMIPNEAREST    | D3DPTFILTERCAPS_LINEARMIPLINEAR     |
4761         D3DPTFILTERCAPS_MINFPOINT        | D3DPTFILTERCAPS_MINFLINEAR          | D3DPTFILTERCAPS_MINFANISOTROPIC     |
4762         D3DPTFILTERCAPS_MIPFPOINT        | D3DPTFILTERCAPS_MIPFLINEAR          | D3DPTFILTERCAPS_MAGFPOINT           |
4763         D3DPTFILTERCAPS_MAGFLINEAR       | D3DPTFILTERCAPS_MAGFANISOTROPIC     | D3DPTFILTERCAPS_MAGFAFLATCUBIC      |
4764         D3DPTFILTERCAPS_MAGFGAUSSIANCUBIC);
4765
4766     desc7->dpcLineCaps.dwTextureBlendCaps &= (
4767         D3DPTBLENDCAPS_DECAL             | D3DPTBLENDCAPS_MODULATE             | D3DPTBLENDCAPS_DECALALPHA           |
4768         D3DPTBLENDCAPS_MODULATEALPHA     | D3DPTBLENDCAPS_DECALMASK            | D3DPTBLENDCAPS_MODULATEMASK         |
4769         D3DPTBLENDCAPS_COPY              | D3DPTBLENDCAPS_ADD);
4770
4771     desc7->dpcLineCaps.dwTextureAddressCaps &= (
4772         D3DPTADDRESSCAPS_WRAP            | D3DPTADDRESSCAPS_MIRROR             | D3DPTADDRESSCAPS_CLAMP              |
4773         D3DPTADDRESSCAPS_BORDER          | D3DPTADDRESSCAPS_INDEPENDENTUV);
4774
4775     if (!(desc7->dpcLineCaps.dwTextureCaps & D3DPTEXTURECAPS_POW2))
4776     {
4777         /* DirectX7 always has the np2 flag set, no matter what the card
4778          * supports. Some old games (Rollcage) check the caps incorrectly.
4779          * If wined3d supports nonpow2 textures it also has np2 conditional
4780          * support. */
4781         desc7->dpcLineCaps.dwTextureCaps |= D3DPTEXTURECAPS_POW2 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL;
4782     }
4783
4784     /* Fill the missing members, and do some fixup */
4785     desc7->dpcLineCaps.dwSize = sizeof(desc7->dpcLineCaps);
4786     desc7->dpcLineCaps.dwTextureBlendCaps = D3DPTBLENDCAPS_ADD | D3DPTBLENDCAPS_MODULATEMASK |
4787                                             D3DPTBLENDCAPS_COPY | D3DPTBLENDCAPS_DECAL |
4788                                             D3DPTBLENDCAPS_DECALALPHA | D3DPTBLENDCAPS_DECALMASK |
4789                                             D3DPTBLENDCAPS_MODULATE | D3DPTBLENDCAPS_MODULATEALPHA;
4790     desc7->dpcLineCaps.dwStippleWidth = 32;
4791     desc7->dpcLineCaps.dwStippleHeight = 32;
4792     /* Use the same for the TriCaps */
4793     desc7->dpcTriCaps = desc7->dpcLineCaps;
4794
4795     desc7->dwDeviceRenderBitDepth = DDBD_16 | DDBD_24 | DDBD_32;
4796     desc7->dwDeviceZBufferBitDepth = DDBD_16 | DDBD_24;
4797     desc7->dwMinTextureWidth = 1;
4798     desc7->dwMinTextureHeight = 1;
4799
4800     /* Convert DWORDs safely to WORDs */
4801     if (wined3d_caps.MaxTextureBlendStages > 0xffff) desc7->wMaxTextureBlendStages = 0xffff;
4802     else desc7->wMaxTextureBlendStages = (WORD)wined3d_caps.MaxTextureBlendStages;
4803     if (wined3d_caps.MaxSimultaneousTextures > 0xffff) desc7->wMaxSimultaneousTextures = 0xffff;
4804     else desc7->wMaxSimultaneousTextures = (WORD)wined3d_caps.MaxSimultaneousTextures;
4805
4806     if (wined3d_caps.MaxUserClipPlanes > 0xffff) desc7->wMaxUserClipPlanes = 0xffff;
4807     else desc7->wMaxUserClipPlanes = (WORD)wined3d_caps.MaxUserClipPlanes;
4808     if (wined3d_caps.MaxVertexBlendMatrices > 0xffff) desc7->wMaxVertexBlendMatrices = 0xffff;
4809     else desc7->wMaxVertexBlendMatrices = (WORD)wined3d_caps.MaxVertexBlendMatrices;
4810
4811     desc7->deviceGUID = IID_IDirect3DTnLHalDevice;
4812
4813     desc7->dwReserved1 = 0;
4814     desc7->dwReserved2 = 0;
4815     desc7->dwReserved3 = 0;
4816     desc7->dwReserved4 = 0;
4817
4818     /* Fill the old structure */
4819     memset(desc1, 0, sizeof(*desc1));
4820     desc1->dwSize = sizeof(D3DDEVICEDESC);
4821     desc1->dwFlags = D3DDD_COLORMODEL
4822             | D3DDD_DEVCAPS
4823             | D3DDD_TRANSFORMCAPS
4824             | D3DDD_BCLIPPING
4825             | D3DDD_LIGHTINGCAPS
4826             | D3DDD_LINECAPS
4827             | D3DDD_TRICAPS
4828             | D3DDD_DEVICERENDERBITDEPTH
4829             | D3DDD_DEVICEZBUFFERBITDEPTH
4830             | D3DDD_MAXBUFFERSIZE
4831             | D3DDD_MAXVERTEXCOUNT;
4832
4833     desc1->dcmColorModel = D3DCOLOR_RGB;
4834     desc1->dwDevCaps = desc7->dwDevCaps;
4835     desc1->dtcTransformCaps.dwSize = sizeof(D3DTRANSFORMCAPS);
4836     desc1->dtcTransformCaps.dwCaps = D3DTRANSFORMCAPS_CLIP;
4837     desc1->bClipping = TRUE;
4838     desc1->dlcLightingCaps.dwSize = sizeof(D3DLIGHTINGCAPS);
4839     desc1->dlcLightingCaps.dwCaps = D3DLIGHTCAPS_DIRECTIONAL
4840             | D3DLIGHTCAPS_PARALLELPOINT
4841             | D3DLIGHTCAPS_POINT
4842             | D3DLIGHTCAPS_SPOT;
4843
4844     desc1->dlcLightingCaps.dwLightingModel = D3DLIGHTINGMODEL_RGB;
4845     desc1->dlcLightingCaps.dwNumLights = desc7->dwMaxActiveLights;
4846
4847     desc1->dpcLineCaps.dwSize = sizeof(D3DPRIMCAPS);
4848     desc1->dpcLineCaps.dwMiscCaps = desc7->dpcLineCaps.dwMiscCaps;
4849     desc1->dpcLineCaps.dwRasterCaps = desc7->dpcLineCaps.dwRasterCaps;
4850     desc1->dpcLineCaps.dwZCmpCaps = desc7->dpcLineCaps.dwZCmpCaps;
4851     desc1->dpcLineCaps.dwSrcBlendCaps = desc7->dpcLineCaps.dwSrcBlendCaps;
4852     desc1->dpcLineCaps.dwDestBlendCaps = desc7->dpcLineCaps.dwDestBlendCaps;
4853     desc1->dpcLineCaps.dwShadeCaps = desc7->dpcLineCaps.dwShadeCaps;
4854     desc1->dpcLineCaps.dwTextureCaps = desc7->dpcLineCaps.dwTextureCaps;
4855     desc1->dpcLineCaps.dwTextureFilterCaps = desc7->dpcLineCaps.dwTextureFilterCaps;
4856     desc1->dpcLineCaps.dwTextureBlendCaps = desc7->dpcLineCaps.dwTextureBlendCaps;
4857     desc1->dpcLineCaps.dwTextureAddressCaps = desc7->dpcLineCaps.dwTextureAddressCaps;
4858     desc1->dpcLineCaps.dwStippleWidth = desc7->dpcLineCaps.dwStippleWidth;
4859     desc1->dpcLineCaps.dwAlphaCmpCaps = desc7->dpcLineCaps.dwAlphaCmpCaps;
4860
4861     desc1->dpcTriCaps.dwSize = sizeof(D3DPRIMCAPS);
4862     desc1->dpcTriCaps.dwMiscCaps = desc7->dpcTriCaps.dwMiscCaps;
4863     desc1->dpcTriCaps.dwRasterCaps = desc7->dpcTriCaps.dwRasterCaps;
4864     desc1->dpcTriCaps.dwZCmpCaps = desc7->dpcTriCaps.dwZCmpCaps;
4865     desc1->dpcTriCaps.dwSrcBlendCaps = desc7->dpcTriCaps.dwSrcBlendCaps;
4866     desc1->dpcTriCaps.dwDestBlendCaps = desc7->dpcTriCaps.dwDestBlendCaps;
4867     desc1->dpcTriCaps.dwShadeCaps = desc7->dpcTriCaps.dwShadeCaps;
4868     desc1->dpcTriCaps.dwTextureCaps = desc7->dpcTriCaps.dwTextureCaps;
4869     desc1->dpcTriCaps.dwTextureFilterCaps = desc7->dpcTriCaps.dwTextureFilterCaps;
4870     desc1->dpcTriCaps.dwTextureBlendCaps = desc7->dpcTriCaps.dwTextureBlendCaps;
4871     desc1->dpcTriCaps.dwTextureAddressCaps = desc7->dpcTriCaps.dwTextureAddressCaps;
4872     desc1->dpcTriCaps.dwStippleWidth = desc7->dpcTriCaps.dwStippleWidth;
4873     desc1->dpcTriCaps.dwAlphaCmpCaps = desc7->dpcTriCaps.dwAlphaCmpCaps;
4874
4875     desc1->dwDeviceRenderBitDepth = desc7->dwDeviceRenderBitDepth;
4876     desc1->dwDeviceZBufferBitDepth = desc7->dwDeviceZBufferBitDepth;
4877     desc1->dwMaxBufferSize = 0;
4878     desc1->dwMaxVertexCount = 65536;
4879     desc1->dwMinTextureWidth  = desc7->dwMinTextureWidth;
4880     desc1->dwMinTextureHeight = desc7->dwMinTextureHeight;
4881     desc1->dwMaxTextureWidth  = desc7->dwMaxTextureWidth;
4882     desc1->dwMaxTextureHeight = desc7->dwMaxTextureHeight;
4883     desc1->dwMinStippleWidth  = 1;
4884     desc1->dwMinStippleHeight = 1;
4885     desc1->dwMaxStippleWidth  = 32;
4886     desc1->dwMaxStippleHeight = 32;
4887     desc1->dwMaxTextureRepeat = desc7->dwMaxTextureRepeat;
4888     desc1->dwMaxTextureAspectRatio = desc7->dwMaxTextureAspectRatio;
4889     desc1->dwMaxAnisotropy = desc7->dwMaxAnisotropy;
4890     desc1->dvGuardBandLeft = desc7->dvGuardBandLeft;
4891     desc1->dvGuardBandRight = desc7->dvGuardBandRight;
4892     desc1->dvGuardBandTop = desc7->dvGuardBandTop;
4893     desc1->dvGuardBandBottom = desc7->dvGuardBandBottom;
4894     desc1->dvExtentsAdjust = desc7->dvExtentsAdjust;
4895     desc1->dwStencilCaps = desc7->dwStencilCaps;
4896     desc1->dwFVFCaps = desc7->dwFVFCaps;
4897     desc1->dwTextureOpCaps = desc7->dwTextureOpCaps;
4898     desc1->wMaxTextureBlendStages = desc7->wMaxTextureBlendStages;
4899     desc1->wMaxSimultaneousTextures = desc7->wMaxSimultaneousTextures;
4900
4901     return DD_OK;
4902 }
4903
4904 /*****************************************************************************
4905  * IDirectDraw7 VTable
4906  *****************************************************************************/
4907 static const struct IDirectDraw7Vtbl ddraw7_vtbl =
4908 {
4909     /* IUnknown */
4910     ddraw7_QueryInterface,
4911     ddraw7_AddRef,
4912     ddraw7_Release,
4913     /* IDirectDraw */
4914     ddraw7_Compact,
4915     ddraw7_CreateClipper,
4916     ddraw7_CreatePalette,
4917     ddraw7_CreateSurface,
4918     ddraw7_DuplicateSurface,
4919     ddraw7_EnumDisplayModes,
4920     ddraw7_EnumSurfaces,
4921     ddraw7_FlipToGDISurface,
4922     ddraw7_GetCaps,
4923     ddraw7_GetDisplayMode,
4924     ddraw7_GetFourCCCodes,
4925     ddraw7_GetGDISurface,
4926     ddraw7_GetMonitorFrequency,
4927     ddraw7_GetScanLine,
4928     ddraw7_GetVerticalBlankStatus,
4929     ddraw7_Initialize,
4930     ddraw7_RestoreDisplayMode,
4931     ddraw7_SetCooperativeLevel,
4932     ddraw7_SetDisplayMode,
4933     ddraw7_WaitForVerticalBlank,
4934     /* IDirectDraw2 */
4935     ddraw7_GetAvailableVidMem,
4936     /* IDirectDraw3 */
4937     ddraw7_GetSurfaceFromDC,
4938     /* IDirectDraw4 */
4939     ddraw7_RestoreAllSurfaces,
4940     ddraw7_TestCooperativeLevel,
4941     ddraw7_GetDeviceIdentifier,
4942     /* IDirectDraw7 */
4943     ddraw7_StartModeTest,
4944     ddraw7_EvaluateMode
4945 };
4946
4947 static const struct IDirectDraw4Vtbl ddraw4_vtbl =
4948 {
4949     /* IUnknown */
4950     ddraw4_QueryInterface,
4951     ddraw4_AddRef,
4952     ddraw4_Release,
4953     /* IDirectDraw */
4954     ddraw4_Compact,
4955     ddraw4_CreateClipper,
4956     ddraw4_CreatePalette,
4957     ddraw4_CreateSurface,
4958     ddraw4_DuplicateSurface,
4959     ddraw4_EnumDisplayModes,
4960     ddraw4_EnumSurfaces,
4961     ddraw4_FlipToGDISurface,
4962     ddraw4_GetCaps,
4963     ddraw4_GetDisplayMode,
4964     ddraw4_GetFourCCCodes,
4965     ddraw4_GetGDISurface,
4966     ddraw4_GetMonitorFrequency,
4967     ddraw4_GetScanLine,
4968     ddraw4_GetVerticalBlankStatus,
4969     ddraw4_Initialize,
4970     ddraw4_RestoreDisplayMode,
4971     ddraw4_SetCooperativeLevel,
4972     ddraw4_SetDisplayMode,
4973     ddraw4_WaitForVerticalBlank,
4974     /* IDirectDraw2 */
4975     ddraw4_GetAvailableVidMem,
4976     /* IDirectDraw3 */
4977     ddraw4_GetSurfaceFromDC,
4978     /* IDirectDraw4 */
4979     ddraw4_RestoreAllSurfaces,
4980     ddraw4_TestCooperativeLevel,
4981     ddraw4_GetDeviceIdentifier,
4982 };
4983
4984 static const struct IDirectDraw2Vtbl ddraw2_vtbl =
4985 {
4986     /* IUnknown */
4987     ddraw2_QueryInterface,
4988     ddraw2_AddRef,
4989     ddraw2_Release,
4990     /* IDirectDraw */
4991     ddraw2_Compact,
4992     ddraw2_CreateClipper,
4993     ddraw2_CreatePalette,
4994     ddraw2_CreateSurface,
4995     ddraw2_DuplicateSurface,
4996     ddraw2_EnumDisplayModes,
4997     ddraw2_EnumSurfaces,
4998     ddraw2_FlipToGDISurface,
4999     ddraw2_GetCaps,
5000     ddraw2_GetDisplayMode,
5001     ddraw2_GetFourCCCodes,
5002     ddraw2_GetGDISurface,
5003     ddraw2_GetMonitorFrequency,
5004     ddraw2_GetScanLine,
5005     ddraw2_GetVerticalBlankStatus,
5006     ddraw2_Initialize,
5007     ddraw2_RestoreDisplayMode,
5008     ddraw2_SetCooperativeLevel,
5009     ddraw2_SetDisplayMode,
5010     ddraw2_WaitForVerticalBlank,
5011     /* IDirectDraw2 */
5012     ddraw2_GetAvailableVidMem,
5013 };
5014
5015 static const struct IDirectDrawVtbl ddraw1_vtbl =
5016 {
5017     /* IUnknown */
5018     ddraw1_QueryInterface,
5019     ddraw1_AddRef,
5020     ddraw1_Release,
5021     /* IDirectDraw */
5022     ddraw1_Compact,
5023     ddraw1_CreateClipper,
5024     ddraw1_CreatePalette,
5025     ddraw1_CreateSurface,
5026     ddraw1_DuplicateSurface,
5027     ddraw1_EnumDisplayModes,
5028     ddraw1_EnumSurfaces,
5029     ddraw1_FlipToGDISurface,
5030     ddraw1_GetCaps,
5031     ddraw1_GetDisplayMode,
5032     ddraw1_GetFourCCCodes,
5033     ddraw1_GetGDISurface,
5034     ddraw1_GetMonitorFrequency,
5035     ddraw1_GetScanLine,
5036     ddraw1_GetVerticalBlankStatus,
5037     ddraw1_Initialize,
5038     ddraw1_RestoreDisplayMode,
5039     ddraw1_SetCooperativeLevel,
5040     ddraw1_SetDisplayMode,
5041     ddraw1_WaitForVerticalBlank,
5042 };
5043
5044 static const struct IDirect3D7Vtbl d3d7_vtbl =
5045 {
5046     /* IUnknown methods */
5047     d3d7_QueryInterface,
5048     d3d7_AddRef,
5049     d3d7_Release,
5050     /* IDirect3D7 methods */
5051     d3d7_EnumDevices,
5052     d3d7_CreateDevice,
5053     d3d7_CreateVertexBuffer,
5054     d3d7_EnumZBufferFormats,
5055     d3d7_EvictManagedTextures
5056 };
5057
5058 static const struct IDirect3D3Vtbl d3d3_vtbl =
5059 {
5060     /* IUnknown methods */
5061     d3d3_QueryInterface,
5062     d3d3_AddRef,
5063     d3d3_Release,
5064     /* IDirect3D3 methods */
5065     d3d3_EnumDevices,
5066     d3d3_CreateLight,
5067     d3d3_CreateMaterial,
5068     d3d3_CreateViewport,
5069     d3d3_FindDevice,
5070     d3d3_CreateDevice,
5071     d3d3_CreateVertexBuffer,
5072     d3d3_EnumZBufferFormats,
5073     d3d3_EvictManagedTextures
5074 };
5075
5076 static const struct IDirect3D2Vtbl d3d2_vtbl =
5077 {
5078     /* IUnknown methods */
5079     d3d2_QueryInterface,
5080     d3d2_AddRef,
5081     d3d2_Release,
5082     /* IDirect3D2 methods */
5083     d3d2_EnumDevices,
5084     d3d2_CreateLight,
5085     d3d2_CreateMaterial,
5086     d3d2_CreateViewport,
5087     d3d2_FindDevice,
5088     d3d2_CreateDevice
5089 };
5090
5091 static const struct IDirect3DVtbl d3d1_vtbl =
5092 {
5093     /* IUnknown methods */
5094     d3d1_QueryInterface,
5095     d3d1_AddRef,
5096     d3d1_Release,
5097     /* IDirect3D methods */
5098     d3d1_Initialize,
5099     d3d1_EnumDevices,
5100     d3d1_CreateLight,
5101     d3d1_CreateMaterial,
5102     d3d1_CreateViewport,
5103     d3d1_FindDevice
5104 };
5105
5106 /*****************************************************************************
5107  * ddraw_find_decl
5108  *
5109  * Finds the WineD3D vertex declaration for a specific fvf, and creates one
5110  * if none was found.
5111  *
5112  * This function is in ddraw.c and the DDraw object space because D3D7
5113  * vertex buffers are created using the IDirect3D interface to the ddraw
5114  * object, so they can be valid across D3D devices(theoretically. The ddraw
5115  * object also owns the wined3d device
5116  *
5117  * Parameters:
5118  *  This: Device
5119  *  fvf: Fvf to find the decl for
5120  *
5121  * Returns:
5122  *  NULL in case of an error, the vertex declaration for the FVF otherwise.
5123  *
5124  *****************************************************************************/
5125 struct wined3d_vertex_declaration *ddraw_find_decl(IDirectDrawImpl *This, DWORD fvf)
5126 {
5127     struct wined3d_vertex_declaration *pDecl = NULL;
5128     HRESULT hr;
5129     int p, low, high; /* deliberately signed */
5130     struct FvfToDecl *convertedDecls = This->decls;
5131
5132     TRACE("Searching for declaration for fvf %08x... ", fvf);
5133
5134     low = 0;
5135     high = This->numConvertedDecls - 1;
5136     while(low <= high) {
5137         p = (low + high) >> 1;
5138         TRACE("%d ", p);
5139         if(convertedDecls[p].fvf == fvf) {
5140             TRACE("found %p\n", convertedDecls[p].decl);
5141             return convertedDecls[p].decl;
5142         } else if(convertedDecls[p].fvf < fvf) {
5143             low = p + 1;
5144         } else {
5145             high = p - 1;
5146         }
5147     }
5148     TRACE("not found. Creating and inserting at position %d.\n", low);
5149
5150     hr = wined3d_vertex_declaration_create_from_fvf(This->wined3d_device,
5151             fvf, This, &ddraw_null_wined3d_parent_ops, &pDecl);
5152     if (hr != S_OK) return NULL;
5153
5154     if(This->declArraySize == This->numConvertedDecls) {
5155         int grow = max(This->declArraySize / 2, 8);
5156         convertedDecls = HeapReAlloc(GetProcessHeap(), 0, convertedDecls,
5157                                      sizeof(convertedDecls[0]) * (This->numConvertedDecls + grow));
5158         if (!convertedDecls)
5159         {
5160             wined3d_vertex_declaration_decref(pDecl);
5161             return NULL;
5162         }
5163         This->decls = convertedDecls;
5164         This->declArraySize += grow;
5165     }
5166
5167     memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low));
5168     convertedDecls[low].decl = pDecl;
5169     convertedDecls[low].fvf = fvf;
5170     This->numConvertedDecls++;
5171
5172     TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
5173     return pDecl;
5174 }
5175
5176 static inline struct IDirectDrawImpl *ddraw_from_device_parent(struct wined3d_device_parent *device_parent)
5177 {
5178     return CONTAINING_RECORD(device_parent, struct IDirectDrawImpl, device_parent);
5179 }
5180
5181 static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
5182         struct wined3d_device *device)
5183 {
5184     TRACE("device_parent %p, device %p.\n", device_parent, device);
5185 }
5186
5187 static HRESULT CDECL device_parent_create_surface(struct wined3d_device_parent *device_parent,
5188         void *container_parent, UINT width, UINT height, enum wined3d_format_id format, DWORD usage,
5189         WINED3DPOOL pool, UINT level, WINED3DCUBEMAP_FACES face, struct wined3d_surface **surface)
5190 {
5191     struct IDirectDrawImpl *ddraw = ddraw_from_device_parent(device_parent);
5192     IDirectDrawSurfaceImpl *surf = NULL;
5193     UINT i = 0;
5194     DDSCAPS2 searchcaps = ddraw->tex_root->surface_desc.ddsCaps;
5195
5196     TRACE("device_parent %p, container_parent %p, width %u, height %u, format %#x, usage %#x,\n"
5197             "\tpool %#x, level %u, face %u, surface %p.\n",
5198             device_parent, container_parent, width, height, format, usage, pool, level, face, surface);
5199
5200     searchcaps.dwCaps2 &= ~DDSCAPS2_CUBEMAP_ALLFACES;
5201     switch(face)
5202     {
5203         case WINED3DCUBEMAP_FACE_POSITIVE_X:
5204             TRACE("Asked for positive x\n");
5205             if (searchcaps.dwCaps2 & DDSCAPS2_CUBEMAP)
5206             {
5207                 searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEX;
5208             }
5209             surf = ddraw->tex_root; break;
5210         case WINED3DCUBEMAP_FACE_NEGATIVE_X:
5211             TRACE("Asked for negative x\n");
5212             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEX; break;
5213         case WINED3DCUBEMAP_FACE_POSITIVE_Y:
5214             TRACE("Asked for positive y\n");
5215             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEY; break;
5216         case WINED3DCUBEMAP_FACE_NEGATIVE_Y:
5217             TRACE("Asked for negative y\n");
5218             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEY; break;
5219         case WINED3DCUBEMAP_FACE_POSITIVE_Z:
5220             TRACE("Asked for positive z\n");
5221             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_POSITIVEZ; break;
5222         case WINED3DCUBEMAP_FACE_NEGATIVE_Z:
5223             TRACE("Asked for negative z\n");
5224             searchcaps.dwCaps2 |= DDSCAPS2_CUBEMAP_NEGATIVEZ; break;
5225         default: {ERR("Unexpected cube face\n");} /* Stupid compiler */
5226     }
5227
5228     if (!surf)
5229     {
5230         IDirectDrawSurface7 *attached;
5231         IDirectDrawSurface7_GetAttachedSurface(&ddraw->tex_root->IDirectDrawSurface7_iface, &searchcaps, &attached);
5232         surf = unsafe_impl_from_IDirectDrawSurface7(attached);
5233         IDirectDrawSurface7_Release(attached);
5234     }
5235     if (!surf) ERR("root search surface not found\n");
5236
5237     /* Find the wanted mipmap. There are enough mipmaps in the chain */
5238     while (i < level)
5239     {
5240         IDirectDrawSurface7 *attached;
5241         IDirectDrawSurface7_GetAttachedSurface(&surf->IDirectDrawSurface7_iface, &searchcaps, &attached);
5242         if(!attached) ERR("Surface not found\n");
5243         surf = impl_from_IDirectDrawSurface7(attached);
5244         IDirectDrawSurface7_Release(attached);
5245         ++i;
5246     }
5247
5248     /* Return the surface */
5249     *surface = surf->wined3d_surface;
5250     wined3d_surface_incref(*surface);
5251
5252     TRACE("Returning wineD3DSurface %p, it belongs to surface %p\n", *surface, surf);
5253
5254     return D3D_OK;
5255 }
5256
5257 static void STDMETHODCALLTYPE ddraw_frontbuffer_destroyed(void *parent)
5258 {
5259     struct IDirectDrawImpl *ddraw = parent;
5260     ddraw->wined3d_frontbuffer = NULL;
5261 }
5262
5263 static const struct wined3d_parent_ops ddraw_frontbuffer_parent_ops =
5264 {
5265     ddraw_frontbuffer_destroyed,
5266 };
5267
5268 static HRESULT CDECL device_parent_create_rendertarget(struct wined3d_device_parent *device_parent,
5269         void *container_parent, UINT width, UINT height, enum wined3d_format_id format,
5270         WINED3DMULTISAMPLE_TYPE multisample_type, DWORD multisample_quality, BOOL lockable,
5271         struct wined3d_surface **surface)
5272 {
5273     struct IDirectDrawImpl *ddraw = ddraw_from_device_parent(device_parent);
5274     HRESULT hr;
5275
5276     TRACE("device_parent %p, container_parent %p, width %u, height %u, format %#x, multisample_type %#x,\n"
5277             "\tmultisample_quality %u, lockable %u, surface %p.\n",
5278             device_parent, container_parent, width, height, format, multisample_type,
5279             multisample_quality, lockable, surface);
5280
5281     if (ddraw->wined3d_frontbuffer)
5282     {
5283         ERR("Frontbuffer already created.\n");
5284         return E_FAIL;
5285     }
5286
5287     hr = wined3d_surface_create(ddraw->wined3d_device, width, height, format, lockable, FALSE, 0,
5288             WINED3DUSAGE_RENDERTARGET, WINED3DPOOL_DEFAULT, multisample_type, multisample_quality,
5289             DefaultSurfaceType, ddraw, &ddraw_frontbuffer_parent_ops, surface);
5290     if (SUCCEEDED(hr))
5291         ddraw->wined3d_frontbuffer = *surface;
5292
5293     return hr;
5294 }
5295
5296 static HRESULT CDECL device_parent_create_depth_stencil(struct wined3d_device_parent *device_parent,
5297         UINT width, UINT height, enum wined3d_format_id format, WINED3DMULTISAMPLE_TYPE multisample_type,
5298         DWORD multisample_quality, BOOL discard, struct wined3d_surface **surface)
5299 {
5300     ERR("DirectDraw doesn't have and shouldn't try creating implicit depth buffers.\n");
5301     return E_NOTIMPL;
5302 }
5303
5304 static HRESULT CDECL device_parent_create_volume(struct wined3d_device_parent *device_parent,
5305         void *container_parent, UINT width, UINT height, UINT depth, enum wined3d_format_id format,
5306         WINED3DPOOL pool, DWORD usage, struct wined3d_volume **volume)
5307 {
5308     TRACE("device_parent %p, container_parent %p, width %u, height %u, depth %u, "
5309             "format %#x, pool %#x, usage %#x, volume %p.\n",
5310             device_parent, container_parent, width, height, depth,
5311             format, pool, usage, volume);
5312
5313     ERR("Not implemented!\n");
5314
5315     return E_NOTIMPL;
5316 }
5317
5318 static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
5319         WINED3DPRESENT_PARAMETERS *present_parameters, struct wined3d_swapchain **swapchain)
5320 {
5321     struct IDirectDrawImpl *ddraw = ddraw_from_device_parent(device_parent);
5322     IDirectDrawSurfaceImpl *iterator;
5323     HRESULT hr;
5324
5325     TRACE("device_parent %p, present_parameters %p, swapchain %p.\n", device_parent, present_parameters, swapchain);
5326
5327     hr = wined3d_swapchain_create(ddraw->wined3d_device, present_parameters,
5328             DefaultSurfaceType, NULL, &ddraw_null_wined3d_parent_ops, swapchain);
5329     if (FAILED(hr))
5330     {
5331         WARN("Failed to create swapchain, hr %#x.\n", hr);
5332         *swapchain = NULL;
5333         return hr;
5334     }
5335
5336     ddraw->d3d_target->wined3d_swapchain = *swapchain;
5337     iterator = ddraw->d3d_target->complex_array[0];
5338     while (iterator)
5339     {
5340         iterator->wined3d_swapchain = *swapchain;
5341         iterator = iterator->complex_array[0];
5342     }
5343
5344     return hr;
5345 }
5346
5347 static const struct wined3d_device_parent_ops ddraw_wined3d_device_parent_ops =
5348 {
5349     device_parent_wined3d_device_created,
5350     device_parent_create_surface,
5351     device_parent_create_rendertarget,
5352     device_parent_create_depth_stencil,
5353     device_parent_create_volume,
5354     device_parent_create_swapchain,
5355 };
5356
5357 HRESULT ddraw_init(IDirectDrawImpl *ddraw, WINED3DDEVTYPE device_type)
5358 {
5359     HRESULT hr;
5360     HDC hDC;
5361
5362     ddraw->IDirectDraw7_iface.lpVtbl = &ddraw7_vtbl;
5363     ddraw->IDirectDraw_iface.lpVtbl = &ddraw1_vtbl;
5364     ddraw->IDirectDraw2_iface.lpVtbl = &ddraw2_vtbl;
5365     ddraw->IDirectDraw4_iface.lpVtbl = &ddraw4_vtbl;
5366     ddraw->IDirect3D_iface.lpVtbl = &d3d1_vtbl;
5367     ddraw->IDirect3D2_iface.lpVtbl = &d3d2_vtbl;
5368     ddraw->IDirect3D3_iface.lpVtbl = &d3d3_vtbl;
5369     ddraw->IDirect3D7_iface.lpVtbl = &d3d7_vtbl;
5370     ddraw->device_parent.ops = &ddraw_wined3d_device_parent_ops;
5371     ddraw->numIfaces = 1;
5372     ddraw->ref7 = 1;
5373
5374     /* Get the current screen settings. */
5375     hDC = GetDC(0);
5376     ddraw->orig_bpp = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
5377     ReleaseDC(0, hDC);
5378     ddraw->orig_width = GetSystemMetrics(SM_CXSCREEN);
5379     ddraw->orig_height = GetSystemMetrics(SM_CYSCREEN);
5380
5381     ddraw->wineD3D = wined3d_create(7, WINED3D_PALETTE_PER_SURFACE | WINED3D_LEGACY_DEPTH_BIAS,
5382             &ddraw->IDirectDraw7_iface);
5383     if (!ddraw->wineD3D)
5384     {
5385         WARN("Failed to create a wined3d object.\n");
5386         return E_OUTOFMEMORY;
5387     }
5388
5389     hr = wined3d_device_create(ddraw->wineD3D, WINED3DADAPTER_DEFAULT, device_type,
5390             NULL, 0, 8, &ddraw->device_parent, &ddraw->wined3d_device);
5391     if (FAILED(hr))
5392     {
5393         WARN("Failed to create a wined3d device, hr %#x.\n", hr);
5394         wined3d_decref(ddraw->wineD3D);
5395         return hr;
5396     }
5397
5398     list_init(&ddraw->surface_list);
5399
5400     return DD_OK;
5401 }