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