xref: /reactos/dll/directx/wine/ddraw/ddraw.c (revision b3a5eeb1)
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     IDirectDrawSurface7 *gdi_surface;
2097     struct ddraw_surface *gdi_impl;
2098     HRESULT hr;
2099 
2100     TRACE("iface %p.\n", iface);
2101 
2102     wined3d_mutex_lock();
2103 
2104     if (FAILED(hr = IDirectDraw7_GetGDISurface(iface, &gdi_surface)))
2105     {
2106         WARN("Failed to retrieve GDI surface, hr %#x.\n", hr);
2107         wined3d_mutex_unlock();
2108         return hr;
2109     }
2110 
2111     gdi_impl = impl_from_IDirectDrawSurface7(gdi_surface);
2112     if (gdi_impl->surface_desc.ddsCaps.dwCaps & DDSCAPS_FRONTBUFFER)
2113         hr = DD_OK;
2114     else
2115         hr = IDirectDrawSurface7_Flip(&ddraw->primary->IDirectDrawSurface7_iface, gdi_surface, DDFLIP_WAIT);
2116     IDirectDrawSurface7_Release(gdi_surface);
2117 
2118     wined3d_mutex_unlock();
2119 
2120     return hr;
2121 }
2122 
2123 static HRESULT WINAPI ddraw4_FlipToGDISurface(IDirectDraw4 *iface)
2124 {
2125     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2126 
2127     TRACE("iface %p.\n", iface);
2128 
2129     return ddraw7_FlipToGDISurface(&ddraw->IDirectDraw7_iface);
2130 }
2131 
2132 static HRESULT WINAPI ddraw2_FlipToGDISurface(IDirectDraw2 *iface)
2133 {
2134     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2135 
2136     TRACE("iface %p.\n", iface);
2137 
2138     return ddraw7_FlipToGDISurface(&ddraw->IDirectDraw7_iface);
2139 }
2140 
2141 static HRESULT WINAPI ddraw1_FlipToGDISurface(IDirectDraw *iface)
2142 {
2143     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2144 
2145     TRACE("iface %p.\n", iface);
2146 
2147     return ddraw7_FlipToGDISurface(&ddraw->IDirectDraw7_iface);
2148 }
2149 
2150 /*****************************************************************************
2151  * IDirectDraw7::WaitForVerticalBlank
2152  *
2153  * This method allows applications to get in sync with the vertical blank
2154  * interval.
2155  * The wormhole demo in the DirectX 7 sdk uses this call, and it doesn't
2156  * redraw the screen, most likely because of this stub
2157  *
2158  * Parameters:
2159  *  Flags: one of DDWAITVB_BLOCKBEGIN, DDWAITVB_BLOCKBEGINEVENT
2160  *         or DDWAITVB_BLOCKEND
2161  *  h: Not used, according to MSDN
2162  *
2163  * Returns:
2164  *  Always returns DD_OK
2165  *
2166  *****************************************************************************/
2167 static HRESULT WINAPI ddraw7_WaitForVerticalBlank(IDirectDraw7 *iface, DWORD Flags, HANDLE event)
2168 {
2169     static BOOL hide;
2170 
2171     TRACE("iface %p, flags %#x, event %p.\n", iface, Flags, event);
2172 
2173     /* This function is called often, so print the fixme only once */
2174     if(!hide)
2175     {
2176         FIXME("iface %p, flags %#x, event %p stub!\n", iface, Flags, event);
2177         hide = TRUE;
2178     }
2179 
2180     /* MSDN says DDWAITVB_BLOCKBEGINEVENT is not supported */
2181     if(Flags & DDWAITVB_BLOCKBEGINEVENT)
2182         return DDERR_UNSUPPORTED; /* unchecked */
2183 
2184     return DD_OK;
2185 }
2186 
2187 static HRESULT WINAPI ddraw4_WaitForVerticalBlank(IDirectDraw4 *iface, DWORD flags, HANDLE event)
2188 {
2189     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2190 
2191     TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
2192 
2193     return ddraw7_WaitForVerticalBlank(&ddraw->IDirectDraw7_iface, flags, event);
2194 }
2195 
2196 static HRESULT WINAPI ddraw2_WaitForVerticalBlank(IDirectDraw2 *iface, DWORD flags, HANDLE event)
2197 {
2198     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2199 
2200     TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
2201 
2202     return ddraw7_WaitForVerticalBlank(&ddraw->IDirectDraw7_iface, flags, event);
2203 }
2204 
2205 static HRESULT WINAPI ddraw1_WaitForVerticalBlank(IDirectDraw *iface, DWORD flags, HANDLE event)
2206 {
2207     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2208 
2209     TRACE("iface %p, flags %#x, event %p.\n", iface, flags, event);
2210 
2211     return ddraw7_WaitForVerticalBlank(&ddraw->IDirectDraw7_iface, flags, event);
2212 }
2213 
2214 static HRESULT WINAPI ddraw7_GetScanLine(IDirectDraw7 *iface, DWORD *Scanline)
2215 {
2216     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2217     struct wined3d_raster_status raster_status;
2218     HRESULT hr;
2219 
2220     TRACE("iface %p, line %p.\n", iface, Scanline);
2221 
2222     wined3d_mutex_lock();
2223     hr = wined3d_get_adapter_raster_status(ddraw->wined3d, WINED3DADAPTER_DEFAULT, &raster_status);
2224     wined3d_mutex_unlock();
2225     if (FAILED(hr))
2226     {
2227         WARN("Failed to get raster status, hr %#x.\n", hr);
2228         return hr;
2229     }
2230 
2231     *Scanline = raster_status.scan_line;
2232 
2233     if (raster_status.in_vblank)
2234         return DDERR_VERTICALBLANKINPROGRESS;
2235 
2236     return DD_OK;
2237 }
2238 
2239 static HRESULT WINAPI ddraw4_GetScanLine(IDirectDraw4 *iface, DWORD *line)
2240 {
2241     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2242 
2243     TRACE("iface %p, line %p.\n", iface, line);
2244 
2245     return ddraw7_GetScanLine(&ddraw->IDirectDraw7_iface, line);
2246 }
2247 
2248 static HRESULT WINAPI ddraw2_GetScanLine(IDirectDraw2 *iface, DWORD *line)
2249 {
2250     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2251 
2252     TRACE("iface %p, line %p.\n", iface, line);
2253 
2254     return ddraw7_GetScanLine(&ddraw->IDirectDraw7_iface, line);
2255 }
2256 
2257 static HRESULT WINAPI ddraw1_GetScanLine(IDirectDraw *iface, DWORD *line)
2258 {
2259     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2260 
2261     TRACE("iface %p, line %p.\n", iface, line);
2262 
2263     return ddraw7_GetScanLine(&ddraw->IDirectDraw7_iface, line);
2264 }
2265 
2266 static HRESULT WINAPI ddraw7_TestCooperativeLevel(IDirectDraw7 *iface)
2267 {
2268     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2269 
2270     TRACE("iface %p.\n", iface);
2271 
2272     return ddraw->device_state == DDRAW_DEVICE_STATE_LOST ? DDERR_NOEXCLUSIVEMODE : DD_OK;
2273 }
2274 
2275 static HRESULT WINAPI ddraw4_TestCooperativeLevel(IDirectDraw4 *iface)
2276 {
2277     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2278 
2279     TRACE("iface %p.\n", iface);
2280 
2281     return ddraw7_TestCooperativeLevel(&ddraw->IDirectDraw7_iface);
2282 }
2283 
2284 /*****************************************************************************
2285  * IDirectDraw7::GetGDISurface
2286  *
2287  * Returns the surface that GDI is treating as the primary surface.
2288  * For Wine this is the front buffer
2289  *
2290  * Params:
2291  *  GDISurface: Address to write the surface pointer to
2292  *
2293  * Returns:
2294  *  DD_OK if the surface was found
2295  *  DDERR_NOTFOUND if the GDI surface wasn't found
2296  *
2297  *****************************************************************************/
2298 static HRESULT WINAPI ddraw7_GetGDISurface(IDirectDraw7 *iface, IDirectDrawSurface7 **GDISurface)
2299 {
2300     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2301 
2302     TRACE("iface %p, surface %p.\n", iface, GDISurface);
2303 
2304     wined3d_mutex_lock();
2305 
2306     if (!(*GDISurface = &ddraw->primary->IDirectDrawSurface7_iface))
2307     {
2308         WARN("Primary not created yet.\n");
2309         wined3d_mutex_unlock();
2310         return DDERR_NOTFOUND;
2311     }
2312     IDirectDrawSurface7_AddRef(*GDISurface);
2313 
2314     wined3d_mutex_unlock();
2315 
2316     return DD_OK;
2317 }
2318 
2319 static HRESULT WINAPI ddraw4_GetGDISurface(IDirectDraw4 *iface, IDirectDrawSurface4 **surface)
2320 {
2321     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2322     struct ddraw_surface *surface_impl;
2323     IDirectDrawSurface7 *surface7;
2324     HRESULT hr;
2325 
2326     TRACE("iface %p, surface %p.\n", iface, surface);
2327 
2328     hr = ddraw7_GetGDISurface(&ddraw->IDirectDraw7_iface, &surface7);
2329     if (FAILED(hr))
2330     {
2331         *surface = NULL;
2332         return hr;
2333     }
2334     surface_impl = impl_from_IDirectDrawSurface7(surface7);
2335     *surface = &surface_impl->IDirectDrawSurface4_iface;
2336     IDirectDrawSurface4_AddRef(*surface);
2337     IDirectDrawSurface7_Release(surface7);
2338 
2339     return hr;
2340 }
2341 
2342 static HRESULT WINAPI ddraw2_GetGDISurface(IDirectDraw2 *iface, IDirectDrawSurface **surface)
2343 {
2344     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2345     struct ddraw_surface *surface_impl;
2346     IDirectDrawSurface7 *surface7;
2347     HRESULT hr;
2348 
2349     TRACE("iface %p, surface %p.\n", iface, surface);
2350 
2351     hr = ddraw7_GetGDISurface(&ddraw->IDirectDraw7_iface, &surface7);
2352     if (FAILED(hr))
2353     {
2354         *surface = NULL;
2355         return hr;
2356     }
2357     surface_impl = impl_from_IDirectDrawSurface7(surface7);
2358     *surface = &surface_impl->IDirectDrawSurface_iface;
2359     IDirectDrawSurface_AddRef(*surface);
2360     IDirectDrawSurface7_Release(surface7);
2361 
2362     return hr;
2363 }
2364 
2365 static HRESULT WINAPI ddraw1_GetGDISurface(IDirectDraw *iface, IDirectDrawSurface **surface)
2366 {
2367     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2368     struct ddraw_surface *surface_impl;
2369     IDirectDrawSurface7 *surface7;
2370     HRESULT hr;
2371 
2372     TRACE("iface %p, surface %p.\n", iface, surface);
2373 
2374     hr = ddraw7_GetGDISurface(&ddraw->IDirectDraw7_iface, &surface7);
2375     if (FAILED(hr))
2376     {
2377         *surface = NULL;
2378         return hr;
2379     }
2380     surface_impl = impl_from_IDirectDrawSurface7(surface7);
2381     *surface = &surface_impl->IDirectDrawSurface_iface;
2382     IDirectDrawSurface_AddRef(*surface);
2383     IDirectDrawSurface7_Release(surface7);
2384 
2385     return hr;
2386 }
2387 
2388 struct displaymodescallback_context
2389 {
2390     LPDDENUMMODESCALLBACK func;
2391     void *context;
2392 };
2393 
2394 static HRESULT CALLBACK EnumDisplayModesCallbackThunk(DDSURFACEDESC2 *surface_desc, void *context)
2395 {
2396     struct displaymodescallback_context *cbcontext = context;
2397     DDSURFACEDESC desc;
2398 
2399     DDSD2_to_DDSD(surface_desc, &desc);
2400     return cbcontext->func(&desc, cbcontext->context);
2401 }
2402 
2403 /*****************************************************************************
2404  * IDirectDraw7::EnumDisplayModes
2405  *
2406  * Enumerates the supported Display modes. The modes can be filtered with
2407  * the DDSD parameter.
2408  *
2409  * Params:
2410  *  Flags: can be DDEDM_REFRESHRATES and DDEDM_STANDARDVGAMODES. For old ddraw
2411  *         versions (3 and older?) this is reserved and must be 0.
2412  *  DDSD: Surface description to filter the modes
2413  *  Context: Pointer passed back to the callback function
2414  *  cb: Application-provided callback function
2415  *
2416  * Returns:
2417  *  DD_OK on success
2418  *  DDERR_INVALIDPARAMS if the callback wasn't set
2419  *
2420  *****************************************************************************/
2421 static HRESULT WINAPI ddraw7_EnumDisplayModes(IDirectDraw7 *iface, DWORD Flags,
2422         DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMMODESCALLBACK2 cb)
2423 {
2424     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2425     struct wined3d_display_mode *enum_modes = NULL;
2426     struct wined3d_display_mode mode;
2427     unsigned int modenum, fmt;
2428     DDSURFACEDESC2 callback_sd;
2429     unsigned enum_mode_count = 0, enum_mode_array_size = 16;
2430     DDPIXELFORMAT pixelformat;
2431 
2432     static const enum wined3d_format_id checkFormatList[] =
2433     {
2434         WINED3DFMT_B8G8R8X8_UNORM,
2435         WINED3DFMT_B5G6R5_UNORM,
2436         WINED3DFMT_P8_UINT,
2437     };
2438 
2439     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2440             iface, Flags, DDSD, Context, cb);
2441 
2442     if (!cb)
2443         return DDERR_INVALIDPARAMS;
2444 
2445     if (!(enum_modes = heap_alloc(enum_mode_array_size * sizeof(*enum_modes))))
2446         return DDERR_OUTOFMEMORY;
2447 
2448     wined3d_mutex_lock();
2449 
2450     pixelformat.dwSize = sizeof(pixelformat);
2451     for(fmt = 0; fmt < ARRAY_SIZE(checkFormatList); fmt++)
2452     {
2453         modenum = 0;
2454         while (wined3d_enum_adapter_modes(ddraw->wined3d, WINED3DADAPTER_DEFAULT, checkFormatList[fmt],
2455                 WINED3D_SCANLINE_ORDERING_UNKNOWN, modenum++, &mode) == WINED3D_OK)
2456         {
2457             BOOL found = FALSE;
2458             unsigned i;
2459 
2460             ddrawformat_from_wined3dformat(&pixelformat, mode.format_id);
2461             if (DDSD)
2462             {
2463                 if (DDSD->dwFlags & DDSD_WIDTH && mode.width != DDSD->dwWidth)
2464                     continue;
2465                 if (DDSD->dwFlags & DDSD_HEIGHT && mode.height != DDSD->dwHeight)
2466                     continue;
2467                 if (DDSD->dwFlags & DDSD_REFRESHRATE && mode.refresh_rate != DDSD->u2.dwRefreshRate)
2468                     continue;
2469                 if (DDSD->dwFlags & DDSD_PIXELFORMAT
2470                         && pixelformat.u1.dwRGBBitCount != DDSD->u4.ddpfPixelFormat.u1.dwRGBBitCount)
2471                     continue;
2472             }
2473 
2474             /* DX docs state EnumDisplayMode should return only unique modes */
2475             for (i = 0; i < enum_mode_count; i++)
2476             {
2477                 if (enum_modes[i].width == mode.width && enum_modes[i].height == mode.height
2478                     && enum_modes[i].format_id == mode.format_id
2479                     && (enum_modes[i].refresh_rate == mode.refresh_rate || !(Flags & DDEDM_REFRESHRATES)))
2480                 {
2481                     found = TRUE;
2482                     break;
2483                 }
2484             }
2485             if(found) continue;
2486 
2487             memset(&callback_sd, 0, sizeof(callback_sd));
2488             callback_sd.dwSize = sizeof(callback_sd);
2489             callback_sd.u4.ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT);
2490 
2491             callback_sd.dwFlags = DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_PITCH|DDSD_REFRESHRATE;
2492             if (Flags & DDEDM_REFRESHRATES)
2493                 callback_sd.u2.dwRefreshRate = mode.refresh_rate;
2494 
2495             callback_sd.dwWidth = mode.width;
2496             callback_sd.dwHeight = mode.height;
2497 
2498             callback_sd.u4.ddpfPixelFormat=pixelformat;
2499 
2500             /* Calc pitch and DWORD align like MSDN says */
2501             callback_sd.u1.lPitch = (callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount / 8) * mode.width;
2502             callback_sd.u1.lPitch = (callback_sd.u1.lPitch + 3) & ~3;
2503 
2504             TRACE("Enumerating %dx%dx%d @%d\n", callback_sd.dwWidth, callback_sd.dwHeight, callback_sd.u4.ddpfPixelFormat.u1.dwRGBBitCount,
2505               callback_sd.u2.dwRefreshRate);
2506 
2507             if(cb(&callback_sd, Context) == DDENUMRET_CANCEL)
2508             {
2509                 TRACE("Application asked to terminate the enumeration\n");
2510                 heap_free(enum_modes);
2511                 wined3d_mutex_unlock();
2512                 return DD_OK;
2513             }
2514 
2515             if (enum_mode_count == enum_mode_array_size)
2516             {
2517                 struct wined3d_display_mode *new_enum_modes;
2518 
2519                 enum_mode_array_size *= 2;
2520                 if (!(new_enum_modes = heap_realloc(enum_modes, enum_mode_array_size * sizeof(*new_enum_modes))))
2521                 {
2522                     heap_free(enum_modes);
2523                     wined3d_mutex_unlock();
2524                     return DDERR_OUTOFMEMORY;
2525                 }
2526 
2527                 enum_modes = new_enum_modes;
2528             }
2529             enum_modes[enum_mode_count++] = mode;
2530         }
2531     }
2532 
2533     TRACE("End of enumeration\n");
2534     heap_free(enum_modes);
2535     wined3d_mutex_unlock();
2536 
2537     return DD_OK;
2538 }
2539 
2540 static HRESULT WINAPI ddraw4_EnumDisplayModes(IDirectDraw4 *iface, DWORD flags,
2541         DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMMODESCALLBACK2 callback)
2542 {
2543     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2544 
2545     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2546             iface, flags, surface_desc, context, callback);
2547 
2548     return ddraw7_EnumDisplayModes(&ddraw->IDirectDraw7_iface, flags, surface_desc, context, callback);
2549 }
2550 
2551 static HRESULT WINAPI ddraw2_EnumDisplayModes(IDirectDraw2 *iface, DWORD flags,
2552         DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2553 {
2554     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2555     struct displaymodescallback_context cbcontext;
2556     DDSURFACEDESC2 surface_desc2;
2557 
2558     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2559             iface, flags, surface_desc, context, callback);
2560 
2561     cbcontext.func = callback;
2562     cbcontext.context = context;
2563 
2564     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
2565     return ddraw7_EnumDisplayModes(&ddraw->IDirectDraw7_iface, flags,
2566             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumDisplayModesCallbackThunk);
2567 }
2568 
2569 static HRESULT WINAPI ddraw1_EnumDisplayModes(IDirectDraw *iface, DWORD flags,
2570         DDSURFACEDESC *surface_desc, void *context, LPDDENUMMODESCALLBACK callback)
2571 {
2572     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
2573     struct displaymodescallback_context cbcontext;
2574     DDSURFACEDESC2 surface_desc2;
2575 
2576     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
2577             iface, flags, surface_desc, context, callback);
2578 
2579     cbcontext.func = callback;
2580     cbcontext.context = context;
2581 
2582     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
2583     return ddraw7_EnumDisplayModes(&ddraw->IDirectDraw7_iface, flags,
2584             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumDisplayModesCallbackThunk);
2585 }
2586 
2587 /*****************************************************************************
2588  * IDirectDraw7::EvaluateMode
2589  *
2590  * Used with IDirectDraw7::StartModeTest to test video modes.
2591  * EvaluateMode is used to pass or fail a mode, and continue with the next
2592  * mode
2593  *
2594  * Params:
2595  *  Flags: DDEM_MODEPASSED or DDEM_MODEFAILED
2596  *  Timeout: Returns the amount of seconds left before the mode would have
2597  *           been failed automatically
2598  *
2599  * Returns:
2600  *  This implementation always DD_OK, because it's a stub
2601  *
2602  *****************************************************************************/
2603 static HRESULT WINAPI ddraw7_EvaluateMode(IDirectDraw7 *iface, DWORD Flags, DWORD *Timeout)
2604 {
2605     FIXME("iface %p, flags %#x, timeout %p stub!\n", iface, Flags, Timeout);
2606 
2607     /* When implementing this, implement it in WineD3D */
2608 
2609     return DD_OK;
2610 }
2611 
2612 /*****************************************************************************
2613  * IDirectDraw7::GetDeviceIdentifier
2614  *
2615  * Returns the device identifier, which gives information about the driver
2616  * Our device identifier is defined at the beginning of this file.
2617  *
2618  * Params:
2619  *  DDDI: Address for the returned structure
2620  *  Flags: Can be DDGDI_GETHOSTIDENTIFIER
2621  *
2622  * Returns:
2623  *  On success it returns DD_OK
2624  *  DDERR_INVALIDPARAMS if DDDI is NULL
2625  *
2626  *****************************************************************************/
2627 static HRESULT WINAPI ddraw7_GetDeviceIdentifier(IDirectDraw7 *iface,
2628         DDDEVICEIDENTIFIER2 *DDDI, DWORD Flags)
2629 {
2630     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2631     struct wined3d_adapter_identifier adapter_id;
2632     HRESULT hr = S_OK;
2633 
2634     TRACE("iface %p, device_identifier %p, flags %#x.\n", iface, DDDI, Flags);
2635 
2636     if (!DDDI)
2637         return DDERR_INVALIDPARAMS;
2638 
2639     if (Flags & DDGDI_GETHOSTIDENTIFIER)
2640     {
2641         /* The DDGDI_GETHOSTIDENTIFIER returns the information about the 2D
2642          * host adapter, if there's a secondary 3D adapter. This doesn't apply
2643          * to any modern hardware, nor is it interesting for Wine, so ignore it.
2644          * Size of DDDEVICEIDENTIFIER2 may be aligned to 8 bytes and thus 4
2645          * bytes too long. So only copy the relevant part of the structure
2646          */
2647 
2648         memcpy(DDDI, &deviceidentifier, FIELD_OFFSET(DDDEVICEIDENTIFIER2, dwWHQLLevel) + sizeof(DWORD));
2649         return DD_OK;
2650     }
2651 
2652     /* Drakan: Order of the Flame expects accurate D3D device information from ddraw */
2653     adapter_id.driver = DDDI->szDriver;
2654     adapter_id.driver_size = sizeof(DDDI->szDriver);
2655     adapter_id.description = DDDI->szDescription;
2656     adapter_id.description_size = sizeof(DDDI->szDescription);
2657     adapter_id.device_name_size = 0;
2658     wined3d_mutex_lock();
2659     hr = wined3d_get_adapter_identifier(ddraw->wined3d, WINED3DADAPTER_DEFAULT, 0x0, &adapter_id);
2660     wined3d_mutex_unlock();
2661     if (FAILED(hr)) return hr;
2662 
2663     DDDI->liDriverVersion = adapter_id.driver_version;
2664     DDDI->dwVendorId = adapter_id.vendor_id;
2665     DDDI->dwDeviceId = adapter_id.device_id;
2666     DDDI->dwSubSysId = adapter_id.subsystem_id;
2667     DDDI->dwRevision = adapter_id.revision;
2668     DDDI->guidDeviceIdentifier = adapter_id.device_identifier;
2669     DDDI->dwWHQLLevel = adapter_id.whql_level;
2670     return DD_OK;
2671 }
2672 
2673 static HRESULT WINAPI ddraw4_GetDeviceIdentifier(IDirectDraw4 *iface,
2674         DDDEVICEIDENTIFIER *identifier, DWORD flags)
2675 {
2676     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2677     DDDEVICEIDENTIFIER2 identifier2;
2678     HRESULT hr;
2679 
2680     TRACE("iface %p, identifier %p, flags %#x.\n", iface, identifier, flags);
2681 
2682     hr = ddraw7_GetDeviceIdentifier(&ddraw->IDirectDraw7_iface, &identifier2, flags);
2683     DDRAW_Convert_DDDEVICEIDENTIFIER_2_To_1(&identifier2, identifier);
2684 
2685     return hr;
2686 }
2687 
2688 /*****************************************************************************
2689  * IDirectDraw7::GetSurfaceFromDC
2690  *
2691  * Returns the Surface for a GDI device context handle.
2692  * Is this related to IDirectDrawSurface::GetDC ???
2693  *
2694  * Params:
2695  *  hdc: hdc to return the surface for
2696  *  Surface: Address to write the surface pointer to
2697  *
2698  * Returns:
2699  *  Always returns DD_OK because it's a stub
2700  *
2701  *****************************************************************************/
2702 static HRESULT WINAPI ddraw7_GetSurfaceFromDC(IDirectDraw7 *iface,
2703         HDC dc, IDirectDrawSurface7 **surface)
2704 {
2705     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2706     struct ddraw_surface *surface_impl;
2707 
2708     TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2709 
2710     if (!surface)
2711         return E_INVALIDARG;
2712 
2713     if (!dc)
2714         goto done;
2715 
2716     wined3d_mutex_lock();
2717     LIST_FOR_EACH_ENTRY(surface_impl, &ddraw->surface_list, struct ddraw_surface, surface_list_entry)
2718     {
2719         if (surface_impl->dc != dc)
2720             continue;
2721 
2722         TRACE("Found surface %p for dc %p.\n", surface_impl, dc);
2723         *surface = &surface_impl->IDirectDrawSurface7_iface;
2724         IDirectDrawSurface7_AddRef(*surface);
2725         wined3d_mutex_unlock();
2726         return DD_OK;
2727     }
2728     wined3d_mutex_unlock();
2729 
2730 done:
2731     TRACE("No surface found for dc %p.\n", dc);
2732     *surface = NULL;
2733     return DDERR_NOTFOUND;
2734 }
2735 
2736 static HRESULT WINAPI ddraw4_GetSurfaceFromDC(IDirectDraw4 *iface, HDC dc,
2737         IDirectDrawSurface4 **surface)
2738 {
2739     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2740     struct ddraw_surface *surface_impl;
2741     IDirectDrawSurface7 *surface7;
2742     HRESULT hr;
2743 
2744     TRACE("iface %p, dc %p, surface %p.\n", iface, dc, surface);
2745 
2746     if (!surface) return E_INVALIDARG;
2747 
2748     hr = ddraw7_GetSurfaceFromDC(&ddraw->IDirectDraw7_iface, dc, &surface7);
2749     if (FAILED(hr))
2750     {
2751         *surface = NULL;
2752         return hr;
2753     }
2754     surface_impl = impl_from_IDirectDrawSurface7(surface7);
2755     /* Tests say this is true */
2756     *surface = (IDirectDrawSurface4 *)&surface_impl->IDirectDrawSurface_iface;
2757     IDirectDrawSurface_AddRef(&surface_impl->IDirectDrawSurface_iface);
2758     IDirectDrawSurface7_Release(surface7);
2759 
2760     return hr;
2761 }
2762 
2763 static HRESULT CALLBACK restore_callback(IDirectDrawSurface7 *surface, DDSURFACEDESC2 *desc, void *context)
2764 {
2765     IDirectDrawSurface_Restore(surface);
2766     IDirectDrawSurface_Release(surface);
2767 
2768     return DDENUMRET_OK;
2769 }
2770 
2771 static HRESULT WINAPI ddraw7_RestoreAllSurfaces(IDirectDraw7 *iface)
2772 {
2773     TRACE("iface %p.\n", iface);
2774 
2775     return IDirectDraw7_EnumSurfaces(iface, DDENUMSURFACES_ALL | DDENUMSURFACES_DOESEXIST,
2776             NULL, NULL, restore_callback);
2777 }
2778 
2779 static HRESULT WINAPI ddraw4_RestoreAllSurfaces(IDirectDraw4 *iface)
2780 {
2781     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2782 
2783     TRACE("iface %p.\n", iface);
2784 
2785     return ddraw7_RestoreAllSurfaces(&ddraw->IDirectDraw7_iface);
2786 }
2787 
2788 /*****************************************************************************
2789  * IDirectDraw7::StartModeTest
2790  *
2791  * Tests the specified video modes to update the system registry with
2792  * refresh rate information. StartModeTest starts the mode test,
2793  * EvaluateMode is used to fail or pass a mode. If EvaluateMode
2794  * isn't called within 15 seconds, the mode is failed automatically
2795  *
2796  * As refresh rates are handled by the X server, I don't think this
2797  * Method is important
2798  *
2799  * Params:
2800  *  Modes: An array of mode specifications
2801  *  NumModes: The number of modes in Modes
2802  *  Flags: Some flags...
2803  *
2804  * Returns:
2805  *  Returns DDERR_TESTFINISHED if flags contains DDSMT_ISTESTREQUIRED,
2806  *  if no modes are passed, DDERR_INVALIDPARAMS is returned,
2807  *  otherwise DD_OK
2808  *
2809  *****************************************************************************/
2810 static HRESULT WINAPI ddraw7_StartModeTest(IDirectDraw7 *iface, SIZE *Modes, DWORD NumModes, DWORD Flags)
2811 {
2812     FIXME("iface %p, modes %p, mode_count %u, flags %#x partial stub!\n",
2813             iface, Modes, NumModes, Flags);
2814 
2815     /* This looks sane */
2816     if( (!Modes) || (NumModes == 0) ) return DDERR_INVALIDPARAMS;
2817 
2818     /* DDSMT_ISTESTREQUIRED asks if a mode test is necessary.
2819      * As it is not, DDERR_TESTFINISHED is returned
2820      * (hopefully that's correct
2821      *
2822     if(Flags & DDSMT_ISTESTREQUIRED) return DDERR_TESTFINISHED;
2823      * well, that value doesn't (yet) exist in the wine headers, so ignore it
2824      */
2825 
2826     return DD_OK;
2827 }
2828 
2829 static HRESULT WINAPI ddraw7_CreateSurface(IDirectDraw7 *iface, DDSURFACEDESC2 *surface_desc,
2830         IDirectDrawSurface7 **surface, IUnknown *outer_unknown)
2831 {
2832     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
2833     struct ddraw_surface *impl;
2834     HRESULT hr;
2835 
2836     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
2837             iface, surface_desc, surface, outer_unknown);
2838 
2839     wined3d_mutex_lock();
2840 
2841     if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
2842     {
2843         WARN("Cooperative level not set.\n");
2844         wined3d_mutex_unlock();
2845         return DDERR_NOCOOPERATIVELEVELSET;
2846     }
2847 
2848     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC2))
2849     {
2850         WARN("Application supplied invalid surface descriptor\n");
2851         wined3d_mutex_unlock();
2852         return DDERR_INVALIDPARAMS;
2853     }
2854 
2855     __TRY
2856     {
2857         *surface = NULL;
2858     }
2859     __EXCEPT_PAGE_FAULT
2860     {
2861         WARN("Surface pointer %p is invalid.\n", surface);
2862         wined3d_mutex_unlock();
2863         return DDERR_INVALIDPARAMS;
2864     }
2865     __ENDTRY;
2866 
2867     if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
2868     {
2869         if (TRACE_ON(ddraw))
2870         {
2871             TRACE(" (%p) Requesting surface desc :\n", iface);
2872             DDRAW_dump_surface_desc(surface_desc);
2873         }
2874 
2875         WARN("Application tried to create an explicit front or back buffer\n");
2876         wined3d_mutex_unlock();
2877         return DDERR_INVALIDCAPS;
2878     }
2879 
2880     hr = ddraw_surface_create(ddraw, surface_desc, &impl, outer_unknown, 7);
2881     wined3d_mutex_unlock();
2882     if (FAILED(hr))
2883         return hr;
2884 
2885     *surface = &impl->IDirectDrawSurface7_iface;
2886     IDirectDraw7_AddRef(iface);
2887     impl->ifaceToRelease = (IUnknown *)iface;
2888 
2889     return hr;
2890 }
2891 
2892 static HRESULT WINAPI ddraw4_CreateSurface(IDirectDraw4 *iface,
2893         DDSURFACEDESC2 *surface_desc, IDirectDrawSurface4 **surface, IUnknown *outer_unknown)
2894 {
2895     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
2896     struct ddraw_surface *impl;
2897     HRESULT hr;
2898 
2899     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
2900             iface, surface_desc, surface, outer_unknown);
2901 
2902     wined3d_mutex_lock();
2903 
2904     if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
2905     {
2906         WARN("Cooperative level not set.\n");
2907         wined3d_mutex_unlock();
2908         return DDERR_NOCOOPERATIVELEVELSET;
2909     }
2910 
2911     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC2))
2912     {
2913         WARN("Application supplied invalid surface descriptor\n");
2914         wined3d_mutex_unlock();
2915         return DDERR_INVALIDPARAMS;
2916     }
2917 
2918     __TRY
2919     {
2920         *surface = NULL;
2921     }
2922     __EXCEPT_PAGE_FAULT
2923     {
2924         WARN("Surface pointer %p is invalid.\n", surface);
2925         wined3d_mutex_unlock();
2926         return DDERR_INVALIDPARAMS;
2927     }
2928     __ENDTRY;
2929 
2930     if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
2931     {
2932         if (TRACE_ON(ddraw))
2933         {
2934             TRACE(" (%p) Requesting surface desc :\n", iface);
2935             DDRAW_dump_surface_desc(surface_desc);
2936         }
2937 
2938         WARN("Application tried to create an explicit front or back buffer\n");
2939         wined3d_mutex_unlock();
2940         return DDERR_INVALIDCAPS;
2941     }
2942 
2943     hr = ddraw_surface_create(ddraw, surface_desc, &impl, outer_unknown, 4);
2944     wined3d_mutex_unlock();
2945     if (FAILED(hr))
2946         return hr;
2947 
2948     *surface = &impl->IDirectDrawSurface4_iface;
2949     IDirectDraw4_AddRef(iface);
2950     impl->ifaceToRelease = (IUnknown *)iface;
2951 
2952     return hr;
2953 }
2954 
2955 static HRESULT WINAPI ddraw2_CreateSurface(IDirectDraw2 *iface,
2956         DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
2957 {
2958     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
2959     struct ddraw_surface *impl;
2960     HRESULT hr;
2961     DDSURFACEDESC2 surface_desc2;
2962 
2963     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
2964             iface, surface_desc, surface, outer_unknown);
2965 
2966     wined3d_mutex_lock();
2967 
2968     if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
2969     {
2970         WARN("Cooperative level not set.\n");
2971         wined3d_mutex_unlock();
2972         return DDERR_NOCOOPERATIVELEVELSET;
2973     }
2974 
2975     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC))
2976     {
2977         WARN("Application supplied invalid surface descriptor\n");
2978         wined3d_mutex_unlock();
2979         return DDERR_INVALIDPARAMS;
2980     }
2981 
2982     __TRY
2983     {
2984         *surface = NULL;
2985     }
2986     __EXCEPT_PAGE_FAULT
2987     {
2988         WARN("Surface pointer %p is invalid.\n", surface);
2989         wined3d_mutex_unlock();
2990         return DDERR_INVALIDPARAMS;
2991     }
2992     __ENDTRY;
2993 
2994     DDSD_to_DDSD2(surface_desc, &surface_desc2);
2995     if(surface_desc->ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER | DDSCAPS_BACKBUFFER))
2996     {
2997         if (TRACE_ON(ddraw))
2998         {
2999             TRACE(" (%p) Requesting surface desc :\n", iface);
3000             DDRAW_dump_surface_desc((DDSURFACEDESC2 *)surface_desc);
3001         }
3002 
3003         WARN("Application tried to create an explicit front or back buffer\n");
3004         wined3d_mutex_unlock();
3005         return DDERR_INVALIDCAPS;
3006     }
3007 
3008     hr = ddraw_surface_create(ddraw, &surface_desc2, &impl, outer_unknown, 2);
3009     wined3d_mutex_unlock();
3010     if (FAILED(hr))
3011         return hr;
3012 
3013     *surface = &impl->IDirectDrawSurface_iface;
3014     impl->ifaceToRelease = NULL;
3015 
3016     return hr;
3017 }
3018 
3019 static HRESULT WINAPI ddraw1_CreateSurface(IDirectDraw *iface,
3020         DDSURFACEDESC *surface_desc, IDirectDrawSurface **surface, IUnknown *outer_unknown)
3021 {
3022     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3023     struct ddraw_surface *impl;
3024     HRESULT hr;
3025     DDSURFACEDESC2 surface_desc2;
3026 
3027     TRACE("iface %p, surface_desc %p, surface %p, outer_unknown %p.\n",
3028             iface, surface_desc, surface, outer_unknown);
3029 
3030     wined3d_mutex_lock();
3031 
3032     if (!(ddraw->cooperative_level & (DDSCL_NORMAL | DDSCL_EXCLUSIVE)))
3033     {
3034         WARN("Cooperative level not set.\n");
3035         wined3d_mutex_unlock();
3036         return DDERR_NOCOOPERATIVELEVELSET;
3037     }
3038 
3039     if(surface_desc == NULL || surface_desc->dwSize != sizeof(DDSURFACEDESC))
3040     {
3041         WARN("Application supplied invalid surface descriptor\n");
3042         wined3d_mutex_unlock();
3043         return DDERR_INVALIDPARAMS;
3044     }
3045 
3046     __TRY
3047     {
3048         *surface = NULL;
3049     }
3050     __EXCEPT_PAGE_FAULT
3051     {
3052         WARN("Surface pointer %p is invalid.\n", surface);
3053         wined3d_mutex_unlock();
3054         return DDERR_INVALIDPARAMS;
3055     }
3056     __ENDTRY;
3057 
3058     if ((surface_desc->ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER))
3059             == (DDSCAPS_PRIMARYSURFACE | DDSCAPS_BACKBUFFER)
3060             || (surface_desc->ddsCaps.dwCaps & (DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER))
3061             == ((DDSCAPS_FLIP | DDSCAPS_FRONTBUFFER)))
3062     {
3063         WARN("Application tried to create an explicit front or back buffer.\n");
3064         wined3d_mutex_unlock();
3065         return DDERR_INVALIDCAPS;
3066     }
3067 
3068     DDSD_to_DDSD2(surface_desc, &surface_desc2);
3069     hr = ddraw_surface_create(ddraw, &surface_desc2, &impl, outer_unknown, 1);
3070     wined3d_mutex_unlock();
3071     if (FAILED(hr))
3072         return hr;
3073 
3074     *surface = &impl->IDirectDrawSurface_iface;
3075     impl->ifaceToRelease = NULL;
3076 
3077     return hr;
3078 }
3079 
3080 static BOOL
3081 Main_DirectDraw_DDPIXELFORMAT_Match(const DDPIXELFORMAT *requested,
3082                                     const DDPIXELFORMAT *provided)
3083 {
3084     /* Some flags must be present in both or neither for a match. */
3085     static const DWORD must_match = DDPF_PALETTEINDEXED1 | DDPF_PALETTEINDEXED2
3086         | DDPF_PALETTEINDEXED4 | DDPF_PALETTEINDEXED8 | DDPF_FOURCC
3087         | DDPF_ZBUFFER | DDPF_STENCILBUFFER;
3088 
3089     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3090         return FALSE;
3091 
3092     if ((requested->dwFlags & must_match) != (provided->dwFlags & must_match))
3093         return FALSE;
3094 
3095     if (requested->dwFlags & DDPF_FOURCC)
3096         if (requested->dwFourCC != provided->dwFourCC)
3097             return FALSE;
3098 
3099     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_ALPHA
3100                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3101         if (requested->u1.dwRGBBitCount != provided->u1.dwRGBBitCount)
3102             return FALSE;
3103 
3104     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3105                               |DDPF_LUMINANCE|DDPF_BUMPDUDV))
3106         if (requested->u2.dwRBitMask != provided->u2.dwRBitMask)
3107             return FALSE;
3108 
3109     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_ZBUFFER|DDPF_BUMPDUDV))
3110         if (requested->u3.dwGBitMask != provided->u3.dwGBitMask)
3111             return FALSE;
3112 
3113     /* I could be wrong about the bumpmapping. MSDN docs are vague. */
3114     if (requested->dwFlags & (DDPF_RGB|DDPF_YUV|DDPF_STENCILBUFFER
3115                               |DDPF_BUMPDUDV))
3116         if (requested->u4.dwBBitMask != provided->u4.dwBBitMask)
3117             return FALSE;
3118 
3119     if (requested->dwFlags & (DDPF_ALPHAPIXELS|DDPF_ZPIXELS))
3120         if (requested->u5.dwRGBAlphaBitMask != provided->u5.dwRGBAlphaBitMask)
3121             return FALSE;
3122 
3123     return TRUE;
3124 }
3125 
3126 static BOOL ddraw_match_surface_desc(const DDSURFACEDESC2 *requested, const DDSURFACEDESC2 *provided)
3127 {
3128     struct compare_info
3129     {
3130         DWORD flag;
3131         ptrdiff_t offset;
3132         size_t size;
3133     };
3134 
3135 #define CMP(FLAG, FIELD)                                \
3136         { DDSD_##FLAG, offsetof(DDSURFACEDESC2, FIELD), \
3137           sizeof(((DDSURFACEDESC2 *)(NULL))->FIELD) }
3138 
3139     static const struct compare_info compare[] =
3140     {
3141         CMP(ALPHABITDEPTH, dwAlphaBitDepth),
3142         CMP(BACKBUFFERCOUNT, u5.dwBackBufferCount),
3143         CMP(CAPS, ddsCaps),
3144         CMP(CKDESTBLT, ddckCKDestBlt),
3145         CMP(CKDESTOVERLAY, u3 /* ddckCKDestOverlay */),
3146         CMP(CKSRCBLT, ddckCKSrcBlt),
3147         CMP(CKSRCOVERLAY, ddckCKSrcOverlay),
3148         CMP(HEIGHT, dwHeight),
3149         CMP(LINEARSIZE, u1 /* dwLinearSize */),
3150         CMP(LPSURFACE, lpSurface),
3151         CMP(MIPMAPCOUNT, u2 /* dwMipMapCount */),
3152         CMP(PITCH, u1 /* lPitch */),
3153         /* PIXELFORMAT: manual */
3154         CMP(REFRESHRATE, u2 /* dwRefreshRate */),
3155         CMP(TEXTURESTAGE, dwTextureStage),
3156         CMP(WIDTH, dwWidth),
3157         /* ZBUFFERBITDEPTH: "obsolete" */
3158     };
3159 
3160 #undef CMP
3161 
3162     unsigned int i;
3163 
3164     if ((requested->dwFlags & provided->dwFlags) != requested->dwFlags)
3165         return FALSE;
3166 
3167     for (i=0; i < ARRAY_SIZE(compare); i++)
3168     {
3169         if (requested->dwFlags & compare[i].flag
3170             && memcmp((const char *)provided + compare[i].offset,
3171                       (const char *)requested + compare[i].offset,
3172                       compare[i].size) != 0)
3173             return FALSE;
3174     }
3175 
3176     if (requested->dwFlags & DDSD_PIXELFORMAT)
3177     {
3178         if (!Main_DirectDraw_DDPIXELFORMAT_Match(&requested->u4.ddpfPixelFormat,
3179                                                 &provided->u4.ddpfPixelFormat))
3180             return FALSE;
3181     }
3182 
3183     return TRUE;
3184 }
3185 
3186 struct surfacescallback2_context
3187 {
3188     LPDDENUMSURFACESCALLBACK2 func;
3189     void *context;
3190 };
3191 
3192 struct surfacescallback_context
3193 {
3194     LPDDENUMSURFACESCALLBACK func;
3195     void *context;
3196 };
3197 
3198 static HRESULT CALLBACK EnumSurfacesCallback2Thunk(IDirectDrawSurface7 *surface,
3199         DDSURFACEDESC2 *surface_desc, void *context)
3200 {
3201     struct ddraw_surface *surface_impl = impl_from_IDirectDrawSurface7(surface);
3202     struct surfacescallback2_context *cbcontext = context;
3203 
3204     IDirectDrawSurface4_AddRef(&surface_impl->IDirectDrawSurface4_iface);
3205     IDirectDrawSurface7_Release(surface);
3206 
3207     return cbcontext->func(&surface_impl->IDirectDrawSurface4_iface,
3208             surface_desc, cbcontext->context);
3209 }
3210 
3211 static HRESULT CALLBACK EnumSurfacesCallbackThunk(IDirectDrawSurface7 *surface,
3212         DDSURFACEDESC2 *surface_desc, void *context)
3213 {
3214     struct ddraw_surface *surface_impl = impl_from_IDirectDrawSurface7(surface);
3215     struct surfacescallback_context *cbcontext = context;
3216 
3217     IDirectDrawSurface_AddRef(&surface_impl->IDirectDrawSurface_iface);
3218     IDirectDrawSurface7_Release(surface);
3219 
3220     return cbcontext->func(&surface_impl->IDirectDrawSurface_iface,
3221             (DDSURFACEDESC *)surface_desc, cbcontext->context);
3222 }
3223 
3224 /*****************************************************************************
3225  * IDirectDraw7::EnumSurfaces
3226  *
3227  * Loops through all surfaces attached to this device and calls the
3228  * application callback. This can't be relayed to WineD3DDevice,
3229  * because some WineD3DSurfaces' parents are IParent objects
3230  *
3231  * Params:
3232  *  Flags: Some filtering flags. See IDirectDrawImpl_EnumSurfacesCallback
3233  *  DDSD: Description to filter for
3234  *  Context: Application-provided pointer, it's passed unmodified to the
3235  *           Callback function
3236  *  Callback: Address to call for each surface
3237  *
3238  * Returns:
3239  *  DDERR_INVALIDPARAMS if the callback is NULL
3240  *  DD_OK on success
3241  *
3242  *****************************************************************************/
3243 static HRESULT WINAPI ddraw7_EnumSurfaces(IDirectDraw7 *iface, DWORD Flags,
3244         DDSURFACEDESC2 *DDSD, void *Context, LPDDENUMSURFACESCALLBACK7 Callback)
3245 {
3246     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
3247     struct ddraw_surface *surf;
3248     DWORD match_flags = Flags & (DDENUMSURFACES_ALL | DDENUMSURFACES_NOMATCH | DDENUMSURFACES_MATCH);
3249 
3250     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3251             iface, Flags, DDSD, Context, Callback);
3252 
3253     if (!Callback)
3254         return DDERR_INVALIDPARAMS;
3255 
3256     if (Flags & DDENUMSURFACES_CANBECREATED)
3257     {
3258          IDirectDrawSurface7 *surface;
3259          DDSURFACEDESC2 testdesc;
3260          HRESULT hr;
3261 
3262         if (match_flags != DDENUMSURFACES_MATCH)
3263             return DDERR_INVALIDPARAMS;
3264 
3265         if (!DDSD)
3266             return DDERR_INVALIDPARAMS;
3267 
3268         memcpy(&testdesc, DDSD, sizeof(testdesc));
3269         if (!(testdesc.dwFlags & DDSD_WIDTH))
3270         {
3271             testdesc.dwFlags |= DDSD_WIDTH;
3272             testdesc.dwWidth = 512;
3273         }
3274         if (!(testdesc.dwFlags & DDSD_HEIGHT))
3275         {
3276             testdesc.dwFlags |= DDSD_HEIGHT;
3277             testdesc.dwHeight = 512;
3278         }
3279 
3280         hr = IDirectDraw7_CreateSurface(iface, &testdesc, &surface, NULL);
3281         if (SUCCEEDED(hr))
3282         {
3283             surf = unsafe_impl_from_IDirectDrawSurface7(surface);
3284             Callback(NULL, &surf->surface_desc, Context);
3285             IDirectDrawSurface7_Release(surface);
3286         }
3287         else
3288             ERR("Failed to create surface, hr %#x.\n", hr);
3289     }
3290     else if (Flags & DDENUMSURFACES_DOESEXIST)
3291     {
3292         BOOL all, nomatch;
3293         DDSURFACEDESC2 desc;
3294         struct list *entry, *entry2;
3295 
3296         /* a combination of match flags is not allowed */
3297         if (match_flags != 0 &&
3298                 match_flags != DDENUMSURFACES_ALL &&
3299                 match_flags != DDENUMSURFACES_MATCH &&
3300                 match_flags != DDENUMSURFACES_NOMATCH)
3301             return DDERR_INVALIDPARAMS;
3302 
3303         all = (Flags & DDENUMSURFACES_ALL) != 0;
3304         nomatch = (Flags & DDENUMSURFACES_NOMATCH) != 0;
3305 
3306         if (!all && !DDSD)
3307             return DDERR_INVALIDPARAMS;
3308 
3309         wined3d_mutex_lock();
3310 
3311         /* Use the _SAFE enumeration, the app may destroy enumerated surfaces */
3312         LIST_FOR_EACH_SAFE(entry, entry2, &ddraw->surface_list)
3313         {
3314             surf = LIST_ENTRY(entry, struct ddraw_surface, surface_list_entry);
3315 
3316             if (!surf->iface_count)
3317             {
3318                 WARN("Not enumerating surface %p because it doesn't have any references.\n", surf);
3319                 continue;
3320             }
3321 
3322             if (all || (nomatch != ddraw_match_surface_desc(DDSD, &surf->surface_desc)))
3323             {
3324                 TRACE("Enumerating surface %p.\n", surf);
3325                 desc = surf->surface_desc;
3326                 IDirectDrawSurface7_AddRef(&surf->IDirectDrawSurface7_iface);
3327                 if (Callback(&surf->IDirectDrawSurface7_iface, &desc, Context) != DDENUMRET_OK)
3328                 {
3329                     wined3d_mutex_unlock();
3330                     return DD_OK;
3331                 }
3332             }
3333         }
3334 
3335         wined3d_mutex_unlock();
3336     }
3337     else
3338         return DDERR_INVALIDPARAMS;
3339 
3340     return DD_OK;
3341 }
3342 
3343 static HRESULT WINAPI ddraw4_EnumSurfaces(IDirectDraw4 *iface, DWORD flags,
3344         DDSURFACEDESC2 *surface_desc, void *context, LPDDENUMSURFACESCALLBACK2 callback)
3345 {
3346     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3347     struct surfacescallback2_context cbcontext;
3348 
3349     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3350             iface, flags, surface_desc, context, callback);
3351 
3352     cbcontext.func = callback;
3353     cbcontext.context = context;
3354 
3355     return ddraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, flags, surface_desc,
3356             &cbcontext, EnumSurfacesCallback2Thunk);
3357 }
3358 
3359 static HRESULT WINAPI ddraw2_EnumSurfaces(IDirectDraw2 *iface, DWORD flags,
3360         DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3361 {
3362     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3363     struct surfacescallback_context cbcontext;
3364     DDSURFACEDESC2 surface_desc2;
3365 
3366     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3367             iface, flags, surface_desc, context, callback);
3368 
3369     cbcontext.func = callback;
3370     cbcontext.context = context;
3371 
3372     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
3373     return ddraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, flags,
3374             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumSurfacesCallbackThunk);
3375 }
3376 
3377 static HRESULT WINAPI ddraw1_EnumSurfaces(IDirectDraw *iface, DWORD flags,
3378         DDSURFACEDESC *surface_desc, void *context, LPDDENUMSURFACESCALLBACK callback)
3379 {
3380     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3381     struct surfacescallback_context cbcontext;
3382     DDSURFACEDESC2 surface_desc2;
3383 
3384     TRACE("iface %p, flags %#x, surface_desc %p, context %p, callback %p.\n",
3385             iface, flags, surface_desc, context, callback);
3386 
3387     cbcontext.func = callback;
3388     cbcontext.context = context;
3389 
3390     if (surface_desc) DDSD_to_DDSD2(surface_desc, &surface_desc2);
3391     return ddraw7_EnumSurfaces(&ddraw->IDirectDraw7_iface, flags,
3392             surface_desc ? &surface_desc2 : NULL, &cbcontext, EnumSurfacesCallbackThunk);
3393 }
3394 
3395 /*****************************************************************************
3396  * DirectDrawCreateClipper (DDRAW.@)
3397  *
3398  * Creates a new IDirectDrawClipper object.
3399  *
3400  * Params:
3401  *  Clipper: Address to write the interface pointer to
3402  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3403  *            NULL
3404  *
3405  * Returns:
3406  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
3407  *  E_OUTOFMEMORY if allocating the object failed
3408  *
3409  *****************************************************************************/
3410 HRESULT WINAPI DirectDrawCreateClipper(DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3411 {
3412     struct ddraw_clipper *object;
3413     HRESULT hr;
3414 
3415     TRACE("flags %#x, clipper %p, outer_unknown %p.\n",
3416             flags, clipper, outer_unknown);
3417 
3418     if (outer_unknown)
3419         return CLASS_E_NOAGGREGATION;
3420 
3421     wined3d_mutex_lock();
3422 
3423     if (!(object = heap_alloc_zero(sizeof(*object))))
3424     {
3425         wined3d_mutex_unlock();
3426         return E_OUTOFMEMORY;
3427     }
3428 
3429     hr = ddraw_clipper_init(object);
3430     if (FAILED(hr))
3431     {
3432         WARN("Failed to initialize clipper, hr %#x.\n", hr);
3433         heap_free(object);
3434         wined3d_mutex_unlock();
3435         return hr;
3436     }
3437 
3438     TRACE("Created clipper %p.\n", object);
3439     *clipper = &object->IDirectDrawClipper_iface;
3440     wined3d_mutex_unlock();
3441 
3442     return DD_OK;
3443 }
3444 
3445 /*****************************************************************************
3446  * IDirectDraw7::CreateClipper
3447  *
3448  * Creates a DDraw clipper. See DirectDrawCreateClipper for details
3449  *
3450  *****************************************************************************/
3451 static HRESULT WINAPI ddraw7_CreateClipper(IDirectDraw7 *iface, DWORD Flags,
3452         IDirectDrawClipper **Clipper, IUnknown *UnkOuter)
3453 {
3454     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3455             iface, Flags, Clipper, UnkOuter);
3456 
3457     return DirectDrawCreateClipper(Flags, Clipper, UnkOuter);
3458 }
3459 
3460 static HRESULT WINAPI ddraw4_CreateClipper(IDirectDraw4 *iface, DWORD flags,
3461         IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3462 {
3463     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3464 
3465     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3466             iface, flags, clipper, outer_unknown);
3467 
3468     return ddraw7_CreateClipper(&ddraw->IDirectDraw7_iface, flags, clipper, outer_unknown);
3469 }
3470 
3471 static HRESULT WINAPI ddraw2_CreateClipper(IDirectDraw2 *iface,
3472         DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3473 {
3474     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3475 
3476     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3477             iface, flags, clipper, outer_unknown);
3478 
3479     return ddraw7_CreateClipper(&ddraw->IDirectDraw7_iface, flags, clipper, outer_unknown);
3480 }
3481 
3482 static HRESULT WINAPI ddraw1_CreateClipper(IDirectDraw *iface,
3483         DWORD flags, IDirectDrawClipper **clipper, IUnknown *outer_unknown)
3484 {
3485     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3486 
3487     TRACE("iface %p, flags %#x, clipper %p, outer_unknown %p.\n",
3488             iface, flags, clipper, outer_unknown);
3489 
3490     return ddraw7_CreateClipper(&ddraw->IDirectDraw7_iface, flags, clipper, outer_unknown);
3491 }
3492 
3493 /*****************************************************************************
3494  * IDirectDraw7::CreatePalette
3495  *
3496  * Creates a new IDirectDrawPalette object
3497  *
3498  * Params:
3499  *  Flags: The flags for the new clipper
3500  *  ColorTable: Color table to assign to the new clipper
3501  *  Palette: Address to write the interface pointer to
3502  *  UnkOuter: For aggregation support, which ddraw doesn't have. Has to be
3503  *            NULL
3504  *
3505  * Returns:
3506  *  CLASS_E_NOAGGREGATION if UnkOuter != NULL
3507  *  E_OUTOFMEMORY if allocating the object failed
3508  *
3509  *****************************************************************************/
3510 static HRESULT WINAPI ddraw7_CreatePalette(IDirectDraw7 *iface, DWORD Flags,
3511         PALETTEENTRY *ColorTable, IDirectDrawPalette **Palette, IUnknown *pUnkOuter)
3512 {
3513     struct ddraw *ddraw = impl_from_IDirectDraw7(iface);
3514     struct ddraw_palette *object;
3515     HRESULT hr;
3516 
3517     TRACE("iface %p, flags %#x, color_table %p, palette %p, outer_unknown %p.\n",
3518             iface, Flags, ColorTable, Palette, pUnkOuter);
3519 
3520     if (pUnkOuter)
3521         return CLASS_E_NOAGGREGATION;
3522 
3523     wined3d_mutex_lock();
3524 
3525     /* The refcount test shows that a cooplevel is required for this */
3526     if (!ddraw->cooperative_level)
3527     {
3528         WARN("No cooperative level set, returning DDERR_NOCOOPERATIVELEVELSET\n");
3529         wined3d_mutex_unlock();
3530         return DDERR_NOCOOPERATIVELEVELSET;
3531     }
3532 
3533     if (!(object = heap_alloc(sizeof(*object))))
3534     {
3535         ERR("Out of memory when allocating memory for a palette implementation\n");
3536         wined3d_mutex_unlock();
3537         return E_OUTOFMEMORY;
3538     }
3539 
3540     hr = ddraw_palette_init(object, ddraw, Flags, ColorTable);
3541     if (FAILED(hr))
3542     {
3543         WARN("Failed to initialize palette, hr %#x.\n", hr);
3544         heap_free(object);
3545         wined3d_mutex_unlock();
3546         return hr;
3547     }
3548 
3549     TRACE("Created palette %p.\n", object);
3550     *Palette = &object->IDirectDrawPalette_iface;
3551     wined3d_mutex_unlock();
3552 
3553     return DD_OK;
3554 }
3555 
3556 static HRESULT WINAPI ddraw4_CreatePalette(IDirectDraw4 *iface, DWORD flags, PALETTEENTRY *entries,
3557         IDirectDrawPalette **palette, IUnknown *outer_unknown)
3558 {
3559     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3560     HRESULT hr;
3561 
3562     TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3563             iface, flags, entries, palette, outer_unknown);
3564 
3565     hr = ddraw7_CreatePalette(&ddraw->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3566     if (SUCCEEDED(hr) && *palette)
3567     {
3568         struct ddraw_palette *impl = impl_from_IDirectDrawPalette(*palette);
3569         IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
3570         IDirectDraw4_AddRef(iface);
3571         impl->ifaceToRelease = (IUnknown *)iface;
3572     }
3573     return hr;
3574 }
3575 
3576 static HRESULT WINAPI ddraw2_CreatePalette(IDirectDraw2 *iface, DWORD flags,
3577         PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3578 {
3579     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3580     HRESULT hr;
3581 
3582     TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3583             iface, flags, entries, palette, outer_unknown);
3584 
3585     hr = ddraw7_CreatePalette(&ddraw->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3586     if (SUCCEEDED(hr) && *palette)
3587     {
3588         struct ddraw_palette *impl = impl_from_IDirectDrawPalette(*palette);
3589         IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
3590         impl->ifaceToRelease = NULL;
3591     }
3592 
3593     return hr;
3594 }
3595 
3596 static HRESULT WINAPI ddraw1_CreatePalette(IDirectDraw *iface, DWORD flags,
3597         PALETTEENTRY *entries, IDirectDrawPalette **palette, IUnknown *outer_unknown)
3598 {
3599     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3600     HRESULT hr;
3601 
3602     TRACE("iface %p, flags %#x, entries %p, palette %p, outer_unknown %p.\n",
3603             iface, flags, entries, palette, outer_unknown);
3604 
3605     hr = ddraw7_CreatePalette(&ddraw->IDirectDraw7_iface, flags, entries, palette, outer_unknown);
3606     if (SUCCEEDED(hr) && *palette)
3607     {
3608         struct ddraw_palette *impl = impl_from_IDirectDrawPalette(*palette);
3609         IDirectDraw7_Release(&ddraw->IDirectDraw7_iface);
3610         impl->ifaceToRelease = NULL;
3611     }
3612 
3613     return hr;
3614 }
3615 
3616 /*****************************************************************************
3617  * IDirectDraw7::DuplicateSurface
3618  *
3619  * Duplicates a surface. The surface memory points to the same memory as
3620  * the original surface, and it's released when the last surface referencing
3621  * it is released. I guess that's beyond Wine's surface management right now
3622  * (Idea: create a new DDraw surface with the same WineD3DSurface. I need a
3623  * test application to implement this)
3624  *
3625  * Params:
3626  *  Src: Address of the source surface
3627  *  Dest: Address to write the new surface pointer to
3628  *
3629  * Returns:
3630  *  See IDirectDraw7::CreateSurface
3631  *
3632  *****************************************************************************/
3633 static HRESULT WINAPI ddraw7_DuplicateSurface(IDirectDraw7 *iface,
3634         IDirectDrawSurface7 *Src, IDirectDrawSurface7 **Dest)
3635 {
3636     struct ddraw_surface *src_surface = unsafe_impl_from_IDirectDrawSurface7(Src);
3637 
3638     FIXME("iface %p, src %p, dst %p partial stub!\n", iface, Src, Dest);
3639 
3640     /* For now, simply create a new, independent surface */
3641     return IDirectDraw7_CreateSurface(iface, &src_surface->surface_desc, Dest, NULL);
3642 }
3643 
3644 static HRESULT WINAPI ddraw4_DuplicateSurface(IDirectDraw4 *iface, IDirectDrawSurface4 *src,
3645         IDirectDrawSurface4 **dst)
3646 {
3647     struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface4(src);
3648     struct ddraw *ddraw = impl_from_IDirectDraw4(iface);
3649     struct ddraw_surface *dst_impl;
3650     IDirectDrawSurface7 *dst7;
3651     HRESULT hr;
3652 
3653     TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3654 
3655     hr = ddraw7_DuplicateSurface(&ddraw->IDirectDraw7_iface,
3656             src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3657     if (FAILED(hr))
3658     {
3659         *dst = NULL;
3660         return hr;
3661     }
3662     dst_impl = impl_from_IDirectDrawSurface7(dst7);
3663     *dst = &dst_impl->IDirectDrawSurface4_iface;
3664     IDirectDrawSurface4_AddRef(*dst);
3665     IDirectDrawSurface7_Release(dst7);
3666 
3667     return hr;
3668 }
3669 
3670 static HRESULT WINAPI ddraw2_DuplicateSurface(IDirectDraw2 *iface,
3671         IDirectDrawSurface *src, IDirectDrawSurface **dst)
3672 {
3673     struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface(src);
3674     struct ddraw *ddraw = impl_from_IDirectDraw2(iface);
3675     struct ddraw_surface *dst_impl;
3676     IDirectDrawSurface7 *dst7;
3677     HRESULT hr;
3678 
3679     TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3680 
3681     hr = ddraw7_DuplicateSurface(&ddraw->IDirectDraw7_iface,
3682             src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3683     if (FAILED(hr))
3684         return hr;
3685     dst_impl = impl_from_IDirectDrawSurface7(dst7);
3686     *dst = &dst_impl->IDirectDrawSurface_iface;
3687     IDirectDrawSurface_AddRef(*dst);
3688     IDirectDrawSurface7_Release(dst7);
3689 
3690     return hr;
3691 }
3692 
3693 static HRESULT WINAPI ddraw1_DuplicateSurface(IDirectDraw *iface, IDirectDrawSurface *src,
3694         IDirectDrawSurface **dst)
3695 {
3696     struct ddraw_surface *src_impl = unsafe_impl_from_IDirectDrawSurface(src);
3697     struct ddraw *ddraw = impl_from_IDirectDraw(iface);
3698     struct ddraw_surface *dst_impl;
3699     IDirectDrawSurface7 *dst7;
3700     HRESULT hr;
3701 
3702     TRACE("iface %p, src %p, dst %p.\n", iface, src, dst);
3703 
3704     hr = ddraw7_DuplicateSurface(&ddraw->IDirectDraw7_iface,
3705             src_impl ? &src_impl->IDirectDrawSurface7_iface : NULL, &dst7);
3706     if (FAILED(hr))
3707         return hr;
3708     dst_impl = impl_from_IDirectDrawSurface7(dst7);
3709     *dst = &dst_impl->IDirectDrawSurface_iface;
3710     IDirectDrawSurface_AddRef(*dst);
3711     IDirectDrawSurface7_Release(dst7);
3712 
3713     return hr;
3714 }
3715 
3716 /*****************************************************************************
3717  * IDirect3D7::EnumDevices
3718  *
3719  * The EnumDevices method for IDirect3D7. It enumerates all supported
3720  * D3D7 devices. Currently the T&L, HAL and RGB devices are enumerated.
3721  *
3722  * Params:
3723  *  callback: Function to call for each enumerated device
3724  *  context: Pointer to pass back to the app
3725  *
3726  * Returns:
3727  *  D3D_OK, or the return value of the GetCaps call
3728  *
3729  *****************************************************************************/
3730 static HRESULT WINAPI d3d7_EnumDevices(IDirect3D7 *iface, LPD3DENUMDEVICESCALLBACK7 callback, void *context)
3731 {
3732     struct ddraw *ddraw = impl_from_IDirect3D7(iface);
3733     D3DDEVICEDESC7 device_desc7;
3734     DWORD dev_caps;
3735     HRESULT hr;
3736     size_t i;
3737 
3738     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3739 
3740     if (!callback)
3741         return DDERR_INVALIDPARAMS;
3742 
3743     wined3d_mutex_lock();
3744 
3745     if (FAILED(hr = ddraw_get_d3dcaps(ddraw, &device_desc7)))
3746     {
3747         wined3d_mutex_unlock();
3748         return hr;
3749     }
3750 
3751     dev_caps = device_desc7.dwDevCaps;
3752 
3753     for (i = 0; i < ARRAY_SIZE(device_list7); i++)
3754     {
3755         HRESULT ret;
3756 
3757         device_desc7.deviceGUID = *device_list7[i].device_guid;
3758         device_desc7.dwDevCaps  = dev_caps & ~device_list7[i].remove_caps;
3759 
3760         ret = callback(device_list7[i].interface_name, device_list7[i].device_name, &device_desc7, context);
3761         if (ret != DDENUMRET_OK)
3762         {
3763             TRACE("Application cancelled the enumeration.\n");
3764             wined3d_mutex_unlock();
3765             return D3D_OK;
3766         }
3767     }
3768 
3769     TRACE("End of enumeration.\n");
3770 
3771     wined3d_mutex_unlock();
3772 
3773     return D3D_OK;
3774 }
3775 
3776 /*****************************************************************************
3777  * IDirect3D3::EnumDevices
3778  *
3779  * Enumerates all supported Direct3DDevice interfaces. This is the
3780  * implementation for Direct3D 1 to Direc3D 3, Version 7 has its own.
3781  *
3782  * Versions 1, 2 and 3
3783  *
3784  * Params:
3785  *  callback: Application-provided routine to call for each enumerated device
3786  *  Context: Pointer to pass to the callback
3787  *
3788  * Returns:
3789  *  D3D_OK on success,
3790  *  The result of IDirect3DImpl_GetCaps if it failed
3791  *
3792  *****************************************************************************/
3793 static HRESULT WINAPI d3d3_EnumDevices(IDirect3D3 *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3794 {
3795     static CHAR wined3d_description[] = "Wine D3DDevice using WineD3D and OpenGL";
3796 
3797     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
3798     D3DDEVICEDESC device_desc1, hal_desc, hel_desc;
3799     D3DDEVICEDESC7 device_desc7;
3800     HRESULT hr;
3801 
3802     /* Some games (Motoracer 2 demo) have the bad idea to modify the device
3803      * name string. Let's put the string in a sufficiently sized array in
3804      * writable memory. */
3805     char device_name[50];
3806     strcpy(device_name,"Direct3D HEL");
3807 
3808     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3809 
3810     if (!callback)
3811         return DDERR_INVALIDPARAMS;
3812 
3813     wined3d_mutex_lock();
3814 
3815     if (FAILED(hr = ddraw_get_d3dcaps(ddraw, &device_desc7)))
3816     {
3817         wined3d_mutex_unlock();
3818         return hr;
3819     }
3820     ddraw_d3dcaps1_from_7(&device_desc1, &device_desc7);
3821 
3822     /* Do I have to enumerate the reference id? Note from old d3d7:
3823      * "It seems that enumerating the reference IID on Direct3D 1 games
3824      * (AvP / Motoracer2) breaks them". So do not enumerate this iid in V1
3825      *
3826      * There's a registry key HKLM\Software\Microsoft\Direct3D\Drivers,
3827      * EnumReference which enables / disables enumerating the reference
3828      * rasterizer. It's a DWORD, 0 means disabled, 2 means enabled. The
3829      * enablerefrast.reg and disablerefrast.reg files in the DirectX 7.0 sdk
3830      * demo directory suggest this.
3831      *
3832      * Some games(GTA 2) seem to use the second enumerated device, so I have
3833      * to enumerate at least 2 devices. So enumerate the reference device to
3834      * have 2 devices.
3835      *
3836      * Other games (Rollcage) tell emulation and hal device apart by certain
3837      * flags. Rollcage expects D3DPTEXTURECAPS_POW2 to be set (yeah, it is a
3838      * limitation flag), and it refuses all devices that have the perspective
3839      * flag set. This way it refuses the emulation device, and HAL devices
3840      * never have POW2 unset in d3d7 on windows. */
3841     if (ddraw->d3dversion != 1)
3842     {
3843         static CHAR reference_description[] = "RGB Direct3D emulation";
3844 
3845         TRACE("Enumerating WineD3D D3DDevice interface.\n");
3846         hal_desc = device_desc1;
3847         hel_desc = device_desc1;
3848         /* The rgb device has the pow2 flag set in the hel caps, but not in the hal caps. */
3849         hal_desc.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3850                 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3851         hal_desc.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3852                 | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3853         /* RGB, RAMP and MMX devices have a HAL dcmColorModel of 0 */
3854         hal_desc.dcmColorModel = 0;
3855         /* RGB, RAMP and MMX devices cannot report HAL hardware flags */
3856         hal_desc.dwFlags = 0;
3857 
3858         hr = callback((GUID *)&IID_IDirect3DRGBDevice, reference_description,
3859                 device_name, &hal_desc, &hel_desc, context);
3860         if (hr != D3DENUMRET_OK)
3861         {
3862             TRACE("Application cancelled the enumeration.\n");
3863             wined3d_mutex_unlock();
3864             return D3D_OK;
3865         }
3866     }
3867 
3868     strcpy(device_name,"Direct3D HAL");
3869 
3870     TRACE("Enumerating HAL Direct3D device.\n");
3871     hal_desc = device_desc1;
3872     hel_desc = device_desc1;
3873 
3874     /* The hal device does not have the pow2 flag set in hel, but in hal. */
3875     hel_desc.dpcLineCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3876             | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3877     hel_desc.dpcTriCaps.dwTextureCaps &= ~(D3DPTEXTURECAPS_POW2
3878             | D3DPTEXTURECAPS_NONPOW2CONDITIONAL | D3DPTEXTURECAPS_PERSPECTIVE);
3879     /* HAL devices have a HEL dcmColorModel of 0 */
3880     hel_desc.dcmColorModel = 0;
3881 
3882     hr = callback((GUID *)&IID_IDirect3DHALDevice, wined3d_description,
3883             device_name, &hal_desc, &hel_desc, context);
3884     if (hr != D3DENUMRET_OK)
3885     {
3886         TRACE("Application cancelled the enumeration.\n");
3887         wined3d_mutex_unlock();
3888         return D3D_OK;
3889     }
3890 
3891     TRACE("End of enumeration.\n");
3892 
3893     wined3d_mutex_unlock();
3894 
3895     return D3D_OK;
3896 }
3897 
3898 static HRESULT WINAPI d3d2_EnumDevices(IDirect3D2 *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3899 {
3900     struct ddraw *ddraw = impl_from_IDirect3D2(iface);
3901 
3902     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3903 
3904     return d3d3_EnumDevices(&ddraw->IDirect3D3_iface, callback, context);
3905 }
3906 
3907 static HRESULT WINAPI d3d1_EnumDevices(IDirect3D *iface, LPD3DENUMDEVICESCALLBACK callback, void *context)
3908 {
3909     struct ddraw *ddraw = impl_from_IDirect3D(iface);
3910 
3911     TRACE("iface %p, callback %p, context %p.\n", iface, callback, context);
3912 
3913     return d3d3_EnumDevices(&ddraw->IDirect3D3_iface, callback, context);
3914 }
3915 
3916 /*****************************************************************************
3917  * IDirect3D3::CreateLight
3918  *
3919  * Creates an IDirect3DLight interface. This interface is used in
3920  * Direct3D3 or earlier for lighting. In Direct3D7 it has been replaced
3921  * by the DIRECT3DLIGHT7 structure. Wine's Direct3DLight implementation
3922  * uses the IDirect3DDevice7 interface with D3D7 lights.
3923  *
3924  * Versions 1, 2 and 3
3925  *
3926  * Params:
3927  *  light: Address to store the new interface pointer
3928  *  outer_unknown: Basically for aggregation, but ddraw doesn't support it.
3929  *                 Must be NULL
3930  *
3931  * Returns:
3932  *  D3D_OK on success
3933  *  DDERR_OUTOFMEMORY if memory allocation failed
3934  *  CLASS_E_NOAGGREGATION if outer_unknown != NULL
3935  *
3936  *****************************************************************************/
3937 static HRESULT WINAPI d3d3_CreateLight(IDirect3D3 *iface, IDirect3DLight **light,
3938         IUnknown *outer_unknown)
3939 {
3940     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
3941     struct d3d_light *object;
3942 
3943     TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
3944 
3945     if (outer_unknown)
3946         return CLASS_E_NOAGGREGATION;
3947 
3948     if (!(object = heap_alloc_zero(sizeof(*object))))
3949     {
3950         ERR("Failed to allocate light memory.\n");
3951         return DDERR_OUTOFMEMORY;
3952     }
3953 
3954     d3d_light_init(object, ddraw);
3955 
3956     TRACE("Created light %p.\n", object);
3957     *light = &object->IDirect3DLight_iface;
3958 
3959     return D3D_OK;
3960 }
3961 
3962 static HRESULT WINAPI d3d2_CreateLight(IDirect3D2 *iface, IDirect3DLight **light, IUnknown *outer_unknown)
3963 {
3964     struct ddraw *ddraw = impl_from_IDirect3D2(iface);
3965 
3966     TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
3967 
3968     return d3d3_CreateLight(&ddraw->IDirect3D3_iface, light, outer_unknown);
3969 }
3970 
3971 static HRESULT WINAPI d3d1_CreateLight(IDirect3D *iface, IDirect3DLight **light, IUnknown *outer_unknown)
3972 {
3973     struct ddraw *ddraw = impl_from_IDirect3D(iface);
3974 
3975     TRACE("iface %p, light %p, outer_unknown %p.\n", iface, light, outer_unknown);
3976 
3977     return d3d3_CreateLight(&ddraw->IDirect3D3_iface, light, outer_unknown);
3978 }
3979 
3980 /*****************************************************************************
3981  * IDirect3D3::CreateMaterial
3982  *
3983  * Creates an IDirect3DMaterial interface. This interface is used by Direct3D3
3984  * and older versions. The IDirect3DMaterial implementation wraps its
3985  * functionality to IDirect3DDevice7::SetMaterial and friends.
3986  *
3987  * Versions 1, 2 and 3
3988  *
3989  * Params:
3990  *  material: Address to store the new interface's pointer to
3991  *  outer_unknown: Basically for aggregation, but ddraw doesn't support it.
3992  *                 Must be NULL
3993  *
3994  * Returns:
3995  *  D3D_OK on success
3996  *  DDERR_OUTOFMEMORY if memory allocation failed
3997  *  CLASS_E_NOAGGREGATION if outer_unknown != NULL
3998  *
3999  *****************************************************************************/
4000 static HRESULT WINAPI d3d3_CreateMaterial(IDirect3D3 *iface, IDirect3DMaterial3 **material,
4001         IUnknown *outer_unknown)
4002 {
4003     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4004     struct d3d_material *object;
4005 
4006     TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4007 
4008     if (outer_unknown) return CLASS_E_NOAGGREGATION;
4009 
4010     object = d3d_material_create(ddraw);
4011     if (!object)
4012     {
4013         ERR("Failed to allocate material memory.\n");
4014         return DDERR_OUTOFMEMORY;
4015     }
4016 
4017     TRACE("Created material %p.\n", object);
4018     *material = &object->IDirect3DMaterial3_iface;
4019 
4020     return D3D_OK;
4021 }
4022 
4023 static HRESULT WINAPI d3d2_CreateMaterial(IDirect3D2 *iface, IDirect3DMaterial2 **material,
4024         IUnknown *outer_unknown)
4025 {
4026     struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4027     struct d3d_material *object;
4028 
4029     TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4030 
4031     object = d3d_material_create(ddraw);
4032     if (!object)
4033     {
4034         ERR("Failed to allocate material memory.\n");
4035         return DDERR_OUTOFMEMORY;
4036     }
4037 
4038     TRACE("Created material %p.\n", object);
4039     *material = &object->IDirect3DMaterial2_iface;
4040 
4041     return D3D_OK;
4042 }
4043 
4044 static HRESULT WINAPI d3d1_CreateMaterial(IDirect3D *iface, IDirect3DMaterial **material,
4045         IUnknown *outer_unknown)
4046 {
4047     struct ddraw *ddraw = impl_from_IDirect3D(iface);
4048     struct d3d_material *object;
4049 
4050     TRACE("iface %p, material %p, outer_unknown %p.\n", iface, material, outer_unknown);
4051 
4052     object = d3d_material_create(ddraw);
4053     if (!object)
4054     {
4055         ERR("Failed to allocate material memory.\n");
4056         return DDERR_OUTOFMEMORY;
4057     }
4058 
4059     TRACE("Created material %p.\n", object);
4060     *material = &object->IDirect3DMaterial_iface;
4061 
4062     return D3D_OK;
4063 }
4064 
4065 /*****************************************************************************
4066  * IDirect3D3::CreateViewport
4067  *
4068  * Creates an IDirect3DViewport interface. This interface is used
4069  * by Direct3D and earlier versions for Viewport management. In Direct3D7
4070  * it has been replaced by a viewport structure and
4071  * IDirect3DDevice7::*Viewport. Wine's IDirect3DViewport implementation
4072  * uses the IDirect3DDevice7 methods for its functionality
4073  *
4074  * Params:
4075  *  Viewport: Address to store the new interface pointer
4076  *  outer_unknown: Basically for aggregation, but ddraw doesn't support it.
4077  *                 Must be NULL
4078  *
4079  * Returns:
4080  *  D3D_OK on success
4081  *  DDERR_OUTOFMEMORY if memory allocation failed
4082  *  CLASS_E_NOAGGREGATION if outer_unknown != NULL
4083  *
4084  *****************************************************************************/
4085 static HRESULT WINAPI d3d3_CreateViewport(IDirect3D3 *iface, IDirect3DViewport3 **viewport,
4086         IUnknown *outer_unknown)
4087 {
4088     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4089     struct d3d_viewport *object;
4090 
4091     TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4092 
4093     if (outer_unknown) return CLASS_E_NOAGGREGATION;
4094 
4095     if (!(object = heap_alloc_zero(sizeof(*object))))
4096     {
4097         ERR("Failed to allocate viewport memory.\n");
4098         return DDERR_OUTOFMEMORY;
4099     }
4100 
4101     d3d_viewport_init(object, ddraw);
4102 
4103     TRACE("Created viewport %p.\n", object);
4104     *viewport = &object->IDirect3DViewport3_iface;
4105 
4106     return D3D_OK;
4107 }
4108 
4109 static HRESULT WINAPI d3d2_CreateViewport(IDirect3D2 *iface, IDirect3DViewport2 **viewport, IUnknown *outer_unknown)
4110 {
4111     struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4112 
4113     TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4114 
4115     return d3d3_CreateViewport(&ddraw->IDirect3D3_iface, (IDirect3DViewport3 **)viewport,
4116             outer_unknown);
4117 }
4118 
4119 static HRESULT WINAPI d3d1_CreateViewport(IDirect3D *iface, IDirect3DViewport **viewport, IUnknown *outer_unknown)
4120 {
4121     struct ddraw *ddraw = impl_from_IDirect3D(iface);
4122 
4123     TRACE("iface %p, viewport %p, outer_unknown %p.\n", iface, viewport, outer_unknown);
4124 
4125     return d3d3_CreateViewport(&ddraw->IDirect3D3_iface, (IDirect3DViewport3 **)viewport,
4126             outer_unknown);
4127 }
4128 
4129 /*****************************************************************************
4130  * IDirect3D3::FindDevice
4131  *
4132  * This method finds a device with the requested properties and returns a
4133  * device description
4134  *
4135  * Versions 1, 2 and 3
4136  * Params:
4137  *  fds: Describes the requested device characteristics
4138  *  fdr: Returns the device description
4139  *
4140  * Returns:
4141  *  D3D_OK on success
4142  *  DDERR_INVALIDPARAMS if no device was found
4143  *
4144  *****************************************************************************/
4145 static HRESULT WINAPI d3d3_FindDevice(IDirect3D3 *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4146 {
4147     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4148     D3DDEVICEDESC7 desc7;
4149     D3DDEVICEDESC desc1;
4150     HRESULT hr;
4151 
4152     TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4153 
4154     if (!fds || !fdr) return DDERR_INVALIDPARAMS;
4155 
4156     if (fds->dwSize != sizeof(D3DFINDDEVICESEARCH) || (fdr->dwSize != sizeof(D3DFINDDEVICERESULT1) &&
4157         fdr->dwSize != sizeof(D3DFINDDEVICERESULT2) && fdr->dwSize != sizeof(D3DFINDDEVICERESULT)))
4158         return DDERR_INVALIDPARAMS;
4159 
4160     if ((fds->dwFlags & D3DFDS_COLORMODEL)
4161             && fds->dcmColorModel != D3DCOLOR_RGB)
4162     {
4163         WARN("Trying to request a non-RGB D3D color model. Not supported.\n");
4164         return DDERR_INVALIDPARAMS; /* No real idea what to return here :-) */
4165     }
4166 
4167     if (fds->dwFlags & D3DFDS_GUID)
4168     {
4169         TRACE("Trying to match guid %s.\n", debugstr_guid(&(fds->guid)));
4170         if (!IsEqualGUID(&IID_D3DDEVICE_WineD3D, &fds->guid)
4171                 && !IsEqualGUID(&IID_IDirect3DHALDevice, &fds->guid)
4172                 && !IsEqualGUID(&IID_IDirect3DRGBDevice, &fds->guid))
4173         {
4174             WARN("No match for this GUID.\n");
4175             return DDERR_NOTFOUND;
4176         }
4177     }
4178 
4179     /* Get the caps */
4180     if (FAILED(hr = ddraw_get_d3dcaps(ddraw, &desc7)))
4181         return hr;
4182 
4183     /* Now return our own GUID */
4184     ddraw_d3dcaps1_from_7(&desc1, &desc7);
4185     fdr->guid = IID_D3DDEVICE_WineD3D;
4186 
4187     if (fdr->dwSize == sizeof(D3DFINDDEVICERESULT1))
4188     {
4189         D3DFINDDEVICERESULT1 *fdr1 = (D3DFINDDEVICERESULT1 *)fdr;
4190         memcpy(&fdr1->ddHwDesc, &desc1, sizeof(fdr1->ddHwDesc));
4191         memcpy(&fdr1->ddSwDesc, &desc1, sizeof(fdr1->ddSwDesc));
4192     }
4193     else if (fdr->dwSize == sizeof(D3DFINDDEVICERESULT2))
4194     {
4195         D3DFINDDEVICERESULT2 *fdr2 = (D3DFINDDEVICERESULT2 *)fdr;
4196         memcpy(&fdr2->ddHwDesc, &desc1, sizeof(fdr2->ddHwDesc));
4197         memcpy(&fdr2->ddSwDesc, &desc1, sizeof(fdr2->ddSwDesc));
4198     }
4199     else
4200     {
4201         fdr->ddHwDesc = desc1;
4202         fdr->ddSwDesc = desc1;
4203     }
4204 
4205     TRACE("Returning Wine's wined3d device with (undumped) capabilities.\n");
4206 
4207     return D3D_OK;
4208 }
4209 
4210 static HRESULT WINAPI d3d2_FindDevice(IDirect3D2 *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4211 {
4212     struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4213 
4214     TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4215 
4216     return d3d3_FindDevice(&ddraw->IDirect3D3_iface, fds, fdr);
4217 }
4218 
4219 static HRESULT WINAPI d3d1_FindDevice(IDirect3D *iface, D3DFINDDEVICESEARCH *fds, D3DFINDDEVICERESULT *fdr)
4220 {
4221     struct ddraw *ddraw = impl_from_IDirect3D(iface);
4222 
4223     TRACE("iface %p, fds %p, fdr %p.\n", iface, fds, fdr);
4224 
4225     return d3d3_FindDevice(&ddraw->IDirect3D3_iface, fds, fdr);
4226 }
4227 
4228 /*****************************************************************************
4229  * IDirect3D7::CreateDevice
4230  *
4231  * Creates an IDirect3DDevice7 interface.
4232  *
4233  * Versions 2, 3 and 7. IDirect3DDevice 1 interfaces are interfaces to
4234  * DirectDraw surfaces and are created with
4235  * IDirectDrawSurface::QueryInterface. This method uses CreateDevice to
4236  * create the device object and QueryInterfaces for IDirect3DDevice
4237  *
4238  * Params:
4239  *  refiid: IID of the device to create
4240  *  Surface: Initial rendertarget
4241  *  Device: Address to return the interface pointer
4242  *
4243  * Returns:
4244  *  D3D_OK on success
4245  *  DDERR_OUTOFMEMORY if memory allocation failed
4246  *  DDERR_INVALIDPARAMS if a device exists already
4247  *
4248  *****************************************************************************/
4249 static HRESULT WINAPI d3d7_CreateDevice(IDirect3D7 *iface, REFCLSID riid,
4250         IDirectDrawSurface7 *surface, IDirect3DDevice7 **device)
4251 {
4252     struct ddraw_surface *target = unsafe_impl_from_IDirectDrawSurface7(surface);
4253     struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4254     struct d3d_device *object;
4255     HRESULT hr;
4256 
4257     TRACE("iface %p, riid %s, surface %p, device %p.\n", iface, debugstr_guid(riid), surface, device);
4258 
4259     wined3d_mutex_lock();
4260     if (SUCCEEDED(hr = d3d_device_create(ddraw, riid, target, (IUnknown *)surface, 7, &object, NULL)))
4261     {
4262         *device = &object->IDirect3DDevice7_iface;
4263     }
4264     else
4265     {
4266         WARN("Failed to create device, hr %#x.\n", hr);
4267         *device = NULL;
4268     }
4269     wined3d_mutex_unlock();
4270 
4271     return hr;
4272 }
4273 
4274 static HRESULT WINAPI d3d3_CreateDevice(IDirect3D3 *iface, REFCLSID riid,
4275         IDirectDrawSurface4 *surface, IDirect3DDevice3 **device, IUnknown *outer_unknown)
4276 {
4277     struct ddraw_surface *surface_impl = unsafe_impl_from_IDirectDrawSurface4(surface);
4278     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4279     struct d3d_device *device_impl;
4280     HRESULT hr;
4281 
4282     TRACE("iface %p, riid %s, surface %p, device %p, outer_unknown %p.\n",
4283             iface, debugstr_guid(riid), surface, device, outer_unknown);
4284 
4285     if (outer_unknown)
4286         return CLASS_E_NOAGGREGATION;
4287 
4288     wined3d_mutex_lock();
4289     if (SUCCEEDED(hr = d3d_device_create(ddraw, riid, surface_impl, (IUnknown *)surface, 3, &device_impl, NULL)))
4290     {
4291         *device = &device_impl->IDirect3DDevice3_iface;
4292     }
4293     else
4294     {
4295         WARN("Failed to create device, hr %#x.\n", hr);
4296         *device = NULL;
4297     }
4298     wined3d_mutex_unlock();
4299 
4300     return hr;
4301 }
4302 
4303 static HRESULT WINAPI d3d2_CreateDevice(IDirect3D2 *iface, REFCLSID riid,
4304         IDirectDrawSurface *surface, IDirect3DDevice2 **device)
4305 {
4306     struct ddraw_surface *surface_impl = unsafe_impl_from_IDirectDrawSurface(surface);
4307     struct ddraw *ddraw = impl_from_IDirect3D2(iface);
4308     struct d3d_device *device_impl;
4309     HRESULT hr;
4310 
4311     TRACE("iface %p, riid %s, surface %p, device %p.\n",
4312             iface, debugstr_guid(riid), surface, device);
4313 
4314     wined3d_mutex_lock();
4315     if (SUCCEEDED(hr = d3d_device_create(ddraw, riid, surface_impl, (IUnknown *)surface, 2, &device_impl, NULL)))
4316     {
4317         *device = &device_impl->IDirect3DDevice2_iface;
4318     }
4319     else
4320     {
4321         WARN("Failed to create device, hr %#x.\n", hr);
4322         *device = NULL;
4323     }
4324     wined3d_mutex_unlock();
4325 
4326     return hr;
4327 }
4328 
4329 /*****************************************************************************
4330  * IDirect3D7::CreateVertexBuffer
4331  *
4332  * Creates a new vertex buffer object and returns a IDirect3DVertexBuffer7
4333  * interface.
4334  *
4335  * Versions 3 and 7
4336  *
4337  * Params:
4338  *  desc: Requested Vertex buffer properties
4339  *  vertex_buffer: Address to return the interface pointer at
4340  *  flags: Some flags, should be 0
4341  *
4342  * Returns
4343  *  D3D_OK on success
4344  *  DDERR_OUTOFMEMORY if memory allocation failed
4345  *  DDERR_INVALIDPARAMS if desc or vertex_buffer is NULL
4346  *
4347  *****************************************************************************/
4348 static HRESULT WINAPI d3d7_CreateVertexBuffer(IDirect3D7 *iface, D3DVERTEXBUFFERDESC *desc,
4349         IDirect3DVertexBuffer7 **vertex_buffer, DWORD flags)
4350 {
4351     struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4352     struct d3d_vertex_buffer *object;
4353     HRESULT hr;
4354 
4355     TRACE("iface %p, desc %p, vertex_buffer %p, flags %#x.\n",
4356             iface, desc, vertex_buffer, flags);
4357 
4358     if (!vertex_buffer || !desc) return DDERR_INVALIDPARAMS;
4359 
4360     hr = d3d_vertex_buffer_create(&object, ddraw, desc);
4361     if (hr == D3D_OK)
4362     {
4363         TRACE("Created vertex buffer %p.\n", object);
4364         *vertex_buffer = &object->IDirect3DVertexBuffer7_iface;
4365     }
4366     else
4367         WARN("Failed to create vertex buffer, hr %#x.\n", hr);
4368 
4369     return hr;
4370 }
4371 
4372 static HRESULT WINAPI d3d3_CreateVertexBuffer(IDirect3D3 *iface, D3DVERTEXBUFFERDESC *desc,
4373         IDirect3DVertexBuffer **vertex_buffer, DWORD flags, IUnknown *outer_unknown)
4374 {
4375     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4376     struct d3d_vertex_buffer *object;
4377     HRESULT hr;
4378 
4379     TRACE("iface %p, desc %p, vertex_buffer %p, flags %#x, outer_unknown %p.\n",
4380             iface, desc, vertex_buffer, flags, outer_unknown);
4381 
4382     if (outer_unknown)
4383         return CLASS_E_NOAGGREGATION;
4384     if (!vertex_buffer || !desc)
4385         return DDERR_INVALIDPARAMS;
4386 
4387     hr = d3d_vertex_buffer_create(&object, ddraw, desc);
4388     if (hr == D3D_OK)
4389     {
4390         TRACE("Created vertex buffer %p.\n", object);
4391         *vertex_buffer = (IDirect3DVertexBuffer *)&object->IDirect3DVertexBuffer7_iface;
4392     }
4393     else
4394         WARN("Failed to create vertex buffer, hr %#x.\n", hr);
4395 
4396     return hr;
4397 }
4398 
4399 /*****************************************************************************
4400  * IDirect3D7::EnumZBufferFormats
4401  *
4402  * Enumerates all supported Z buffer pixel formats
4403  *
4404  * Versions 3 and 7
4405  *
4406  * Params:
4407  *  device_iid:
4408  *  callback: callback to call for each pixel format
4409  *  context: Pointer to pass back to the callback
4410  *
4411  * Returns:
4412  *  D3D_OK on success
4413  *  DDERR_INVALIDPARAMS if callback is NULL
4414  *
4415  *****************************************************************************/
4416 static HRESULT WINAPI d3d7_EnumZBufferFormats(IDirect3D7 *iface, REFCLSID device_iid,
4417         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
4418 {
4419     struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4420     struct wined3d_display_mode mode;
4421     enum wined3d_device_type type;
4422     unsigned int i;
4423     HRESULT hr;
4424 
4425     /* Order matters. Specifically, BattleZone II (full version) expects the
4426      * 16-bit depth formats to be listed before the 24 and 32 ones. */
4427     static const enum wined3d_format_id formats[] =
4428     {
4429         WINED3DFMT_S1_UINT_D15_UNORM,
4430         WINED3DFMT_D16_UNORM,
4431         WINED3DFMT_X8D24_UNORM,
4432         WINED3DFMT_S4X4_UINT_D24_UNORM,
4433         WINED3DFMT_D24_UNORM_S8_UINT,
4434         WINED3DFMT_D32_UNORM,
4435     };
4436 
4437     TRACE("iface %p, device_iid %s, callback %p, context %p.\n",
4438             iface, debugstr_guid(device_iid), callback, context);
4439 
4440     if (!callback) return DDERR_INVALIDPARAMS;
4441 
4442     if (IsEqualGUID(device_iid, &IID_IDirect3DHALDevice)
4443             || IsEqualGUID(device_iid, &IID_IDirect3DTnLHalDevice)
4444             || IsEqualGUID(device_iid, &IID_D3DDEVICE_WineD3D))
4445     {
4446         TRACE("Asked for HAL device.\n");
4447         type = WINED3D_DEVICE_TYPE_HAL;
4448     }
4449     else if (IsEqualGUID(device_iid, &IID_IDirect3DRGBDevice)
4450             || IsEqualGUID(device_iid, &IID_IDirect3DMMXDevice))
4451     {
4452         TRACE("Asked for SW device.\n");
4453         type = WINED3D_DEVICE_TYPE_SW;
4454     }
4455     else if (IsEqualGUID(device_iid, &IID_IDirect3DRefDevice))
4456     {
4457         TRACE("Asked for REF device.\n");
4458         type = WINED3D_DEVICE_TYPE_REF;
4459     }
4460     else if (IsEqualGUID(device_iid, &IID_IDirect3DNullDevice))
4461     {
4462         TRACE("Asked for NULLREF device.\n");
4463         type = WINED3D_DEVICE_TYPE_NULLREF;
4464     }
4465     else
4466     {
4467         FIXME("Unexpected device GUID %s.\n", debugstr_guid(device_iid));
4468         type = WINED3D_DEVICE_TYPE_HAL;
4469     }
4470 
4471     wined3d_mutex_lock();
4472     /* We need an adapter format from somewhere to please wined3d and WGL.
4473      * Use the current display mode. So far all cards offer the same depth
4474      * stencil format for all modes, but if some do not and applications do
4475      * not like that we'll have to find some workaround, like iterating over
4476      * all imaginable formats and collecting all the depth stencil formats we
4477      * can get. */
4478     if (FAILED(hr = wined3d_get_adapter_display_mode(ddraw->wined3d, WINED3DADAPTER_DEFAULT, &mode, NULL)))
4479     {
4480         ERR("Failed to get display mode, hr %#x.\n", hr);
4481         wined3d_mutex_unlock();
4482         return hr;
4483     }
4484 
4485     for (i = 0; i < ARRAY_SIZE(formats); ++i)
4486     {
4487         if (SUCCEEDED(wined3d_check_device_format(ddraw->wined3d, WINED3DADAPTER_DEFAULT, type, mode.format_id,
4488                 WINED3DUSAGE_DEPTHSTENCIL, WINED3D_RTYPE_TEXTURE_2D, formats[i])))
4489         {
4490             DDPIXELFORMAT pformat;
4491 
4492             memset(&pformat, 0, sizeof(pformat));
4493             pformat.dwSize = sizeof(pformat);
4494             ddrawformat_from_wined3dformat(&pformat, formats[i]);
4495 
4496             TRACE("Enumerating wined3d format %#x.\n", formats[i]);
4497             hr = callback(&pformat, context);
4498             if (hr != DDENUMRET_OK)
4499             {
4500                 TRACE("Format enumeration cancelled by application.\n");
4501                 wined3d_mutex_unlock();
4502                 return D3D_OK;
4503             }
4504         }
4505     }
4506 
4507     /* Historically some windows drivers used dwZBufferBitDepth=24 for WINED3DFMT_X8D24_UNORM,
4508      * while others used dwZBufferBitDepth=32. In either case the pitch matches a 32 bits per
4509      * pixel format, so we use dwZBufferBitDepth=32. Some games expect 24. Windows Vista and
4510      * newer enumerate both versions, so we do the same(bug 22434) */
4511     if (SUCCEEDED(wined3d_check_device_format(ddraw->wined3d, WINED3DADAPTER_DEFAULT, type, mode.format_id,
4512             WINED3DUSAGE_DEPTHSTENCIL, WINED3D_RTYPE_TEXTURE_2D, WINED3DFMT_X8D24_UNORM)))
4513     {
4514         DDPIXELFORMAT x8d24 =
4515         {
4516             sizeof(x8d24), DDPF_ZBUFFER, 0,
4517             {24}, {0x00000000}, {0x00ffffff}, {0x00000000}
4518         };
4519         TRACE("Enumerating WINED3DFMT_X8D24_UNORM, dwZBufferBitDepth=24 version\n");
4520         callback(&x8d24, context);
4521     }
4522 
4523     TRACE("End of enumeration.\n");
4524 
4525     wined3d_mutex_unlock();
4526 
4527     return D3D_OK;
4528 }
4529 
4530 static HRESULT WINAPI d3d3_EnumZBufferFormats(IDirect3D3 *iface, REFCLSID device_iid,
4531         LPD3DENUMPIXELFORMATSCALLBACK callback, void *context)
4532 {
4533     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4534 
4535     TRACE("iface %p, device_iid %s, callback %p, context %p.\n",
4536             iface, debugstr_guid(device_iid), callback, context);
4537 
4538     return d3d7_EnumZBufferFormats(&ddraw->IDirect3D7_iface, device_iid, callback, context);
4539 }
4540 
4541 /*****************************************************************************
4542  * IDirect3D7::EvictManagedTextures
4543  *
4544  * Removes all managed textures (=surfaces with DDSCAPS2_TEXTUREMANAGE or
4545  * DDSCAPS2_D3DTEXTUREMANAGE caps) to be removed from video memory.
4546  *
4547  * Versions 3 and 7
4548  *
4549  * Returns:
4550  *  D3D_OK, because it's a stub
4551  *
4552  *****************************************************************************/
4553 static HRESULT WINAPI d3d7_EvictManagedTextures(IDirect3D7 *iface)
4554 {
4555     struct ddraw *ddraw = impl_from_IDirect3D7(iface);
4556 
4557     TRACE("iface %p!\n", iface);
4558 
4559     wined3d_mutex_lock();
4560     if (ddraw->flags & DDRAW_D3D_INITIALIZED)
4561         wined3d_device_evict_managed_resources(ddraw->wined3d_device);
4562     wined3d_mutex_unlock();
4563 
4564     return D3D_OK;
4565 }
4566 
4567 static HRESULT WINAPI d3d3_EvictManagedTextures(IDirect3D3 *iface)
4568 {
4569     struct ddraw *ddraw = impl_from_IDirect3D3(iface);
4570 
4571     TRACE("iface %p.\n", iface);
4572 
4573     return d3d7_EvictManagedTextures(&ddraw->IDirect3D7_iface);
4574 }
4575 
4576 /*****************************************************************************
4577  * IDirectDraw7 VTable
4578  *****************************************************************************/
4579 static const struct IDirectDraw7Vtbl ddraw7_vtbl =
4580 {
4581     /* IUnknown */
4582     ddraw7_QueryInterface,
4583     ddraw7_AddRef,
4584     ddraw7_Release,
4585     /* IDirectDraw */
4586     ddraw7_Compact,
4587     ddraw7_CreateClipper,
4588     ddraw7_CreatePalette,
4589     ddraw7_CreateSurface,
4590     ddraw7_DuplicateSurface,
4591     ddraw7_EnumDisplayModes,
4592     ddraw7_EnumSurfaces,
4593     ddraw7_FlipToGDISurface,
4594     ddraw7_GetCaps,
4595     ddraw7_GetDisplayMode,
4596     ddraw7_GetFourCCCodes,
4597     ddraw7_GetGDISurface,
4598     ddraw7_GetMonitorFrequency,
4599     ddraw7_GetScanLine,
4600     ddraw7_GetVerticalBlankStatus,
4601     ddraw7_Initialize,
4602     ddraw7_RestoreDisplayMode,
4603     ddraw7_SetCooperativeLevel,
4604     ddraw7_SetDisplayMode,
4605     ddraw7_WaitForVerticalBlank,
4606     /* IDirectDraw2 */
4607     ddraw7_GetAvailableVidMem,
4608     /* IDirectDraw3 */
4609     ddraw7_GetSurfaceFromDC,
4610     /* IDirectDraw4 */
4611     ddraw7_RestoreAllSurfaces,
4612     ddraw7_TestCooperativeLevel,
4613     ddraw7_GetDeviceIdentifier,
4614     /* IDirectDraw7 */
4615     ddraw7_StartModeTest,
4616     ddraw7_EvaluateMode
4617 };
4618 
4619 static const struct IDirectDraw4Vtbl ddraw4_vtbl =
4620 {
4621     /* IUnknown */
4622     ddraw4_QueryInterface,
4623     ddraw4_AddRef,
4624     ddraw4_Release,
4625     /* IDirectDraw */
4626     ddraw4_Compact,
4627     ddraw4_CreateClipper,
4628     ddraw4_CreatePalette,
4629     ddraw4_CreateSurface,
4630     ddraw4_DuplicateSurface,
4631     ddraw4_EnumDisplayModes,
4632     ddraw4_EnumSurfaces,
4633     ddraw4_FlipToGDISurface,
4634     ddraw4_GetCaps,
4635     ddraw4_GetDisplayMode,
4636     ddraw4_GetFourCCCodes,
4637     ddraw4_GetGDISurface,
4638     ddraw4_GetMonitorFrequency,
4639     ddraw4_GetScanLine,
4640     ddraw4_GetVerticalBlankStatus,
4641     ddraw4_Initialize,
4642     ddraw4_RestoreDisplayMode,
4643     ddraw4_SetCooperativeLevel,
4644     ddraw4_SetDisplayMode,
4645     ddraw4_WaitForVerticalBlank,
4646     /* IDirectDraw2 */
4647     ddraw4_GetAvailableVidMem,
4648     /* IDirectDraw3 */
4649     ddraw4_GetSurfaceFromDC,
4650     /* IDirectDraw4 */
4651     ddraw4_RestoreAllSurfaces,
4652     ddraw4_TestCooperativeLevel,
4653     ddraw4_GetDeviceIdentifier,
4654 };
4655 
4656 static const struct IDirectDraw2Vtbl ddraw2_vtbl =
4657 {
4658     /* IUnknown */
4659     ddraw2_QueryInterface,
4660     ddraw2_AddRef,
4661     ddraw2_Release,
4662     /* IDirectDraw */
4663     ddraw2_Compact,
4664     ddraw2_CreateClipper,
4665     ddraw2_CreatePalette,
4666     ddraw2_CreateSurface,
4667     ddraw2_DuplicateSurface,
4668     ddraw2_EnumDisplayModes,
4669     ddraw2_EnumSurfaces,
4670     ddraw2_FlipToGDISurface,
4671     ddraw2_GetCaps,
4672     ddraw2_GetDisplayMode,
4673     ddraw2_GetFourCCCodes,
4674     ddraw2_GetGDISurface,
4675     ddraw2_GetMonitorFrequency,
4676     ddraw2_GetScanLine,
4677     ddraw2_GetVerticalBlankStatus,
4678     ddraw2_Initialize,
4679     ddraw2_RestoreDisplayMode,
4680     ddraw2_SetCooperativeLevel,
4681     ddraw2_SetDisplayMode,
4682     ddraw2_WaitForVerticalBlank,
4683     /* IDirectDraw2 */
4684     ddraw2_GetAvailableVidMem,
4685 };
4686 
4687 static struct IDirectDrawVtbl ddraw1_vtbl =
4688 {
4689     /* IUnknown */
4690     ddraw1_QueryInterface,
4691     ddraw1_AddRef,
4692     ddraw1_Release,
4693     /* IDirectDraw */
4694     ddraw1_Compact,
4695     ddraw1_CreateClipper,
4696     ddraw1_CreatePalette,
4697     ddraw1_CreateSurface,
4698     ddraw1_DuplicateSurface,
4699     ddraw1_EnumDisplayModes,
4700     ddraw1_EnumSurfaces,
4701     ddraw1_FlipToGDISurface,
4702     ddraw1_GetCaps,
4703     ddraw1_GetDisplayMode,
4704     ddraw1_GetFourCCCodes,
4705     ddraw1_GetGDISurface,
4706     ddraw1_GetMonitorFrequency,
4707     ddraw1_GetScanLine,
4708     ddraw1_GetVerticalBlankStatus,
4709     ddraw1_Initialize,
4710     ddraw1_RestoreDisplayMode,
4711     ddraw1_SetCooperativeLevel,
4712     ddraw1_SetDisplayMode,
4713     ddraw1_WaitForVerticalBlank,
4714 };
4715 
4716 static const struct IDirect3D7Vtbl d3d7_vtbl =
4717 {
4718     /* IUnknown methods */
4719     d3d7_QueryInterface,
4720     d3d7_AddRef,
4721     d3d7_Release,
4722     /* IDirect3D7 methods */
4723     d3d7_EnumDevices,
4724     d3d7_CreateDevice,
4725     d3d7_CreateVertexBuffer,
4726     d3d7_EnumZBufferFormats,
4727     d3d7_EvictManagedTextures
4728 };
4729 
4730 static const struct IDirect3D3Vtbl d3d3_vtbl =
4731 {
4732     /* IUnknown methods */
4733     d3d3_QueryInterface,
4734     d3d3_AddRef,
4735     d3d3_Release,
4736     /* IDirect3D3 methods */
4737     d3d3_EnumDevices,
4738     d3d3_CreateLight,
4739     d3d3_CreateMaterial,
4740     d3d3_CreateViewport,
4741     d3d3_FindDevice,
4742     d3d3_CreateDevice,
4743     d3d3_CreateVertexBuffer,
4744     d3d3_EnumZBufferFormats,
4745     d3d3_EvictManagedTextures
4746 };
4747 
4748 static const struct IDirect3D2Vtbl d3d2_vtbl =
4749 {
4750     /* IUnknown methods */
4751     d3d2_QueryInterface,
4752     d3d2_AddRef,
4753     d3d2_Release,
4754     /* IDirect3D2 methods */
4755     d3d2_EnumDevices,
4756     d3d2_CreateLight,
4757     d3d2_CreateMaterial,
4758     d3d2_CreateViewport,
4759     d3d2_FindDevice,
4760     d3d2_CreateDevice
4761 };
4762 
4763 static const struct IDirect3DVtbl d3d1_vtbl =
4764 {
4765     /* IUnknown methods */
4766     d3d1_QueryInterface,
4767     d3d1_AddRef,
4768     d3d1_Release,
4769     /* IDirect3D methods */
4770     d3d1_Initialize,
4771     d3d1_EnumDevices,
4772     d3d1_CreateLight,
4773     d3d1_CreateMaterial,
4774     d3d1_CreateViewport,
4775     d3d1_FindDevice
4776 };
4777 
4778 /*****************************************************************************
4779  * ddraw_find_decl
4780  *
4781  * Finds the WineD3D vertex declaration for a specific fvf, and creates one
4782  * if none was found.
4783  *
4784  * This function is in ddraw.c and the DDraw object space because D3D7
4785  * vertex buffers are created using the IDirect3D interface to the ddraw
4786  * object, so they can be valid across D3D devices(theoretically. The ddraw
4787  * object also owns the wined3d device
4788  *
4789  * Parameters:
4790  *  This: Device
4791  *  fvf: Fvf to find the decl for
4792  *
4793  * Returns:
4794  *  NULL in case of an error, the vertex declaration for the FVF otherwise.
4795  *
4796  *****************************************************************************/
4797 struct wined3d_vertex_declaration *ddraw_find_decl(struct ddraw *This, DWORD fvf)
4798 {
4799     struct wined3d_vertex_declaration *pDecl = NULL;
4800     HRESULT hr;
4801     int p, low, high; /* deliberately signed */
4802     struct FvfToDecl *convertedDecls = This->decls;
4803 
4804     TRACE("Searching for declaration for fvf %08x... ", fvf);
4805 
4806     low = 0;
4807     high = This->numConvertedDecls - 1;
4808     while(low <= high) {
4809         p = (low + high) >> 1;
4810         TRACE("%d ", p);
4811         if(convertedDecls[p].fvf == fvf) {
4812             TRACE("found %p\n", convertedDecls[p].decl);
4813             return convertedDecls[p].decl;
4814         } else if(convertedDecls[p].fvf < fvf) {
4815             low = p + 1;
4816         } else {
4817             high = p - 1;
4818         }
4819     }
4820     TRACE("not found. Creating and inserting at position %d.\n", low);
4821 
4822     hr = wined3d_vertex_declaration_create_from_fvf(This->wined3d_device,
4823             fvf, This, &ddraw_null_wined3d_parent_ops, &pDecl);
4824     if (hr != S_OK) return NULL;
4825 
4826     if (This->declArraySize == This->numConvertedDecls)
4827     {
4828         unsigned int grow = max(This->declArraySize / 2, 8);
4829 
4830         if (!(convertedDecls = heap_realloc(convertedDecls,
4831                 (This->numConvertedDecls + grow) * sizeof(*convertedDecls))))
4832         {
4833             wined3d_vertex_declaration_decref(pDecl);
4834             return NULL;
4835         }
4836         This->decls = convertedDecls;
4837         This->declArraySize += grow;
4838     }
4839 
4840     memmove(convertedDecls + low + 1, convertedDecls + low, sizeof(convertedDecls[0]) * (This->numConvertedDecls - low));
4841     convertedDecls[low].decl = pDecl;
4842     convertedDecls[low].fvf = fvf;
4843     This->numConvertedDecls++;
4844 
4845     TRACE("Returning %p. %d decls in array\n", pDecl, This->numConvertedDecls);
4846     return pDecl;
4847 }
4848 
4849 static inline struct ddraw *ddraw_from_device_parent(struct wined3d_device_parent *device_parent)
4850 {
4851     return CONTAINING_RECORD(device_parent, struct ddraw, device_parent);
4852 }
4853 
4854 static void CDECL device_parent_wined3d_device_created(struct wined3d_device_parent *device_parent,
4855         struct wined3d_device *device)
4856 {
4857     TRACE("device_parent %p, device %p.\n", device_parent, device);
4858 }
4859 
4860 /* This is run from device_process_message() in wined3d, we can't take the
4861  * wined3d mutex. */
4862 /* FIXME: We only get mode change notifications in exclusive mode, but we
4863  * should mark surfaces as lost on mode changes in DDSCL_NORMAL mode as well. */
4864 static void CDECL device_parent_mode_changed(struct wined3d_device_parent *device_parent)
4865 {
4866     struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
4867     MONITORINFO monitor_info;
4868     HMONITOR monitor;
4869     RECT *r;
4870 
4871     TRACE("device_parent %p.\n", device_parent);
4872 
4873     if (!(ddraw->cooperative_level & DDSCL_EXCLUSIVE) || !ddraw->swapchain_window)
4874     {
4875         TRACE("Nothing to resize.\n");
4876         return;
4877     }
4878 
4879     monitor = MonitorFromWindow(ddraw->swapchain_window, MONITOR_DEFAULTTOPRIMARY);
4880     monitor_info.cbSize = sizeof(monitor_info);
4881     if (!GetMonitorInfoW(monitor, &monitor_info))
4882     {
4883         ERR("Failed to get monitor info.\n");
4884         return;
4885     }
4886 
4887     r = &monitor_info.rcMonitor;
4888     TRACE("Resizing window %p to %s.\n", ddraw->swapchain_window, wine_dbgstr_rect(r));
4889 
4890     if (!SetWindowPos(ddraw->swapchain_window, HWND_TOP, r->left, r->top,
4891                       r->right - r->left, r->bottom - r->top, SWP_SHOWWINDOW | SWP_NOACTIVATE))
4892         ERR("Failed to resize window.\n");
4893 
4894     InterlockedCompareExchange(&ddraw->device_state, DDRAW_DEVICE_STATE_NOT_RESTORED, DDRAW_DEVICE_STATE_OK);
4895 }
4896 
4897 static void CDECL device_parent_activate(struct wined3d_device_parent *device_parent, BOOL activate)
4898 {
4899     struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
4900 
4901     TRACE("device_parent %p, activate %#x.\n", device_parent, activate);
4902 
4903     if (!activate)
4904     {
4905         ddraw->device_state = DDRAW_DEVICE_STATE_LOST;
4906         exclusive_window = NULL;
4907     }
4908     else
4909     {
4910         InterlockedCompareExchange(&ddraw->device_state, DDRAW_DEVICE_STATE_NOT_RESTORED, DDRAW_DEVICE_STATE_LOST);
4911     }
4912 }
4913 
4914 void ddraw_update_lost_surfaces(struct ddraw *ddraw)
4915 {
4916     struct ddraw_surface *surface;
4917 
4918     if (ddraw->device_state != DDRAW_DEVICE_STATE_NOT_RESTORED)
4919         return;
4920 
4921     LIST_FOR_EACH_ENTRY(surface, &ddraw->surface_list, struct ddraw_surface, surface_list_entry)
4922     {
4923         surface->is_lost = TRUE;
4924     }
4925     ddraw->device_state = DDRAW_DEVICE_STATE_OK;
4926 }
4927 
4928 static HRESULT CDECL device_parent_surface_created(struct wined3d_device_parent *device_parent,
4929         struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
4930         void **parent, const struct wined3d_parent_ops **parent_ops)
4931 {
4932     struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
4933     struct ddraw_surface *ddraw_surface;
4934 
4935     TRACE("device_parent %p, wined3d_texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
4936             device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
4937 
4938     /* We have a swapchain or wined3d internal texture. */
4939     if (!wined3d_texture_get_parent(wined3d_texture) || wined3d_texture_get_parent(wined3d_texture) == ddraw)
4940     {
4941         *parent = NULL;
4942         *parent_ops = &ddraw_null_wined3d_parent_ops;
4943 
4944         return DD_OK;
4945     }
4946 
4947     if (!(ddraw_surface = heap_alloc_zero(sizeof(*ddraw_surface))))
4948     {
4949         ERR("Failed to allocate surface memory.\n");
4950         return DDERR_OUTOFVIDEOMEMORY;
4951     }
4952 
4953     ddraw_surface_init(ddraw_surface, ddraw, wined3d_texture, sub_resource_idx, parent_ops);
4954     *parent = ddraw_surface;
4955 
4956     ddraw_update_lost_surfaces(ddraw);
4957     list_add_head(&ddraw->surface_list, &ddraw_surface->surface_list_entry);
4958 
4959     TRACE("Created ddraw surface %p.\n", ddraw_surface);
4960 
4961     return DD_OK;
4962 }
4963 
4964 static HRESULT CDECL device_parent_volume_created(struct wined3d_device_parent *device_parent,
4965         struct wined3d_texture *wined3d_texture, unsigned int sub_resource_idx,
4966         void **parent, const struct wined3d_parent_ops **parent_ops)
4967 {
4968     TRACE("device_parent %p, texture %p, sub_resource_idx %u, parent %p, parent_ops %p.\n",
4969             device_parent, wined3d_texture, sub_resource_idx, parent, parent_ops);
4970 
4971     *parent = NULL;
4972     *parent_ops = &ddraw_null_wined3d_parent_ops;
4973 
4974     return DD_OK;
4975 }
4976 
4977 static void STDMETHODCALLTYPE ddraw_frontbuffer_destroyed(void *parent)
4978 {
4979     struct ddraw *ddraw = parent;
4980     ddraw->wined3d_frontbuffer = NULL;
4981 }
4982 
4983 static const struct wined3d_parent_ops ddraw_frontbuffer_parent_ops =
4984 {
4985     ddraw_frontbuffer_destroyed,
4986 };
4987 
4988 static HRESULT CDECL device_parent_create_swapchain_texture(struct wined3d_device_parent *device_parent,
4989         void *container_parent, const struct wined3d_resource_desc *desc, DWORD texture_flags,
4990         struct wined3d_texture **texture)
4991 {
4992     struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
4993     HRESULT hr;
4994 
4995     TRACE("device_parent %p, container_parent %p, desc %p, texture flags %#x, texture %p.\n",
4996             device_parent, container_parent, desc, texture_flags, texture);
4997 
4998     if (ddraw->wined3d_frontbuffer)
4999     {
5000         ERR("Frontbuffer already created.\n");
5001         return E_FAIL;
5002     }
5003 
5004     if (FAILED(hr = wined3d_texture_create(ddraw->wined3d_device, desc, 1, 1,
5005             texture_flags | WINED3D_TEXTURE_CREATE_MAPPABLE, NULL, ddraw, &ddraw_frontbuffer_parent_ops, texture)))
5006     {
5007         WARN("Failed to create texture, hr %#x.\n", hr);
5008         return hr;
5009     }
5010 
5011     ddraw->wined3d_frontbuffer = *texture;
5012 
5013     return hr;
5014 }
5015 
5016 static HRESULT CDECL device_parent_create_swapchain(struct wined3d_device_parent *device_parent,
5017         struct wined3d_swapchain_desc *desc, struct wined3d_swapchain **swapchain)
5018 {
5019     struct ddraw *ddraw = ddraw_from_device_parent(device_parent);
5020     HRESULT hr;
5021 
5022     TRACE("device_parent %p, desc %p, swapchain %p.\n", device_parent, desc, swapchain);
5023 
5024     if (ddraw->wined3d_swapchain)
5025     {
5026         ERR("Swapchain already created.\n");
5027         return E_FAIL;
5028     }
5029 
5030     if (FAILED(hr = wined3d_swapchain_create(ddraw->wined3d_device, desc, NULL,
5031             &ddraw_null_wined3d_parent_ops, swapchain)))
5032         WARN("Failed to create swapchain, hr %#x.\n", hr);
5033 
5034     return hr;
5035 }
5036 
5037 static const struct wined3d_device_parent_ops ddraw_wined3d_device_parent_ops =
5038 {
5039     device_parent_wined3d_device_created,
5040     device_parent_mode_changed,
5041     device_parent_activate,
5042     device_parent_surface_created,
5043     device_parent_volume_created,
5044     device_parent_create_swapchain_texture,
5045     device_parent_create_swapchain,
5046 };
5047 
5048 HRESULT ddraw_init(struct ddraw *ddraw, DWORD flags, enum wined3d_device_type device_type)
5049 {
5050     WINED3DCAPS caps;
5051     HRESULT hr;
5052 
5053     ddraw->IDirectDraw7_iface.lpVtbl = &ddraw7_vtbl;
5054     ddraw->IDirectDraw_iface.lpVtbl = &ddraw1_vtbl;
5055     ddraw->IDirectDraw2_iface.lpVtbl = &ddraw2_vtbl;
5056     ddraw->IDirectDraw4_iface.lpVtbl = &ddraw4_vtbl;
5057     ddraw->IDirect3D_iface.lpVtbl = &d3d1_vtbl;
5058     ddraw->IDirect3D2_iface.lpVtbl = &d3d2_vtbl;
5059     ddraw->IDirect3D3_iface.lpVtbl = &d3d3_vtbl;
5060     ddraw->IDirect3D7_iface.lpVtbl = &d3d7_vtbl;
5061     ddraw->device_parent.ops = &ddraw_wined3d_device_parent_ops;
5062     ddraw->numIfaces = 1;
5063     ddraw->ref7 = 1;
5064 
5065     flags |= DDRAW_WINED3D_FLAGS;
5066     if (!(ddraw->wined3d = wined3d_create(flags)))
5067     {
5068         flags |= WINED3D_NO3D;
5069         if (!(ddraw->wined3d = wined3d_create(flags)))
5070         {
5071             WARN("Failed to create a wined3d object.\n");
5072             return E_FAIL;
5073         }
5074     }
5075 
5076     if (FAILED(hr = wined3d_get_device_caps(ddraw->wined3d, WINED3DADAPTER_DEFAULT, device_type, &caps)))
5077     {
5078         ERR("Failed to get device caps, hr %#x.\n", hr);
5079         wined3d_decref(ddraw->wined3d);
5080         return E_FAIL;
5081     }
5082 
5083     if (!(caps.ddraw_caps.caps & WINEDDCAPS_3D))
5084     {
5085         WARN("Created a wined3d object without 3D support.\n");
5086         ddraw->flags |= DDRAW_NO3D;
5087     }
5088 
5089     if (FAILED(hr = wined3d_device_create(ddraw->wined3d, WINED3DADAPTER_DEFAULT, device_type,
5090             NULL, 0, DDRAW_STRIDE_ALIGNMENT, &ddraw->device_parent, &ddraw->wined3d_device)))
5091     {
5092         WARN("Failed to create a wined3d device, hr %#x.\n", hr);
5093         wined3d_decref(ddraw->wined3d);
5094         return hr;
5095     }
5096 
5097     list_init(&ddraw->surface_list);
5098 
5099     return DD_OK;
5100 }
5101