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