po: Update French translation.
[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 IDirect3D9Impl *impl_from_IDirect3D9Ex(IDirect3D9Ex *iface)
28 {
29     return CONTAINING_RECORD(iface, IDirect3D9Impl, IDirect3D9Ex_iface);
30 }
31
32 static HRESULT WINAPI IDirect3D9Impl_QueryInterface(IDirect3D9Ex *iface, REFIID riid, void **object)
33 {
34     IDirect3D9Impl *d3d9 = impl_from_IDirect3D9Ex(iface);
35
36     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
37
38     if (IsEqualGUID(riid, &IID_IDirect3D9)
39             || IsEqualGUID(riid, &IID_IUnknown))
40     {
41         IDirect3D9Ex_AddRef(&d3d9->IDirect3D9Ex_iface);
42         *object = &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             *object = NULL;
52             return E_NOINTERFACE;
53         }
54
55         IDirect3D9Ex_AddRef(&d3d9->IDirect3D9Ex_iface);
56         *object = &d3d9->IDirect3D9Ex_iface;
57         return S_OK;
58     }
59
60     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
61
62     *object = NULL;
63     return E_NOINTERFACE;
64 }
65
66 static ULONG WINAPI IDirect3D9Impl_AddRef(IDirect3D9Ex *iface)
67 {
68     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
69     ULONG ref = InterlockedIncrement(&This->ref);
70
71     TRACE("%p increasing refcount to %u.\n", iface, ref);
72
73     return ref;
74 }
75
76 static ULONG WINAPI IDirect3D9Impl_Release(IDirect3D9Ex *iface)
77 {
78     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
79     ULONG ref = InterlockedDecrement(&This->ref);
80
81     TRACE("%p decreasing refcount to %u.\n", iface, ref);
82
83     if (ref == 0) {
84         wined3d_mutex_lock();
85         wined3d_decref(This->WineD3D);
86         wined3d_mutex_unlock();
87
88         HeapFree(GetProcessHeap(), 0, This);
89     }
90
91     return ref;
92 }
93
94 /* IDirect3D9 Interface follow: */
95 static HRESULT  WINAPI  IDirect3D9Impl_RegisterSoftwareDevice(IDirect3D9Ex *iface,
96         void *pInitializeFunction)
97 {
98     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
99     HRESULT hr;
100
101     TRACE("iface %p, init_function %p.\n", iface, pInitializeFunction);
102
103     wined3d_mutex_lock();
104     hr = wined3d_register_software_device(This->WineD3D, pInitializeFunction);
105     wined3d_mutex_unlock();
106
107     return hr;
108 }
109
110 static UINT WINAPI IDirect3D9Impl_GetAdapterCount(IDirect3D9Ex *iface)
111 {
112     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
113     UINT ret;
114
115     TRACE("iface %p.\n", iface);
116
117     wined3d_mutex_lock();
118     ret = wined3d_get_adapter_count(This->WineD3D);
119     wined3d_mutex_unlock();
120
121     return ret;
122 }
123
124 static HRESULT WINAPI IDirect3D9Impl_GetAdapterIdentifier(IDirect3D9Ex *iface, UINT Adapter,
125         DWORD Flags, D3DADAPTER_IDENTIFIER9 *pIdentifier)
126 {
127     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
128     struct wined3d_adapter_identifier adapter_id;
129     HRESULT hr;
130
131     TRACE("iface %p, adapter %u, flags %#x, identifier %p.\n",
132             iface, Adapter, Flags, pIdentifier);
133
134     adapter_id.driver = pIdentifier->Driver;
135     adapter_id.driver_size = sizeof(pIdentifier->Driver);
136     adapter_id.description = pIdentifier->Description;
137     adapter_id.description_size = sizeof(pIdentifier->Description);
138     adapter_id.device_name = pIdentifier->DeviceName;
139     adapter_id.device_name_size = sizeof(pIdentifier->DeviceName);
140
141     wined3d_mutex_lock();
142     hr = wined3d_get_adapter_identifier(This->WineD3D, Adapter, Flags, &adapter_id);
143     wined3d_mutex_unlock();
144
145     pIdentifier->DriverVersion = adapter_id.driver_version;
146     pIdentifier->VendorId = adapter_id.vendor_id;
147     pIdentifier->DeviceId = adapter_id.device_id;
148     pIdentifier->SubSysId = adapter_id.subsystem_id;
149     pIdentifier->Revision = adapter_id.revision;
150     memcpy(&pIdentifier->DeviceIdentifier, &adapter_id.device_identifier, sizeof(pIdentifier->DeviceIdentifier));
151     pIdentifier->WHQLLevel = adapter_id.whql_level;
152
153     return hr;
154 }
155
156 static UINT WINAPI IDirect3D9Impl_GetAdapterModeCount(IDirect3D9Ex *iface, UINT Adapter,
157         D3DFORMAT Format)
158 {
159     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
160     UINT ret;
161
162     TRACE("iface %p, adapter %u, format %#x.\n", iface, Adapter, Format);
163
164     /* Others than that not supported by d3d9, but reported by wined3d for ddraw. Filter them out */
165     if(Format != D3DFMT_X8R8G8B8 && Format != D3DFMT_R5G6B5) {
166         return 0;
167     }
168
169     wined3d_mutex_lock();
170     ret = wined3d_get_adapter_mode_count(This->WineD3D, Adapter, wined3dformat_from_d3dformat(Format));
171     wined3d_mutex_unlock();
172
173     return ret;
174 }
175
176 static HRESULT WINAPI IDirect3D9Impl_EnumAdapterModes(IDirect3D9Ex *iface, UINT Adapter,
177         D3DFORMAT Format, UINT Mode, D3DDISPLAYMODE *pMode)
178 {
179     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
180     HRESULT hr;
181
182     TRACE("iface %p, adapter %u, format %#x, mode_idx %u, mode %p.\n",
183             iface, Adapter, Format, Mode, pMode);
184
185     /* We can't pass this to WineD3D, otherwise it'll think it came from D3D8 or DDraw.
186        It's supposed to fail anyway, so no harm returning failure. */
187     if(Format != D3DFMT_X8R8G8B8 && Format != D3DFMT_R5G6B5)
188         return D3DERR_INVALIDCALL;
189
190     wined3d_mutex_lock();
191     hr = wined3d_enum_adapter_modes(This->WineD3D, Adapter, wined3dformat_from_d3dformat(Format),
192             Mode, (struct wined3d_display_mode *)pMode);
193     wined3d_mutex_unlock();
194
195     if (SUCCEEDED(hr)) pMode->Format = d3dformat_from_wined3dformat(pMode->Format);
196
197     return hr;
198 }
199
200 static HRESULT WINAPI IDirect3D9Impl_GetAdapterDisplayMode(IDirect3D9Ex *iface, UINT Adapter,
201         D3DDISPLAYMODE *pMode)
202 {
203     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
204     HRESULT hr;
205
206     TRACE("iface %p, adapter %u, mode %p.\n", iface, Adapter, pMode);
207
208     wined3d_mutex_lock();
209     hr = wined3d_get_adapter_display_mode(This->WineD3D, Adapter, (struct wined3d_display_mode *)pMode);
210     wined3d_mutex_unlock();
211
212     if (SUCCEEDED(hr)) pMode->Format = d3dformat_from_wined3dformat(pMode->Format);
213
214     return hr;
215 }
216
217 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceType(IDirect3D9Ex *iface, UINT Adapter,
218         D3DDEVTYPE CheckType, D3DFORMAT DisplayFormat, D3DFORMAT BackBufferFormat, BOOL Windowed)
219 {
220     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
221     HRESULT hr;
222
223     TRACE("iface %p, adapter %u, device_type %#x, display_format %#x, backbuffer_format %#x, windowed %#x.\n",
224             iface, Adapter, CheckType, DisplayFormat, BackBufferFormat, Windowed);
225
226     wined3d_mutex_lock();
227     hr = wined3d_check_device_type(This->WineD3D, Adapter, CheckType, wined3dformat_from_d3dformat(DisplayFormat),
228             wined3dformat_from_d3dformat(BackBufferFormat), Windowed);
229     wined3d_mutex_unlock();
230
231     return hr;
232 }
233
234 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceFormat(IDirect3D9Ex *iface, UINT Adapter,
235         D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, DWORD Usage, D3DRESOURCETYPE RType,
236         D3DFORMAT CheckFormat)
237 {
238     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
239     enum wined3d_resource_type wined3d_rtype;
240     HRESULT hr;
241
242     TRACE("iface %p, adapter %u, device_type %#x, adapter_format %#x, usage %#x, resource_type %#x, format %#x.\n",
243             iface, Adapter, DeviceType, AdapterFormat, Usage, RType, CheckFormat);
244
245     switch(RType) {
246         case D3DRTYPE_VERTEXBUFFER:
247         case D3DRTYPE_INDEXBUFFER:
248             wined3d_rtype = WINED3D_RTYPE_BUFFER;
249             break;
250
251         default:
252             wined3d_rtype = RType;
253             break;
254     }
255
256     wined3d_mutex_lock();
257     hr = wined3d_check_device_format(This->WineD3D, Adapter, DeviceType, wined3dformat_from_d3dformat(AdapterFormat),
258             Usage, wined3d_rtype, wined3dformat_from_d3dformat(CheckFormat), WINED3D_SURFACE_TYPE_OPENGL);
259     wined3d_mutex_unlock();
260
261     return hr;
262 }
263
264 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceMultiSampleType(IDirect3D9Ex *iface, UINT Adapter,
265         D3DDEVTYPE DeviceType, D3DFORMAT SurfaceFormat, BOOL Windowed,
266         D3DMULTISAMPLE_TYPE MultiSampleType, DWORD *pQualityLevels)
267 {
268     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
269     HRESULT hr;
270
271     TRACE("iface %p, adapter %u, device_type %#x, format %#x, windowed %#x, multisample_type %#x, levels %p.\n",
272             iface, Adapter, DeviceType, SurfaceFormat, Windowed, MultiSampleType, pQualityLevels);
273
274     wined3d_mutex_lock();
275     hr = wined3d_check_device_multisample_type(This->WineD3D, Adapter, DeviceType,
276             wined3dformat_from_d3dformat(SurfaceFormat), Windowed, MultiSampleType, pQualityLevels);
277     wined3d_mutex_unlock();
278
279     return hr;
280 }
281
282 static HRESULT WINAPI IDirect3D9Impl_CheckDepthStencilMatch(IDirect3D9Ex *iface, UINT Adapter,
283         D3DDEVTYPE DeviceType, D3DFORMAT AdapterFormat, D3DFORMAT RenderTargetFormat,
284         D3DFORMAT DepthStencilFormat)
285 {
286     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
287     HRESULT hr;
288
289     TRACE("iface %p, adapter %u, device_type %#x, adapter_format %#x, rt_format %#x, ds_format %#x.\n",
290             iface, Adapter, DeviceType, AdapterFormat, RenderTargetFormat, DepthStencilFormat);
291
292     wined3d_mutex_lock();
293     hr = wined3d_check_depth_stencil_match(This->WineD3D, Adapter, DeviceType,
294             wined3dformat_from_d3dformat(AdapterFormat), wined3dformat_from_d3dformat(RenderTargetFormat),
295             wined3dformat_from_d3dformat(DepthStencilFormat));
296     wined3d_mutex_unlock();
297
298     return hr;
299 }
300
301 static HRESULT WINAPI IDirect3D9Impl_CheckDeviceFormatConversion(IDirect3D9Ex *iface, UINT Adapter,
302         D3DDEVTYPE DeviceType, D3DFORMAT SourceFormat, D3DFORMAT TargetFormat)
303 {
304     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
305     HRESULT hr;
306
307     TRACE("iface %p, adapter %u, device_type %#x, src_format %#x, dst_format %#x.\n",
308             iface, Adapter, DeviceType, SourceFormat, TargetFormat);
309
310     wined3d_mutex_lock();
311     hr = wined3d_check_device_format_conversion(This->WineD3D, Adapter, DeviceType,
312             wined3dformat_from_d3dformat(SourceFormat), wined3dformat_from_d3dformat(TargetFormat));
313     wined3d_mutex_unlock();
314
315     return hr;
316 }
317
318 void filter_caps(D3DCAPS9* pCaps)
319 {
320     DWORD ps_minor_version[] = {0, 4, 0, 0};
321     DWORD vs_minor_version[] = {0, 1, 0, 0};
322     DWORD textureFilterCaps =
323         D3DPTFILTERCAPS_MINFPOINT      | D3DPTFILTERCAPS_MINFLINEAR    | D3DPTFILTERCAPS_MINFANISOTROPIC |
324         D3DPTFILTERCAPS_MINFPYRAMIDALQUAD                              | D3DPTFILTERCAPS_MINFGAUSSIANQUAD|
325         D3DPTFILTERCAPS_MIPFPOINT      | D3DPTFILTERCAPS_MIPFLINEAR    | D3DPTFILTERCAPS_MAGFPOINT       |
326         D3DPTFILTERCAPS_MAGFLINEAR     |D3DPTFILTERCAPS_MAGFANISOTROPIC|D3DPTFILTERCAPS_MAGFPYRAMIDALQUAD|
327         D3DPTFILTERCAPS_MAGFGAUSSIANQUAD;
328     pCaps->TextureFilterCaps &= textureFilterCaps;
329     pCaps->CubeTextureFilterCaps &= textureFilterCaps;
330     pCaps->VolumeTextureFilterCaps &= textureFilterCaps;
331
332     pCaps->DevCaps &=
333         D3DDEVCAPS_EXECUTESYSTEMMEMORY | D3DDEVCAPS_EXECUTEVIDEOMEMORY | D3DDEVCAPS_TLVERTEXSYSTEMMEMORY |
334         D3DDEVCAPS_TLVERTEXVIDEOMEMORY | D3DDEVCAPS_TEXTURESYSTEMMEMORY| D3DDEVCAPS_TEXTUREVIDEOMEMORY   |
335         D3DDEVCAPS_DRAWPRIMTLVERTEX    | D3DDEVCAPS_CANRENDERAFTERFLIP | D3DDEVCAPS_TEXTURENONLOCALVIDMEM|
336         D3DDEVCAPS_DRAWPRIMITIVES2     | D3DDEVCAPS_SEPARATETEXTUREMEMORIES                              |
337         D3DDEVCAPS_DRAWPRIMITIVES2EX   | D3DDEVCAPS_HWTRANSFORMANDLIGHT| D3DDEVCAPS_CANBLTSYSTONONLOCAL  |
338         D3DDEVCAPS_HWRASTERIZATION     | D3DDEVCAPS_PUREDEVICE         | D3DDEVCAPS_QUINTICRTPATCHES     |
339         D3DDEVCAPS_RTPATCHES           | D3DDEVCAPS_RTPATCHHANDLEZERO  | D3DDEVCAPS_NPATCHES;
340
341     pCaps->ShadeCaps &=
342         D3DPSHADECAPS_COLORGOURAUDRGB  | D3DPSHADECAPS_SPECULARGOURAUDRGB |
343         D3DPSHADECAPS_ALPHAGOURAUDBLEND | D3DPSHADECAPS_FOGGOURAUD;
344
345     pCaps->RasterCaps &=
346         D3DPRASTERCAPS_DITHER          | D3DPRASTERCAPS_ZTEST          | D3DPRASTERCAPS_FOGVERTEX        |
347         D3DPRASTERCAPS_FOGTABLE        | D3DPRASTERCAPS_MIPMAPLODBIAS  | D3DPRASTERCAPS_ZBUFFERLESSHSR   |
348         D3DPRASTERCAPS_FOGRANGE        | D3DPRASTERCAPS_ANISOTROPY     | D3DPRASTERCAPS_WBUFFER          |
349         D3DPRASTERCAPS_WFOG            | D3DPRASTERCAPS_ZFOG           | D3DPRASTERCAPS_COLORPERSPECTIVE |
350         D3DPRASTERCAPS_SCISSORTEST     | D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS                              |
351         D3DPRASTERCAPS_DEPTHBIAS       | D3DPRASTERCAPS_MULTISAMPLE_TOGGLE;
352
353     pCaps->DevCaps2 &=
354         D3DDEVCAPS2_STREAMOFFSET       | D3DDEVCAPS2_DMAPNPATCH        | D3DDEVCAPS2_ADAPTIVETESSRTPATCH |
355         D3DDEVCAPS2_ADAPTIVETESSNPATCH | D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES                       |
356         D3DDEVCAPS2_PRESAMPLEDDMAPNPATCH| D3DDEVCAPS2_VERTEXELEMENTSCANSHARESTREAMOFFSET;
357
358     pCaps->Caps2 &=
359         D3DCAPS2_FULLSCREENGAMMA       | D3DCAPS2_CANCALIBRATEGAMMA    | D3DCAPS2_RESERVED               |
360         D3DCAPS2_CANMANAGERESOURCE     | D3DCAPS2_DYNAMICTEXTURES      | D3DCAPS2_CANAUTOGENMIPMAP;
361
362     pCaps->VertexProcessingCaps &=
363         D3DVTXPCAPS_TEXGEN             | D3DVTXPCAPS_MATERIALSOURCE7   | D3DVTXPCAPS_DIRECTIONALLIGHTS   |
364         D3DVTXPCAPS_POSITIONALLIGHTS   | D3DVTXPCAPS_LOCALVIEWER       | D3DVTXPCAPS_TWEENING            |
365         D3DVTXPCAPS_TEXGEN_SPHEREMAP   | D3DVTXPCAPS_NO_TEXGEN_NONLOCALVIEWER;
366
367     pCaps->TextureCaps &=
368         D3DPTEXTURECAPS_PERSPECTIVE    | D3DPTEXTURECAPS_POW2          | D3DPTEXTURECAPS_ALPHA           |
369         D3DPTEXTURECAPS_SQUAREONLY     | D3DPTEXTURECAPS_TEXREPEATNOTSCALEDBYSIZE                        |
370         D3DPTEXTURECAPS_ALPHAPALETTE   | D3DPTEXTURECAPS_NONPOW2CONDITIONAL                              |
371         D3DPTEXTURECAPS_PROJECTED      | D3DPTEXTURECAPS_CUBEMAP       | D3DPTEXTURECAPS_VOLUMEMAP       |
372         D3DPTEXTURECAPS_MIPMAP         | D3DPTEXTURECAPS_MIPVOLUMEMAP  | D3DPTEXTURECAPS_MIPCUBEMAP      |
373         D3DPTEXTURECAPS_CUBEMAP_POW2   | D3DPTEXTURECAPS_VOLUMEMAP_POW2| D3DPTEXTURECAPS_NOPROJECTEDBUMPENV;
374
375     pCaps->MaxVertexShaderConst = min(D3D9_MAX_VERTEX_SHADER_CONSTANTF, pCaps->MaxVertexShaderConst);
376     pCaps->NumSimultaneousRTs = min(D3D9_MAX_SIMULTANEOUS_RENDERTARGETS, pCaps->NumSimultaneousRTs);
377
378     if (pCaps->PixelShaderVersion > 3)
379         pCaps->PixelShaderVersion = D3DPS_VERSION(3,0);
380     else
381     {
382         DWORD major = pCaps->PixelShaderVersion;
383         pCaps->PixelShaderVersion = D3DPS_VERSION(major,ps_minor_version[major]);
384     }
385
386     if (pCaps->VertexShaderVersion > 3)
387         pCaps->VertexShaderVersion = D3DVS_VERSION(3,0);
388     else
389     {
390         DWORD major = pCaps->VertexShaderVersion;
391         pCaps->VertexShaderVersion = D3DVS_VERSION(major,vs_minor_version[major]);
392     }
393 }
394
395 static HRESULT WINAPI IDirect3D9Impl_GetDeviceCaps(IDirect3D9Ex *iface, UINT Adapter,
396         D3DDEVTYPE DeviceType, D3DCAPS9 *pCaps)
397 {
398     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
399     HRESULT hrc = D3D_OK;
400     WINED3DCAPS *pWineCaps;
401
402     TRACE("iface %p, adapter %u, device_type %#x, caps %p.\n", iface, Adapter, DeviceType, pCaps);
403
404     if(NULL == pCaps){
405         return D3DERR_INVALIDCALL;
406     }
407     pWineCaps = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WINED3DCAPS));
408     if(pWineCaps == NULL){
409         return D3DERR_INVALIDCALL; /*well this is what MSDN says to return*/
410     }
411     memset(pCaps, 0, sizeof(*pCaps));
412
413     wined3d_mutex_lock();
414     hrc = wined3d_get_device_caps(This->WineD3D, Adapter, DeviceType, pWineCaps);
415     wined3d_mutex_unlock();
416
417     WINECAPSTOD3D9CAPS(pCaps, pWineCaps)
418     HeapFree(GetProcessHeap(), 0, pWineCaps);
419
420     /* Some functionality is implemented in d3d9.dll, not wined3d.dll. Add the needed caps */
421     pCaps->DevCaps2 |= D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES;
422
423     filter_caps(pCaps);
424
425     TRACE("(%p) returning %p\n", This, pCaps);
426     return hrc;
427 }
428
429 static HMONITOR WINAPI IDirect3D9Impl_GetAdapterMonitor(IDirect3D9Ex *iface, UINT Adapter)
430 {
431     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
432     HMONITOR ret;
433
434     TRACE("iface %p, adapter %u.\n", iface, Adapter);
435
436     wined3d_mutex_lock();
437     ret = wined3d_get_adapter_monitor(This->WineD3D, Adapter);
438     wined3d_mutex_unlock();
439
440     return ret;
441 }
442
443 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3D9Impl_CreateDevice(IDirect3D9Ex *iface, UINT adapter,
444         D3DDEVTYPE device_type, HWND focus_window, DWORD flags, D3DPRESENT_PARAMETERS *parameters,
445         IDirect3DDevice9 **device)
446 {
447     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
448     IDirect3DDevice9Impl *object;
449     HRESULT hr;
450
451     TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, device %p.\n",
452             iface, adapter, device_type, focus_window, flags, parameters, device);
453
454     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
455     if (!object)
456     {
457         ERR("Failed to allocate device memory.\n");
458         return E_OUTOFMEMORY;
459     }
460
461     hr = device_init(object, This, This->WineD3D, adapter, device_type, focus_window, flags, parameters, NULL);
462     if (FAILED(hr))
463     {
464         WARN("Failed to initialize device, hr %#x.\n", hr);
465         HeapFree(GetProcessHeap(), 0, object);
466         return hr;
467     }
468
469     TRACE("Created device %p.\n", object);
470     *device = (IDirect3DDevice9 *)object;
471
472     return D3D_OK;
473 }
474
475 static UINT WINAPI IDirect3D9ExImpl_GetAdapterModeCountEx(IDirect3D9Ex *iface,
476         UINT adapter, const D3DDISPLAYMODEFILTER *filter)
477 {
478     FIXME("iface %p, adapter %u, filter %p stub!\n", iface, adapter, filter);
479
480     return 0;
481 }
482
483 static HRESULT WINAPI IDirect3D9ExImpl_EnumAdapterModesEx(IDirect3D9Ex *iface,
484         UINT adapter, const D3DDISPLAYMODEFILTER *filter, UINT mode_idx, D3DDISPLAYMODEEX *mode)
485 {
486     FIXME("iface %p, adapter %u, filter %p, mode_idx %u, mode %p stub!\n",
487             iface, adapter, filter, mode_idx, mode);
488
489     return E_NOTIMPL;
490 }
491
492 static HRESULT WINAPI IDirect3D9ExImpl_GetAdapterDisplayModeEx(IDirect3D9Ex *iface,
493         UINT adapter, D3DDISPLAYMODEEX *mode, D3DDISPLAYROTATION *rotation)
494 {
495     FIXME("iface %p, adapter %u, mode %p, rotation %p stub!\n",
496             iface, adapter, mode, rotation);
497
498     return E_NOTIMPL;
499 }
500
501 static HRESULT WINAPI DECLSPEC_HOTPATCH IDirect3D9ExImpl_CreateDeviceEx(IDirect3D9Ex *iface,
502         UINT adapter, D3DDEVTYPE device_type, HWND focus_window, DWORD flags,
503         D3DPRESENT_PARAMETERS *parameters, D3DDISPLAYMODEEX *mode, IDirect3DDevice9Ex **device)
504 {
505     IDirect3D9Impl *d3d9 = impl_from_IDirect3D9Ex(iface);
506     IDirect3DDevice9Impl *object;
507     HRESULT hr;
508
509     TRACE("iface %p, adapter %u, device_type %#x, focus_window %p, flags %#x, parameters %p, mode %p, device %p.\n",
510             iface, adapter, device_type, focus_window, flags, parameters, mode, device);
511
512     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
513     if (!object)
514     {
515         ERR("Failed to allocate device memory.\n");
516         return E_OUTOFMEMORY;
517     }
518
519     hr = device_init(object, d3d9, d3d9->WineD3D, adapter, device_type, focus_window, flags, parameters, mode);
520     if (FAILED(hr))
521     {
522         WARN("Failed to initialize device, hr %#x.\n", hr);
523         HeapFree(GetProcessHeap(), 0, object);
524         return hr;
525     }
526
527     TRACE("Created device %p.\n", object);
528     *device = &object->IDirect3DDevice9Ex_iface;
529
530     return D3D_OK;
531 }
532
533 static HRESULT WINAPI IDirect3D9ExImpl_GetAdapterLUID(IDirect3D9Ex *iface, UINT adapter, LUID *luid)
534 {
535     IDirect3D9Impl *This = impl_from_IDirect3D9Ex(iface);
536     struct wined3d_adapter_identifier adapter_id;
537     HRESULT hr;
538
539     TRACE("iface %p, adapter %u, luid %p.\n", iface, adapter, luid);
540
541     adapter_id.driver_size = 0;
542     adapter_id.description_size = 0;
543     adapter_id.device_name_size = 0;
544
545     wined3d_mutex_lock();
546     hr = wined3d_get_adapter_identifier(This->WineD3D, adapter, 0, &adapter_id);
547     wined3d_mutex_unlock();
548
549     memcpy(luid, &adapter_id.adapter_luid, sizeof(*luid));
550
551     return hr;
552 }
553
554
555 const IDirect3D9ExVtbl Direct3D9_Vtbl =
556 {
557     /* IUnknown */
558     IDirect3D9Impl_QueryInterface,
559     IDirect3D9Impl_AddRef,
560     IDirect3D9Impl_Release,
561     /* IDirect3D9 */
562     IDirect3D9Impl_RegisterSoftwareDevice,
563     IDirect3D9Impl_GetAdapterCount,
564     IDirect3D9Impl_GetAdapterIdentifier,
565     IDirect3D9Impl_GetAdapterModeCount,
566     IDirect3D9Impl_EnumAdapterModes,
567     IDirect3D9Impl_GetAdapterDisplayMode,
568     IDirect3D9Impl_CheckDeviceType,
569     IDirect3D9Impl_CheckDeviceFormat,
570     IDirect3D9Impl_CheckDeviceMultiSampleType,
571     IDirect3D9Impl_CheckDepthStencilMatch,
572     IDirect3D9Impl_CheckDeviceFormatConversion,
573     IDirect3D9Impl_GetDeviceCaps,
574     IDirect3D9Impl_GetAdapterMonitor,
575     IDirect3D9Impl_CreateDevice,
576     /* IDirect3D9Ex */
577     IDirect3D9ExImpl_GetAdapterModeCountEx,
578     IDirect3D9ExImpl_EnumAdapterModesEx,
579     IDirect3D9ExImpl_GetAdapterDisplayModeEx,
580     IDirect3D9ExImpl_CreateDeviceEx,
581     IDirect3D9ExImpl_GetAdapterLUID
582
583 };