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