d3drm: Implement IDirect3DRMMeshImpl_GetGroupMaterial.
[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     HRESULT hr;
178
179     TRACE("iface %p, adapter %u, format %#x, mode_idx %u, mode %p.\n",
180             iface, adapter, format, mode_idx, mode);
181
182     if (format != D3DFMT_X8R8G8B8 && format != D3DFMT_R5G6B5)
183         return D3DERR_INVALIDCALL;
184
185     wined3d_mutex_lock();
186     hr = wined3d_enum_adapter_modes(d3d9->wined3d, adapter, wined3dformat_from_d3dformat(format),
187             mode_idx, (struct wined3d_display_mode *)mode);
188     wined3d_mutex_unlock();
189
190     if (SUCCEEDED(hr))
191         mode->Format = d3dformat_from_wined3dformat(mode->Format);
192
193     return hr;
194 }
195
196 static HRESULT WINAPI d3d9_GetAdapterDisplayMode(IDirect3D9Ex *iface, UINT adapter, D3DDISPLAYMODE *mode)
197 {
198     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
199     HRESULT hr;
200
201     TRACE("iface %p, adapter %u, mode %p.\n", iface, adapter, mode);
202
203     wined3d_mutex_lock();
204     hr = wined3d_get_adapter_display_mode(d3d9->wined3d, adapter, (struct wined3d_display_mode *)mode);
205     wined3d_mutex_unlock();
206
207     if (SUCCEEDED(hr))
208         mode->Format = d3dformat_from_wined3dformat(mode->Format);
209
210     return hr;
211 }
212
213 static HRESULT WINAPI d3d9_CheckDeviceType(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
214         D3DFORMAT display_format, D3DFORMAT backbuffer_format, BOOL windowed)
215 {
216     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
217     HRESULT hr;
218
219     TRACE("iface %p, adapter %u, device_type %#x, display_format %#x, backbuffer_format %#x, windowed %#x.\n",
220             iface, adapter, device_type, display_format, backbuffer_format, windowed);
221
222     wined3d_mutex_lock();
223     hr = wined3d_check_device_type(d3d9->wined3d, adapter, device_type, wined3dformat_from_d3dformat(display_format),
224             wined3dformat_from_d3dformat(backbuffer_format), windowed);
225     wined3d_mutex_unlock();
226
227     return hr;
228 }
229
230 static HRESULT WINAPI d3d9_CheckDeviceFormat(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
231         D3DFORMAT adapter_format, DWORD usage, D3DRESOURCETYPE resource_type, D3DFORMAT format)
232 {
233     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
234     enum wined3d_resource_type wined3d_rtype;
235     HRESULT hr;
236
237     TRACE("iface %p, adapter %u, device_type %#x, adapter_format %#x, usage %#x, resource_type %#x, format %#x.\n",
238             iface, adapter, device_type, adapter_format, usage, resource_type, format);
239
240     switch (resource_type)
241     {
242         case D3DRTYPE_VERTEXBUFFER:
243         case D3DRTYPE_INDEXBUFFER:
244             wined3d_rtype = WINED3D_RTYPE_BUFFER;
245             break;
246
247         default:
248             wined3d_rtype = resource_type;
249             break;
250     }
251
252     wined3d_mutex_lock();
253     hr = wined3d_check_device_format(d3d9->wined3d, adapter, device_type, wined3dformat_from_d3dformat(adapter_format),
254             usage, wined3d_rtype, wined3dformat_from_d3dformat(format), WINED3D_SURFACE_TYPE_OPENGL);
255     wined3d_mutex_unlock();
256
257     return hr;
258 }
259
260 static HRESULT WINAPI d3d9_CheckDeviceMultiSampleType(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
261         D3DFORMAT format, BOOL windowed, D3DMULTISAMPLE_TYPE multisample_type, DWORD *levels)
262 {
263     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
264     HRESULT hr;
265
266     TRACE("iface %p, adapter %u, device_type %#x, format %#x, windowed %#x, multisample_type %#x, levels %p.\n",
267             iface, adapter, device_type, format, windowed, multisample_type, levels);
268
269     wined3d_mutex_lock();
270     hr = wined3d_check_device_multisample_type(d3d9->wined3d, adapter, device_type,
271             wined3dformat_from_d3dformat(format), windowed, multisample_type, levels);
272     wined3d_mutex_unlock();
273
274     return hr;
275 }
276
277 static HRESULT WINAPI d3d9_CheckDepthStencilMatch(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type,
278         D3DFORMAT adapter_format, D3DFORMAT rt_format, D3DFORMAT ds_format)
279 {
280     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
281     HRESULT hr;
282
283     TRACE("iface %p, adapter %u, device_type %#x, adapter_format %#x, rt_format %#x, ds_format %#x.\n",
284             iface, adapter, device_type, adapter_format, rt_format, ds_format);
285
286     wined3d_mutex_lock();
287     hr = wined3d_check_depth_stencil_match(d3d9->wined3d, adapter, device_type,
288             wined3dformat_from_d3dformat(adapter_format), wined3dformat_from_d3dformat(rt_format),
289             wined3dformat_from_d3dformat(ds_format));
290     wined3d_mutex_unlock();
291
292     return hr;
293 }
294
295 static HRESULT WINAPI d3d9_CheckDeviceFormatConversion(IDirect3D9Ex *iface, UINT adapter,
296         D3DDEVTYPE device_type, D3DFORMAT src_format, D3DFORMAT dst_format)
297 {
298     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
299     HRESULT hr;
300
301     TRACE("iface %p, adapter %u, device_type %#x, src_format %#x, dst_format %#x.\n",
302             iface, adapter, device_type, src_format, dst_format);
303
304     wined3d_mutex_lock();
305     hr = wined3d_check_device_format_conversion(d3d9->wined3d, adapter, device_type,
306             wined3dformat_from_d3dformat(src_format), wined3dformat_from_d3dformat(dst_format));
307     wined3d_mutex_unlock();
308
309     return hr;
310 }
311
312 void filter_caps(D3DCAPS9* pCaps)
313 {
314     DWORD ps_minor_version[] = {0, 4, 0, 0};
315     DWORD vs_minor_version[] = {0, 1, 0, 0};
316     DWORD textureFilterCaps =
317         D3DPTFILTERCAPS_MINFPOINT      | D3DPTFILTERCAPS_MINFLINEAR    | D3DPTFILTERCAPS_MINFANISOTROPIC |
318         D3DPTFILTERCAPS_MINFPYRAMIDALQUAD                              | D3DPTFILTERCAPS_MINFGAUSSIANQUAD|
319         D3DPTFILTERCAPS_MIPFPOINT      | D3DPTFILTERCAPS_MIPFLINEAR    | D3DPTFILTERCAPS_MAGFPOINT       |
320         D3DPTFILTERCAPS_MAGFLINEAR     |D3DPTFILTERCAPS_MAGFANISOTROPIC|D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD|
321         D3DPTFILTERCAPS_MAGFGAUSSIANQUAD;
322     pCaps->TextureFilterCaps &= textureFilterCaps;
323     pCaps->CubeTextureFilterCaps &= textureFilterCaps;
324     pCaps->VolumeTextureFilterCaps &= textureFilterCaps;
325
326     pCaps->DevCaps &=
327         D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY |
328         D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY| D3DDEVCAPS_TEXTUREVIDEOMEMORY   |
329         D3DDEVCAPS_DRAWPRIMTLVERTEX    | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM|
330         D3DDEVCAPS_DRAWPRIMITIVES2     | D3DDEVCAPS_SEPARATETEXTUREMEMORIES                              |
331         D3DDEVCAPS_DRAWPRIMITIVES2EX   | D3DDEVCAPS_HWTRANSFORMANDLIGHT| D3DDEVCAPS_CANBLTSYSTONONLOCAL  |
332         D3DDEVCAPS_HWRASTERIZATION     | D3DDEVCAPS_PUREDEVICE         | D3DDEVCAPS_QUINTICRTPATCHES     |
333         D3DDEVCAPS_RTPATCHES           | D3DDEVCAPS_RTPATCHHANDLEZERO  | D3DDEVCAPS_NPATCHES;
334
335     pCaps->ShadeCaps &=
336         D3DPSHADECAPS_COLORGOURAUDRGB  | D3DPSHADECAPS_SPECULARGOURAUDRGB |
337         D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_FOGGOURAUD;
338
339     pCaps->RasterCaps &=
340         D3DPRASTERCAPS_DITHER          | D3DPRASTERCAPS_ZTEST          | D3DPRASTERCAPS_FOGVERTEX        |
341         D3DPRASTERCAPS_FOGTABLE        | D3DPRASTERCAPS_MIPMAPLODBIAS  | D3DPRASTERCAPS_ZBUFFERLESSHSR   |
342         D3DPRASTERCAPS_FOGRANGE        | D3DPRASTERCAPS_ANISOTROPY     | D3DPRASTERCAPS_WBUFFER          |
343         D3DPRASTERCAPS_WFOG            | D3DPRASTERCAPS_ZFOG           | D3DPRASTERCAPS_COLORPERSPECTIVE |
344         D3DPRASTERCAPS_SCISSORTEST     | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS                              |
345         D3DPRASTERCAPS_DEPTHBIAS       | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;
346
347     pCaps->DevCaps2 &=
348         D3DDEVCAPS2_STREAMOFFSET       | D3DDEVCAPS2_DMAPNPATCH        | D3DDEVCAPS2_ADAPTIVETESSRTPATCH |
349         D3DDEVCAPS2_ADAPTIVETESSNPATCH | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES                       |
350         D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
351
352     pCaps->Caps2 &=
353         D3DCAPS2_FULLSCREENGAMMA       | D3DCAPS2_CANCALIBRATEGAMMA    | D3DCAPS2_RESERVED               |
354         D3DCAPS2_CANMANAGERESOURCE     | D3DCAPS2_DYNAMICTEXTURES      | D3DCAPS2_CANAUTOGENMIPMAP;
355
356     pCaps->VertexProcessingCaps &=
357         D3DVTXPCAPS_TEXGEN             | D3DVTXPCAPS_MATERIALSOURCE7   | D3DVTXPCAPS_DIRECTIONALLIGHTS   |
358         D3DVTXPCAPS_POSITIONALLIGHTS   | D3DVTXPCAPS_LOCALVIEWER       | D3DVTXPCAPS_TWEENING            |
359         D3DVTXPCAPS_TEXGEN_SPHEREMAP   | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER;
360
361     pCaps->TextureCaps &=
362         D3DPTEXTURECAPS_PERSPECTIVE    | D3DPTEXTURECAPS_POW2          | D3DPTEXTURECAPS_ALPHA           |
363         D3DPTEXTURECAPS_SQUAREONLY     | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE                        |
364         D3DPTEXTURECAPS_ALPHAPALETTE   | D3DPTEXTURECAPS_NONPOW2CONDITIONAL                              |
365         D3DPTEXTURECAPS_PROJECTED      | D3DPTEXTURECAPS_CUBEMAP       | D3DPTEXTURECAPS_VOLUMEMAP       |
366         D3DPTEXTURECAPS_MIPMAP         | D3DPTEXTURECAPS_MIPVOLUMEMAP  | D3DPTEXTURECAPS_MIPCUBEMAP      |
367         D3DPTEXTURECAPS_CUBEMAP_POW2   | D3DPTEXTURECAPS_VOLUMEMAP_POW2| D3DPTEXTURECAPS_NOPROJECTEDBUMPENV;
368
369     pCaps->MaxVertexShaderConst = min(D3D9_MAX_VERTEX_SHADER_CONSTANTF, pCaps->MaxVertexShaderConst);
370     pCaps->NumSimultaneousRTs = min(D3D9_MAX_SIMULTANEOUS_RENDERTARGETS, pCaps->NumSimultaneousRTs);
371
372     if (pCaps->PixelShaderVersion > 3)
373         pCaps->PixelShaderVersion = D3DPS_VERSION(3,0);
374     else
375     {
376         DWORD major = pCaps->PixelShaderVersion;
377         pCaps->PixelShaderVersion = D3DPS_VERSION(major,ps_minor_version[major]);
378     }
379
380     if (pCaps->VertexShaderVersion > 3)
381         pCaps->VertexShaderVersion = D3DVS_VERSION(3,0);
382     else
383     {
384         DWORD major = pCaps->VertexShaderVersion;
385         pCaps->VertexShaderVersion = D3DVS_VERSION(major,vs_minor_version[major]);
386     }
387 }
388
389 static HRESULT WINAPI d3d9_GetDeviceCaps(IDirect3D9Ex *iface, UINT adapter, D3DDEVTYPE device_type, D3DCAPS9 *caps)
390 {
391     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
392     WINED3DCAPS *wined3d_caps;
393     HRESULT hr;
394
395     TRACE("iface %p, adapter %u, device_type %#x, caps %p.\n", iface, adapter, device_type, caps);
396
397     if (!caps)
398         return D3DERR_INVALIDCALL;
399
400     if (!(wined3d_caps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINED3DCAPS))))
401         return D3DERR_INVALIDCALL; /*well this is what MSDN says to return*/
402     memset(caps, 0, sizeof(*caps));
403
404     wined3d_mutex_lock();
405     hr = wined3d_get_device_caps(d3d9->wined3d, adapter, device_type, wined3d_caps);
406     wined3d_mutex_unlock();
407
408     WINECAPSTOD3D9CAPS(caps, wined3d_caps)
409     HeapFree(GetProcessHeap(), 0, wined3d_caps);
410
411     /* Some functionality is implemented in d3d9.dll, not wined3d.dll. Add the needed caps */
412     caps->DevCaps2 |= D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES;
413
414     filter_caps(caps);
415
416     return hr;
417 }
418
419 static HMONITOR WINAPI d3d9_GetAdapterMonitor(IDirect3D9Ex *iface, UINT adapter)
420 {
421     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
422     HMONITOR ret;
423
424     TRACE("iface %p, adapter %u.\n", iface, adapter);
425
426     wined3d_mutex_lock();
427     ret = wined3d_get_adapter_monitor(d3d9->wined3d, adapter);
428     wined3d_mutex_unlock();
429
430     return ret;
431 }
432
433 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_CreateDevice(IDirect3D9Ex *iface, UINT adapter,
434         D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters,
435         IDirect3DDevice9 **device)
436 {
437     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
438     struct d3d9_device *object;
439     HRESULT hr;
440
441     TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, device %p.\n",
442             iface, adapter, device_type, focus_window, flags, parameters, device);
443
444     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
445     if (!object)
446     {
447         ERR("Failed to allocate device memory.\n");
448         return E_OUTOFMEMORY;
449     }
450
451     hr = device_init(object, d3d9, d3d9->wined3d, adapter, device_type, focus_window, flags, parameters, NULL);
452     if (FAILED(hr))
453     {
454         WARN("Failed to initialize device, hr %#x.\n", hr);
455         HeapFree(GetProcessHeap(), 0, object);
456         return hr;
457     }
458
459     TRACE("Created device %p.\n", object);
460     *device = (IDirect3DDevice9 *)object;
461
462     return D3D_OK;
463 }
464
465 static UINT WINAPI d3d9_GetAdapterModeCountEx(IDirect3D9Ex *iface,
466         UINT adapter, const D3DDISPLAYMODEFILTER *filter)
467 {
468     FIXME("iface %p, adapter %u, filter %p stub!\n", iface, adapter, filter);
469
470     return 0;
471 }
472
473 static HRESULT WINAPI d3d9_EnumAdapterModesEx(IDirect3D9Ex *iface,
474         UINT adapter, const D3DDISPLAYMODEFILTER *filter, UINT mode_idx, D3DDISPLAYMODEEX *mode)
475 {
476     FIXME("iface %p, adapter %u, filter %p, mode_idx %u, mode %p stub!\n",
477             iface, adapter, filter, mode_idx, mode);
478
479     return E_NOTIMPL;
480 }
481
482 static HRESULT WINAPI d3d9_GetAdapterDisplayModeEx(IDirect3D9Ex *iface,
483         UINT adapter, D3DDISPLAYMODEEX *mode, D3DDISPLAYROTATION *rotation)
484 {
485     FIXME("iface %p, adapter %u, mode %p, rotation %p stub!\n",
486             iface, adapter, mode, rotation);
487
488     return E_NOTIMPL;
489 }
490
491 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_CreateDeviceEx(IDirect3D9Ex *iface,
492         UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags,
493         D3DPRESENT_PARAMETERS *parameters, D3DDISPLAYMODEEX *mode, IDirect3DDevice9Ex **device)
494 {
495     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
496     struct d3d9_device *object;
497     HRESULT hr;
498
499     TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, mode %p, device %p.\n",
500             iface, adapter, device_type, focus_window, flags, parameters, mode, device);
501
502     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
503     if (!object)
504     {
505         ERR("Failed to allocate device memory.\n");
506         return E_OUTOFMEMORY;
507     }
508
509     hr = device_init(object, d3d9, d3d9->wined3d, adapter, device_type, focus_window, flags, parameters, mode);
510     if (FAILED(hr))
511     {
512         WARN("Failed to initialize device, hr %#x.\n", hr);
513         HeapFree(GetProcessHeap(), 0, object);
514         return hr;
515     }
516
517     TRACE("Created device %p.\n", object);
518     *device = &object->IDirect3DDevice9Ex_iface;
519
520     return D3D_OK;
521 }
522
523 static HRESULT WINAPI d3d9_GetAdapterLUID(IDirect3D9Ex *iface, UINT adapter, LUID *luid)
524 {
525     struct d3d9 *d3d9 = impl_from_IDirect3D9Ex(iface);
526     struct wined3d_adapter_identifier adapter_id;
527     HRESULT hr;
528
529     TRACE("iface %p, adapter %u, luid %p.\n", iface, adapter, luid);
530
531     adapter_id.driver_size = 0;
532     adapter_id.description_size = 0;
533     adapter_id.device_name_size = 0;
534
535     wined3d_mutex_lock();
536     hr = wined3d_get_adapter_identifier(d3d9->wined3d, adapter, 0, &adapter_id);
537     wined3d_mutex_unlock();
538
539     memcpy(luid, &adapter_id.adapter_luid, sizeof(*luid));
540
541     return hr;
542 }
543
544 static const struct IDirect3D9ExVtbl d3d9_vtbl =
545 {
546     /* IUnknown */
547     d3d9_QueryInterface,
548     d3d9_AddRef,
549     d3d9_Release,
550     /* IDirect3D9 */
551     d3d9_RegisterSoftwareDevice,
552     d3d9_GetAdapterCount,
553     d3d9_GetAdapterIdentifier,
554     d3d9_GetAdapterModeCount,
555     d3d9_EnumAdapterModes,
556     d3d9_GetAdapterDisplayMode,
557     d3d9_CheckDeviceType,
558     d3d9_CheckDeviceFormat,
559     d3d9_CheckDeviceMultiSampleType,
560     d3d9_CheckDepthStencilMatch,
561     d3d9_CheckDeviceFormatConversion,
562     d3d9_GetDeviceCaps,
563     d3d9_GetAdapterMonitor,
564     d3d9_CreateDevice,
565     /* IDirect3D9Ex */
566     d3d9_GetAdapterModeCountEx,
567     d3d9_EnumAdapterModesEx,
568     d3d9_GetAdapterDisplayModeEx,
569     d3d9_CreateDeviceEx,
570     d3d9_GetAdapterLUID,
571 };
572
573 BOOL d3d9_init(struct d3d9 *d3d9, BOOL extended)
574 {
575     d3d9->IDirect3D9Ex_iface.lpVtbl = &d3d9_vtbl;
576     d3d9->refcount = 1;
577
578     wined3d_mutex_lock();
579     d3d9->wined3d = wined3d_create(9, 0);
580     wined3d_mutex_unlock();
581     if (!d3d9->wined3d)
582         return FALSE;
583     d3d9->extended = extended;
584
585     return TRUE;
586 }