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