wined3d: Take scanline ordering into account in the mode setting code.
[wine] / dlls / d3d9 / directx.c
1 /*
2  * IDirect3D9 implementation
3  *
4  * Copyright 2002 Jason Edmeades
5  * Copyright 2005 Oliver Stieber
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "d3d9_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
26
27 static inline struct d3d9 *impl_from_IDirect3D9Ex(IDirect3D9Ex *iface)
28 {
29     return CONTAINING_RECORD(iface, struct d3d9, IDirect3D9Ex_iface);
30 }
31
32 static HRESULT WINAPI d3d9_QueryInterface(IDirect3D9Ex *iface, REFIID riid, void **out)
33 {
34     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
35
36     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
37
38     if (IsEqualGUID(riid, &IID_IDirect3D9)
39             || IsEqualGUID(riid, &IID_IUnknown))
40     {
41         IDirect3D9Ex_AddRef(&d3d9->IDirect3D9Ex_iface);
42         *out = &d3d9->IDirect3D9Ex_iface;
43         return S_OK;
44     }
45
46     if (IsEqualGUID(riid, &IID_IDirect3D9Ex))
47     {
48         if (!d3d9->extended)
49         {
50             WARN("Application asks for IDirect3D9Ex, but this instance wasn't created with Direct3DCreate9Ex.\n");
51             *out = NULL;
52             return E_NOINTERFACE;
53         }
54
55         IDirect3D9Ex_AddRef(&d3d9->IDirect3D9Ex_iface);
56         *out = &d3d9->IDirect3D9Ex_iface;
57         return S_OK;
58     }
59
60     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
61
62     *out = NULL;
63     return E_NOINTERFACE;
64 }
65
66 static ULONG WINAPI d3d9_AddRef(IDirect3D9Ex *iface)
67 {
68     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
69     ULONG refcount = InterlockedIncrement(&d3d9->refcount);
70
71     TRACE("%p increasing refcount to %u.\n", iface, refcount);
72
73     return refcount;
74 }
75
76 static ULONG WINAPI d3d9_Release(IDirect3D9Ex *iface)
77 {
78     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
79     ULONG refcount = InterlockedDecrement(&d3d9->refcount);
80
81     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
82
83     if (!refcount)
84     {
85         wined3d_mutex_lock();
86         wined3d_decref(d3d9->wined3d);
87         wined3d_mutex_unlock();
88
89         HeapFree(GetProcessHeap(), 0, d3d9);
90     }
91
92     return refcount;
93 }
94
95 static HRESULT WINAPI d3d9_RegisterSoftwareDevice(IDirect3D9Ex *iface, void *init_function)
96 {
97     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
98     HRESULT hr;
99
100     TRACE("iface %p, init_function %p.\n", iface, init_function);
101
102     wined3d_mutex_lock();
103     hr = wined3d_register_software_device(d3d9->wined3d, init_function);
104     wined3d_mutex_unlock();
105
106     return hr;
107 }
108
109 static UINT WINAPI d3d9_GetAdapterCount(IDirect3D9Ex *iface)
110 {
111     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
112     UINT ret;
113
114     TRACE("iface %p.\n", iface);
115
116     wined3d_mutex_lock();
117     ret = wined3d_get_adapter_count(d3d9->wined3d);
118     wined3d_mutex_unlock();
119
120     return ret;
121 }
122
123 static HRESULT WINAPI d3d9_GetAdapterIdentifier(IDirect3D9Ex *iface, UINT adapter,
124         DWORD flags, D3DADAPTER_IDENTIFIER9 *identifier)
125 {
126     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
127     struct wined3d_adapter_identifier adapter_id;
128     HRESULT hr;
129
130     TRACE("iface %p, adapter %u, flags %#x, identifier %p.\n",
131             iface, adapter, flags, identifier);
132
133     adapter_id.driver = identifier->Driver;
134     adapter_id.driver_size = sizeof(identifier->Driver);
135     adapter_id.description = identifier->Description;
136     adapter_id.description_size = sizeof(identifier->Description);
137     adapter_id.device_name = identifier->DeviceName;
138     adapter_id.device_name_size = sizeof(identifier->DeviceName);
139
140     wined3d_mutex_lock();
141     hr = wined3d_get_adapter_identifier(d3d9->wined3d, adapter, flags, &adapter_id);
142     wined3d_mutex_unlock();
143
144     identifier->DriverVersion = adapter_id.driver_version;
145     identifier->VendorId = adapter_id.vendor_id;
146     identifier->DeviceId = adapter_id.device_id;
147     identifier->SubSysId = adapter_id.subsystem_id;
148     identifier->Revision = adapter_id.revision;
149     memcpy(&identifier->DeviceIdentifier, &adapter_id.device_identifier, sizeof(identifier->DeviceIdentifier));
150     identifier->WHQLLevel = adapter_id.whql_level;
151
152     return hr;
153 }
154
155 static UINT WINAPI d3d9_GetAdapterModeCount(IDirect3D9Ex *iface, UINT adapter, D3DFORMAT format)
156 {
157     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
158     UINT ret;
159
160     TRACE("iface %p, adapter %u, format %#x.\n", iface, adapter, format);
161
162     /* Others than that not supported by d3d9, but reported by wined3d for ddraw. Filter them out. */
163     if (format != D3DFMT_X8R8G8B8 && format != D3DFMT_R5G6B5)
164         return 0;
165
166     wined3d_mutex_lock();
167     ret = wined3d_get_adapter_mode_count(d3d9->wined3d, adapter, wined3dformat_from_d3dformat(format));
168     wined3d_mutex_unlock();
169
170     return ret;
171 }
172
173 static HRESULT WINAPI d3d9_EnumAdapterModes(IDirect3D9Ex *iface, UINT adapter,
174         D3DFORMAT format, UINT mode_idx, D3DDISPLAYMODE *mode)
175 {
176     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
177     struct wined3d_display_mode wined3d_mode;
178     HRESULT hr;
179
180     TRACE("iface %p, adapter %u, format %#x, mode_idx %u, mode %p.\n",
181             iface, adapter, format, mode_idx, mode);
182
183     if (format != D3DFMT_X8R8G8B8 && format != D3DFMT_R5G6B5)
184         return D3DERR_INVALIDCALL;
185
186     wined3d_mutex_lock();
187     hr = wined3d_enum_adapter_modes(d3d9->wined3d, adapter, wined3dformat_from_d3dformat(format),
188             mode_idx, &wined3d_mode);
189     wined3d_mutex_unlock();
190
191     if (SUCCEEDED(hr))
192     {
193         mode->Width = wined3d_mode.width;
194         mode->Height = wined3d_mode.height;
195         mode->RefreshRate = wined3d_mode.refresh_rate;
196         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
197     }
198
199     return hr;
200 }
201
202 static HRESULT WINAPI d3d9_GetAdapterDisplayMode(IDirect3D9Ex *iface, UINT adapter, D3DDISPLAYMODE *mode)
203 {
204     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
205     struct wined3d_display_mode wined3d_mode;
206     HRESULT hr;
207
208     TRACE("iface %p, adapter %u, mode %p.\n", iface, adapter, mode);
209
210     wined3d_mutex_lock();
211     hr = wined3d_get_adapter_display_mode(d3d9->wined3d, adapter, &wined3d_mode);
212     wined3d_mutex_unlock();
213
214     if (SUCCEEDED(hr))
215     {
216         mode->Width = wined3d_mode.width;
217         mode->Height = wined3d_mode.height;
218         mode->RefreshRate = wined3d_mode.refresh_rate;
219         mode->Format = d3dformat_from_wined3dformat(wined3d_mode.format_id);
220     }
221
222     return hr;
223 }
224
225 static HRESULT WINAPI d3d9_CheckDeviceType(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
226         D3DFORMAT display_format, D3DFORMAT backbuffer_format, BOOL windowed)
227 {
228     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
229     HRESULT hr;
230
231     TRACE("iface %p, adapter %u, device_type %#x, display_format %#x, backbuffer_format %#x, windowed %#x.\n",
232             iface, adapter, device_type, display_format, backbuffer_format, windowed);
233
234     wined3d_mutex_lock();
235     hr = wined3d_check_device_type(d3d9->wined3d, adapter, device_type, wined3dformat_from_d3dformat(display_format),
236             wined3dformat_from_d3dformat(backbuffer_format), windowed);
237     wined3d_mutex_unlock();
238
239     return hr;
240 }
241
242 static HRESULT WINAPI d3d9_CheckDeviceFormat(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
243         D3DFORMAT adapter_format, DWORD usage, D3DRESOURCETYPE resource_type, D3DFORMAT format)
244 {
245     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
246     enum wined3d_resource_type wined3d_rtype;
247     HRESULT hr;
248
249     TRACE("iface %p, adapter %u, device_type %#x, adapter_format %#x, usage %#x, resource_type %#x, format %#x.\n",
250             iface, adapter, device_type, adapter_format, usage, resource_type, format);
251
252     switch (resource_type)
253     {
254         case D3DRTYPE_VERTEXBUFFER:
255         case D3DRTYPE_INDEXBUFFER:
256             wined3d_rtype = WINED3D_RTYPE_BUFFER;
257             break;
258
259         default:
260             wined3d_rtype = resource_type;
261             break;
262     }
263
264     wined3d_mutex_lock();
265     hr = wined3d_check_device_format(d3d9->wined3d, adapter, device_type, wined3dformat_from_d3dformat(adapter_format),
266             usage, wined3d_rtype, wined3dformat_from_d3dformat(format), WINED3D_SURFACE_TYPE_OPENGL);
267     wined3d_mutex_unlock();
268
269     return hr;
270 }
271
272 static HRESULT WINAPI d3d9_CheckDeviceMultiSampleType(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
273         D3DFORMAT format, BOOL windowed, D3DMULTISAMPLE_TYPE multisample_type, DWORD *levels)
274 {
275     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
276     HRESULT hr;
277
278     TRACE("iface %p, adapter %u, device_type %#x, format %#x, windowed %#x, multisample_type %#x, levels %p.\n",
279             iface, adapter, device_type, format, windowed, multisample_type, levels);
280
281     wined3d_mutex_lock();
282     hr = wined3d_check_device_multisample_type(d3d9->wined3d, adapter, device_type,
283             wined3dformat_from_d3dformat(format), windowed, multisample_type, levels);
284     wined3d_mutex_unlock();
285
286     return hr;
287 }
288
289 static HRESULT WINAPI d3d9_CheckDepthStencilMatch(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
290         D3DFORMAT adapter_format, D3DFORMAT rt_format, D3DFORMAT ds_format)
291 {
292     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
293     HRESULT hr;
294
295     TRACE("iface %p, adapter %u, device_type %#x, adapter_format %#x, rt_format %#x, ds_format %#x.\n",
296             iface, adapter, device_type, adapter_format, rt_format, ds_format);
297
298     wined3d_mutex_lock();
299     hr = wined3d_check_depth_stencil_match(d3d9->wined3d, adapter, device_type,
300             wined3dformat_from_d3dformat(adapter_format), wined3dformat_from_d3dformat(rt_format),
301             wined3dformat_from_d3dformat(ds_format));
302     wined3d_mutex_unlock();
303
304     return hr;
305 }
306
307 static HRESULT WINAPI d3d9_CheckDeviceFormatConversion(IDirect3D9Ex *iface, UINT adapter,
308         D3DDEVTYPE device_type, D3DFORMAT src_format, D3DFORMAT dst_format)
309 {
310     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
311     HRESULT hr;
312
313     TRACE("iface %p, adapter %u, device_type %#x, src_format %#x, dst_format %#x.\n",
314             iface, adapter, device_type, src_format, dst_format);
315
316     wined3d_mutex_lock();
317     hr = wined3d_check_device_format_conversion(d3d9->wined3d, adapter, device_type,
318             wined3dformat_from_d3dformat(src_format), wined3dformat_from_d3dformat(dst_format));
319     wined3d_mutex_unlock();
320
321     return hr;
322 }
323
324 void filter_caps(D3DCAPS9* pCaps)
325 {
326     DWORD ps_minor_version[] = {0, 4, 0, 0};
327     DWORD vs_minor_version[] = {0, 1, 0, 0};
328     DWORD textureFilterCaps =
329         D3DPTFILTERCAPS_MINFPOINT      | D3DPTFILTERCAPS_MINFLINEAR    | D3DPTFILTERCAPS_MINFANISOTROPIC |
330         D3DPTFILTERCAPS_MINFPYRAMIDALQUAD                              | D3DPTFILTERCAPS_MINFGAUSSIANQUAD|
331         D3DPTFILTERCAPS_MIPFPOINT      | D3DPTFILTERCAPS_MIPFLINEAR    | D3DPTFILTERCAPS_MAGFPOINT       |
332         D3DPTFILTERCAPS_MAGFLINEAR     |D3DPTFILTERCAPS_MAGFANISOTROPIC|D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD|
333         D3DPTFILTERCAPS_MAGFGAUSSIANQUAD;
334     pCaps->TextureFilterCaps &= textureFilterCaps;
335     pCaps->CubeTextureFilterCaps &= textureFilterCaps;
336     pCaps->VolumeTextureFilterCaps &= textureFilterCaps;
337
338     pCaps->DevCaps &=
339         D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY |
340         D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY| D3DDEVCAPS_TEXTUREVIDEOMEMORY   |
341         D3DDEVCAPS_DRAWPRIMTLVERTEX    | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM|
342         D3DDEVCAPS_DRAWPRIMITIVES2     | D3DDEVCAPS_SEPARATETEXTUREMEMORIES                              |
343         D3DDEVCAPS_DRAWPRIMITIVES2EX   | D3DDEVCAPS_HWTRANSFORMANDLIGHT| D3DDEVCAPS_CANBLTSYSTONONLOCAL  |
344         D3DDEVCAPS_HWRASTERIZATION     | D3DDEVCAPS_PUREDEVICE         | D3DDEVCAPS_QUINTICRTPATCHES     |
345         D3DDEVCAPS_RTPATCHES           | D3DDEVCAPS_RTPATCHHANDLEZERO  | D3DDEVCAPS_NPATCHES;
346
347     pCaps->ShadeCaps &=
348         D3DPSHADECAPS_COLORGOURAUDRGB  | D3DPSHADECAPS_SPECULARGOURAUDRGB |
349         D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_FOGGOURAUD;
350
351     pCaps->RasterCaps &=
352         D3DPRASTERCAPS_DITHER          | D3DPRASTERCAPS_ZTEST          | D3DPRASTERCAPS_FOGVERTEX        |
353         D3DPRASTERCAPS_FOGTABLE        | D3DPRASTERCAPS_MIPMAPLODBIAS  | D3DPRASTERCAPS_ZBUFFERLESSHSR   |
354         D3DPRASTERCAPS_FOGRANGE        | D3DPRASTERCAPS_ANISOTROPY     | D3DPRASTERCAPS_WBUFFER          |
355         D3DPRASTERCAPS_WFOG            | D3DPRASTERCAPS_ZFOG           | D3DPRASTERCAPS_COLORPERSPECTIVE |
356         D3DPRASTERCAPS_SCISSORTEST     | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS                              |
357         D3DPRASTERCAPS_DEPTHBIAS       | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;
358
359     pCaps->DevCaps2 &=
360         D3DDEVCAPS2_STREAMOFFSET       | D3DDEVCAPS2_DMAPNPATCH        | D3DDEVCAPS2_ADAPTIVETESSRTPATCH |
361         D3DDEVCAPS2_ADAPTIVETESSNPATCH | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES                       |
362         D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
363
364     pCaps->Caps2 &=
365         D3DCAPS2_FULLSCREENGAMMA       | D3DCAPS2_CANCALIBRATEGAMMA    | D3DCAPS2_RESERVED               |
366         D3DCAPS2_CANMANAGERESOURCE     | D3DCAPS2_DYNAMICTEXTURES      | D3DCAPS2_CANAUTOGENMIPMAP;
367
368     pCaps->VertexProcessingCaps &=
369         D3DVTXPCAPS_TEXGEN             | D3DVTXPCAPS_MATERIALSOURCE7   | D3DVTXPCAPS_DIRECTIONALLIGHTS   |
370         D3DVTXPCAPS_POSITIONALLIGHTS   | D3DVTXPCAPS_LOCALVIEWER       | D3DVTXPCAPS_TWEENING            |
371         D3DVTXPCAPS_TEXGEN_SPHEREMAP   | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER;
372
373     pCaps->TextureCaps &=
374         D3DPTEXTURECAPS_PERSPECTIVE    | D3DPTEXTURECAPS_POW2          | D3DPTEXTURECAPS_ALPHA           |
375         D3DPTEXTURECAPS_SQUAREONLY     | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE                        |
376         D3DPTEXTURECAPS_ALPHAPALETTE   | D3DPTEXTURECAPS_NONPOW2CONDITIONAL                              |
377         D3DPTEXTURECAPS_PROJECTED      | D3DPTEXTURECAPS_CUBEMAP       | D3DPTEXTURECAPS_VOLUMEMAP       |
378         D3DPTEXTURECAPS_MIPMAP         | D3DPTEXTURECAPS_MIPVOLUMEMAP  | D3DPTEXTURECAPS_MIPCUBEMAP      |
379         D3DPTEXTURECAPS_CUBEMAP_POW2   | D3DPTEXTURECAPS_VOLUMEMAP_POW2| D3DPTEXTURECAPS_NOPROJECTEDBUMPENV;
380
381     pCaps->MaxVertexShaderConst = min(D3D9_MAX_VERTEX_SHADER_CONSTANTF, pCaps->MaxVertexShaderConst);
382     pCaps->NumSimultaneousRTs = min(D3D9_MAX_SIMULTANEOUS_RENDERTARGETS, pCaps->NumSimultaneousRTs);
383
384     if (pCaps->PixelShaderVersion > 3)
385         pCaps->PixelShaderVersion = D3DPS_VERSION(3,0);
386     else
387     {
388         DWORD major = pCaps->PixelShaderVersion;
389         pCaps->PixelShaderVersion = D3DPS_VERSION(major,ps_minor_version[major]);
390     }
391
392     if (pCaps->VertexShaderVersion > 3)
393         pCaps->VertexShaderVersion = D3DVS_VERSION(3,0);
394     else
395     {
396         DWORD major = pCaps->VertexShaderVersion;
397         pCaps->VertexShaderVersion = D3DVS_VERSION(major,vs_minor_version[major]);
398     }
399 }
400
401 static HRESULT WINAPI d3d9_GetDeviceCaps(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type, D3DCAPS9 *caps)
402 {
403     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
404     WINED3DCAPS *wined3d_caps;
405     HRESULT hr;
406
407     TRACE("iface %p, adapter %u, device_type %#x, caps %p.\n", iface, adapter, device_type, caps);
408
409     if (!caps)
410         return D3DERR_INVALIDCALL;
411
412     if (!(wined3d_caps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINED3DCAPS))))
413         return D3DERR_INVALIDCALL; /*well this is what MSDN says to return*/
414     memset(caps, 0, sizeof(*caps));
415
416     wined3d_mutex_lock();
417     hr = wined3d_get_device_caps(d3d9->wined3d, adapter, device_type, wined3d_caps);
418     wined3d_mutex_unlock();
419
420     WINECAPSTOD3D9CAPS(caps, wined3d_caps)
421     HeapFree(GetProcessHeap(), 0, wined3d_caps);
422
423     /* Some functionality is implemented in d3d9.dll, not wined3d.dll. Add the needed caps */
424     caps->DevCaps2 |= D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES;
425
426     filter_caps(caps);
427
428     return hr;
429 }
430
431 static HMONITOR WINAPI d3d9_GetAdapterMonitor(IDirect3D9Ex *iface, UINT adapter)
432 {
433     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
434     HMONITOR ret;
435
436     TRACE("iface %p, adapter %u.\n", iface, adapter);
437
438     wined3d_mutex_lock();
439     ret = wined3d_get_adapter_monitor(d3d9->wined3d, adapter);
440     wined3d_mutex_unlock();
441
442     return ret;
443 }
444
445 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_CreateDevice(IDirect3D9Ex *iface, UINT adapter,
446         D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters,
447         IDirect3DDevice9 **device)
448 {
449     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
450     struct d3d9_device *object;
451     HRESULT hr;
452
453     TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, device %p.\n",
454             iface, adapter, device_type, focus_window, flags, parameters, device);
455
456     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
457     if (!object)
458     {
459         ERR("Failed to allocate device memory.\n");
460         return E_OUTOFMEMORY;
461     }
462
463     hr = device_init(object, d3d9, d3d9->wined3d, adapter, device_type, focus_window, flags, parameters, NULL);
464     if (FAILED(hr))
465     {
466         WARN("Failed to initialize device, hr %#x.\n", hr);
467         HeapFree(GetProcessHeap(), 0, object);
468         return hr;
469     }
470
471     TRACE("Created device %p.\n", object);
472     *device = (IDirect3DDevice9 *)object;
473
474     return D3D_OK;
475 }
476
477 static UINT WINAPI d3d9_GetAdapterModeCountEx(IDirect3D9Ex *iface,
478         UINT adapter, const D3DDISPLAYMODEFILTER *filter)
479 {
480     FIXME("iface %p, adapter %u, filter %p stub!\n", iface, adapter, filter);
481
482     return 0;
483 }
484
485 static HRESULT WINAPI d3d9_EnumAdapterModesEx(IDirect3D9Ex *iface,
486         UINT adapter, const D3DDISPLAYMODEFILTER *filter, UINT mode_idx, D3DDISPLAYMODEEX *mode)
487 {
488     FIXME("iface %p, adapter %u, filter %p, mode_idx %u, mode %p stub!\n",
489             iface, adapter, filter, mode_idx, mode);
490
491     return E_NOTIMPL;
492 }
493
494 static HRESULT WINAPI d3d9_GetAdapterDisplayModeEx(IDirect3D9Ex *iface,
495         UINT adapter, D3DDISPLAYMODEEX *mode, D3DDISPLAYROTATION *rotation)
496 {
497     FIXME("iface %p, adapter %u, mode %p, rotation %p stub!\n",
498             iface, adapter, mode, rotation);
499
500     return E_NOTIMPL;
501 }
502
503 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_CreateDeviceEx(IDirect3D9Ex *iface,
504         UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags,
505         D3DPRESENT_PARAMETERS *parameters, D3DDISPLAYMODEEX *mode, IDirect3DDevice9Ex **device)
506 {
507     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
508     struct d3d9_device *object;
509     HRESULT hr;
510
511     TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, mode %p, device %p.\n",
512             iface, adapter, device_type, focus_window, flags, parameters, mode, device);
513
514     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
515     if (!object)
516     {
517         ERR("Failed to allocate device memory.\n");
518         return E_OUTOFMEMORY;
519     }
520
521     hr = device_init(object, d3d9, d3d9->wined3d, adapter, device_type, focus_window, flags, parameters, mode);
522     if (FAILED(hr))
523     {
524         WARN("Failed to initialize device, hr %#x.\n", hr);
525         HeapFree(GetProcessHeap(), 0, object);
526         return hr;
527     }
528
529     TRACE("Created device %p.\n", object);
530     *device = &object->IDirect3DDevice9Ex_iface;
531
532     return D3D_OK;
533 }
534
535 static HRESULT WINAPI d3d9_GetAdapterLUID(IDirect3D9Ex *iface, UINT adapter, LUID *luid)
536 {
537     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
538     struct wined3d_adapter_identifier adapter_id;
539     HRESULT hr;
540
541     TRACE("iface %p, adapter %u, luid %p.\n", iface, adapter, luid);
542
543     adapter_id.driver_size = 0;
544     adapter_id.description_size = 0;
545     adapter_id.device_name_size = 0;
546
547     wined3d_mutex_lock();
548     hr = wined3d_get_adapter_identifier(d3d9->wined3d, adapter, 0, &adapter_id);
549     wined3d_mutex_unlock();
550
551     memcpy(luid, &adapter_id.adapter_luid, sizeof(*luid));
552
553     return hr;
554 }
555
556 static const struct IDirect3D9ExVtbl d3d9_vtbl =
557 {
558     /* IUnknown */
559     d3d9_QueryInterface,
560     d3d9_AddRef,
561     d3d9_Release,
562     /* IDirect3D9 */
563     d3d9_RegisterSoftwareDevice,
564     d3d9_GetAdapterCount,
565     d3d9_GetAdapterIdentifier,
566     d3d9_GetAdapterModeCount,
567     d3d9_EnumAdapterModes,
568     d3d9_GetAdapterDisplayMode,
569     d3d9_CheckDeviceType,
570     d3d9_CheckDeviceFormat,
571     d3d9_CheckDeviceMultiSampleType,
572     d3d9_CheckDepthStencilMatch,
573     d3d9_CheckDeviceFormatConversion,
574     d3d9_GetDeviceCaps,
575     d3d9_GetAdapterMonitor,
576     d3d9_CreateDevice,
577     /* IDirect3D9Ex */
578     d3d9_GetAdapterModeCountEx,
579     d3d9_EnumAdapterModesEx,
580     d3d9_GetAdapterDisplayModeEx,
581     d3d9_CreateDeviceEx,
582     d3d9_GetAdapterLUID,
583 };
584
585 BOOL d3d9_init(struct d3d9 *d3d9, BOOL extended)
586 {
587     d3d9->IDirect3D9Ex_iface.lpVtbl = &d3d9_vtbl;
588     d3d9->refcount = 1;
589
590     wined3d_mutex_lock();
591     d3d9->wined3d = wined3d_create(9, 0);
592     wined3d_mutex_unlock();
593     if (!d3d9->wined3d)
594         return FALSE;
595     d3d9->extended = extended;
596
597     return TRUE;
598 }