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