2 * Copyright 2008 Henri Verbeet for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "wine/port.h"
23 #include "dxgi_private.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(dxgi
);
27 static inline struct dxgi_factory
*impl_from_IWineDXGIFactory(IWineDXGIFactory
*iface
)
29 return CONTAINING_RECORD(iface
, struct dxgi_factory
, IWineDXGIFactory_iface
);
32 static HRESULT STDMETHODCALLTYPE
dxgi_factory_QueryInterface(IWineDXGIFactory
*iface
, REFIID iid
, void **out
)
34 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
36 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
38 if (IsEqualGUID(iid
, &IID_IWineDXGIFactory
)
39 || IsEqualGUID(iid
, &IID_IDXGIFactory7
)
40 || IsEqualGUID(iid
, &IID_IDXGIFactory6
)
41 || IsEqualGUID(iid
, &IID_IDXGIFactory5
)
42 || IsEqualGUID(iid
, &IID_IDXGIFactory4
)
43 || IsEqualGUID(iid
, &IID_IDXGIFactory3
)
44 || IsEqualGUID(iid
, &IID_IDXGIFactory2
)
45 || (factory
->extended
&& IsEqualGUID(iid
, &IID_IDXGIFactory1
))
46 || IsEqualGUID(iid
, &IID_IDXGIFactory
)
47 || IsEqualGUID(iid
, &IID_IDXGIObject
)
48 || IsEqualGUID(iid
, &IID_IUnknown
))
50 IUnknown_AddRef(iface
);
55 WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
61 static ULONG STDMETHODCALLTYPE
dxgi_factory_AddRef(IWineDXGIFactory
*iface
)
63 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
64 ULONG refcount
= InterlockedIncrement(&factory
->refcount
);
66 TRACE("%p increasing refcount to %u.\n", iface
, refcount
);
71 static ULONG STDMETHODCALLTYPE
dxgi_factory_Release(IWineDXGIFactory
*iface
)
73 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
74 ULONG refcount
= InterlockedDecrement(&factory
->refcount
);
76 TRACE("%p decreasing refcount to %u.\n", iface
, refcount
);
80 if (factory
->device_window
)
81 DestroyWindow(factory
->device_window
);
84 wined3d_decref(factory
->wined3d
);
85 wined3d_mutex_unlock();
86 wined3d_private_store_cleanup(&factory
->private_store
);
93 static HRESULT STDMETHODCALLTYPE
dxgi_factory_SetPrivateData(IWineDXGIFactory
*iface
,
94 REFGUID guid
, UINT data_size
, const void *data
)
96 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
98 TRACE("iface %p, guid %s, data_size %u, data %p.\n", iface
, debugstr_guid(guid
), data_size
, data
);
100 return dxgi_set_private_data(&factory
->private_store
, guid
, data_size
, data
);
103 static HRESULT STDMETHODCALLTYPE
dxgi_factory_SetPrivateDataInterface(IWineDXGIFactory
*iface
,
104 REFGUID guid
, const IUnknown
*object
)
106 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
108 TRACE("iface %p, guid %s, object %p.\n", iface
, debugstr_guid(guid
), object
);
110 return dxgi_set_private_data_interface(&factory
->private_store
, guid
, object
);
113 static HRESULT STDMETHODCALLTYPE
dxgi_factory_GetPrivateData(IWineDXGIFactory
*iface
,
114 REFGUID guid
, UINT
*data_size
, void *data
)
116 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
118 TRACE("iface %p, guid %s, data_size %p, data %p.\n", iface
, debugstr_guid(guid
), data_size
, data
);
120 return dxgi_get_private_data(&factory
->private_store
, guid
, data_size
, data
);
123 static HRESULT STDMETHODCALLTYPE
dxgi_factory_GetParent(IWineDXGIFactory
*iface
, REFIID iid
, void **parent
)
125 WARN("iface %p, iid %s, parent %p.\n", iface
, debugstr_guid(iid
), parent
);
129 return E_NOINTERFACE
;
132 static HRESULT STDMETHODCALLTYPE
dxgi_factory_EnumAdapters1(IWineDXGIFactory
*iface
,
133 UINT adapter_idx
, IDXGIAdapter1
**adapter
)
135 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
136 struct dxgi_adapter
*adapter_object
;
140 TRACE("iface %p, adapter_idx %u, adapter %p.\n", iface
, adapter_idx
, adapter
);
143 return DXGI_ERROR_INVALID_CALL
;
145 wined3d_mutex_lock();
146 adapter_count
= wined3d_get_adapter_count(factory
->wined3d
);
147 wined3d_mutex_unlock();
149 if (adapter_idx
>= adapter_count
)
152 return DXGI_ERROR_NOT_FOUND
;
155 if (FAILED(hr
= dxgi_adapter_create(factory
, adapter_idx
, &adapter_object
)))
161 *adapter
= (IDXGIAdapter1
*)&adapter_object
->IWineDXGIAdapter_iface
;
163 TRACE("Returning adapter %p.\n", *adapter
);
168 static HRESULT STDMETHODCALLTYPE
dxgi_factory_EnumAdapters(IWineDXGIFactory
*iface
,
169 UINT adapter_idx
, IDXGIAdapter
**adapter
)
171 TRACE("iface %p, adapter_idx %u, adapter %p.\n", iface
, adapter_idx
, adapter
);
173 return dxgi_factory_EnumAdapters1(iface
, adapter_idx
, (IDXGIAdapter1
**)adapter
);
176 static HRESULT STDMETHODCALLTYPE
dxgi_factory_MakeWindowAssociation(IWineDXGIFactory
*iface
,
177 HWND window
, UINT flags
)
179 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
181 TRACE("iface %p, window %p, flags %#x.\n", iface
, window
, flags
);
183 if (flags
> DXGI_MWA_VALID
)
184 return DXGI_ERROR_INVALID_CALL
;
188 wined3d_unregister_windows(factory
->wined3d
);
192 if (!wined3d_register_window(factory
->wined3d
, window
, NULL
, flags
))
198 static HRESULT STDMETHODCALLTYPE
dxgi_factory_GetWindowAssociation(IWineDXGIFactory
*iface
, HWND
*window
)
200 TRACE("iface %p, window %p.\n", iface
, window
);
203 return DXGI_ERROR_INVALID_CALL
;
205 /* The tests show that this always returns NULL for some unknown reason. */
211 static HRESULT STDMETHODCALLTYPE
dxgi_factory_CreateSwapChain(IWineDXGIFactory
*iface
,
212 IUnknown
*device
, DXGI_SWAP_CHAIN_DESC
*desc
, IDXGISwapChain
**swapchain
)
214 struct dxgi_factory
*factory
= impl_from_IWineDXGIFactory(iface
);
215 DXGI_SWAP_CHAIN_FULLSCREEN_DESC fullscreen_desc
;
216 DXGI_SWAP_CHAIN_DESC1 swapchain_desc
;
218 TRACE("iface %p, device %p, desc %p, swapchain %p.\n", iface
, device
, desc
, swapchain
);
222 WARN("Invalid pointer.\n");
223 return DXGI_ERROR_INVALID_CALL
;
226 swapchain_desc
.Width
= desc
->BufferDesc
.Width
;
227 swapchain_desc
.Height
= desc
->BufferDesc
.Height
;
228 swapchain_desc
.Format
= desc
->BufferDesc
.Format
;
229 swapchain_desc
.Stereo
= FALSE
;
230 swapchain_desc
.SampleDesc
= desc
->SampleDesc
;
231 swapchain_desc
.BufferUsage
= desc
->BufferUsage
;
232 swapchain_desc
.BufferCount
= desc
->BufferCount
;
233 swapchain_desc
.Scaling
= DXGI_SCALING_STRETCH
;
234 swapchain_desc
.SwapEffect
= desc
->SwapEffect
;
235 swapchain_desc
.AlphaMode
= DXGI_ALPHA_MODE_IGNORE
;
236 swapchain_desc
.Flags
= desc
->Flags
;
238 fullscreen_desc
.RefreshRate
= desc
->BufferDesc
.RefreshRate
;
239 fullscreen_desc
.ScanlineOrdering
= desc
->BufferDesc
.ScanlineOrdering
;
240 fullscreen_desc
.Scaling
= desc
->BufferDesc
.Scaling
;
241 fullscreen_desc
.Windowed
= desc
->Windowed
;
243 return IWineDXGIFactory_CreateSwapChainForHwnd(&factory
->IWineDXGIFactory_iface
,
244 device
, desc
->OutputWindow
, &swapchain_desc
, &fullscreen_desc
, NULL
,
245 (IDXGISwapChain1
**)swapchain
);
248 static HRESULT STDMETHODCALLTYPE
dxgi_factory_CreateSoftwareAdapter(IWineDXGIFactory
*iface
,
249 HMODULE swrast
, IDXGIAdapter
**adapter
)
251 FIXME("iface %p, swrast %p, adapter %p stub!\n", iface
, swrast
, adapter
);
256 static BOOL STDMETHODCALLTYPE
dxgi_factory_IsCurrent(IWineDXGIFactory
*iface
)
258 FIXME("iface %p stub!\n", iface
);
263 static BOOL STDMETHODCALLTYPE
dxgi_factory_IsWindowedStereoEnabled(IWineDXGIFactory
*iface
)
265 FIXME("iface %p stub!\n", iface
);
270 static HRESULT STDMETHODCALLTYPE
dxgi_factory_CreateSwapChainForHwnd(IWineDXGIFactory
*iface
,
271 IUnknown
*device
, HWND window
, const DXGI_SWAP_CHAIN_DESC1
*desc
,
272 const DXGI_SWAP_CHAIN_FULLSCREEN_DESC
*fullscreen_desc
,
273 IDXGIOutput
*output
, IDXGISwapChain1
**swapchain
)
275 IWineDXGISwapChainFactory
*swapchain_factory
;
276 ID3D12CommandQueue
*command_queue
;
279 TRACE("iface %p, device %p, window %p, desc %p, fullscreen_desc %p, output %p, swapchain %p.\n",
280 iface
, device
, window
, desc
, fullscreen_desc
, output
, swapchain
);
282 if (!device
|| !window
|| !desc
|| !swapchain
)
284 WARN("Invalid pointer.\n");
285 return DXGI_ERROR_INVALID_CALL
;
290 FIXME("Stereo swapchains are not supported.\n");
291 return DXGI_ERROR_UNSUPPORTED
;
294 if (!dxgi_validate_swapchain_desc(desc
))
295 return DXGI_ERROR_INVALID_CALL
;
298 FIXME("Ignoring output %p.\n", output
);
300 if (SUCCEEDED(IUnknown_QueryInterface(device
, &IID_IWineDXGISwapChainFactory
, (void **)&swapchain_factory
)))
302 hr
= IWineDXGISwapChainFactory_create_swapchain(swapchain_factory
,
303 (IDXGIFactory
*)iface
, window
, desc
, fullscreen_desc
, output
, swapchain
);
304 IWineDXGISwapChainFactory_Release(swapchain_factory
);
308 if (SUCCEEDED(IUnknown_QueryInterface(device
, &IID_ID3D12CommandQueue
, (void **)&command_queue
)))
310 hr
= d3d12_swapchain_create(iface
, command_queue
, window
, desc
, fullscreen_desc
, swapchain
);
311 ID3D12CommandQueue_Release(command_queue
);
315 ERR("This is not the device we're looking for.\n");
316 return DXGI_ERROR_UNSUPPORTED
;
319 static HRESULT STDMETHODCALLTYPE
dxgi_factory_CreateSwapChainForCoreWindow(IWineDXGIFactory
*iface
,
320 IUnknown
*device
, IUnknown
*window
, const DXGI_SWAP_CHAIN_DESC1
*desc
,
321 IDXGIOutput
*output
, IDXGISwapChain1
**swapchain
)
323 FIXME("iface %p, device %p, window %p, desc %p, output %p, swapchain %p stub!\n",
324 iface
, device
, window
, desc
, output
, swapchain
);
329 static HRESULT STDMETHODCALLTYPE
dxgi_factory_GetSharedResourceAdapterLuid(IWineDXGIFactory
*iface
,
330 HANDLE resource
, LUID
*luid
)
332 FIXME("iface %p, resource %p, luid %p stub!\n", iface
, resource
, luid
);
337 static HRESULT STDMETHODCALLTYPE
dxgi_factory_RegisterOcclusionStatusWindow(IWineDXGIFactory
*iface
,
338 HWND window
, UINT message
, DWORD
*cookie
)
340 FIXME("iface %p, window %p, message %#x, cookie %p stub!\n",
341 iface
, window
, message
, cookie
);
346 static HRESULT STDMETHODCALLTYPE
dxgi_factory_RegisterStereoStatusEvent(IWineDXGIFactory
*iface
,
347 HANDLE event
, DWORD
*cookie
)
349 FIXME("iface %p, event %p, cookie %p stub!\n", iface
, event
, cookie
);
354 static void STDMETHODCALLTYPE
dxgi_factory_UnregisterStereoStatus(IWineDXGIFactory
*iface
, DWORD cookie
)
356 FIXME("iface %p, cookie %#x stub!\n", iface
, cookie
);
359 static HRESULT STDMETHODCALLTYPE
dxgi_factory_RegisterStereoStatusWindow(IWineDXGIFactory
*iface
,
360 HWND window
, UINT message
, DWORD
*cookie
)
362 FIXME("iface %p, window %p, message %#x, cookie %p stub!\n",
363 iface
, window
, message
, cookie
);
368 static HRESULT STDMETHODCALLTYPE
dxgi_factory_RegisterOcclusionStatusEvent(IWineDXGIFactory
*iface
,
369 HANDLE event
, DWORD
*cookie
)
371 FIXME("iface %p, event %p, cookie %p stub!\n", iface
, event
, cookie
);
376 static void STDMETHODCALLTYPE
dxgi_factory_UnregisterOcclusionStatus(IWineDXGIFactory
*iface
, DWORD cookie
)
378 FIXME("iface %p, cookie %#x stub!\n", iface
, cookie
);
381 static HRESULT STDMETHODCALLTYPE
dxgi_factory_CreateSwapChainForComposition(IWineDXGIFactory
*iface
,
382 IUnknown
*device
, const DXGI_SWAP_CHAIN_DESC1
*desc
, IDXGIOutput
*output
, IDXGISwapChain1
**swapchain
)
384 FIXME("iface %p, device %p, desc %p, output %p, swapchain %p stub!\n",
385 iface
, device
, desc
, output
, swapchain
);
390 static UINT STDMETHODCALLTYPE
dxgi_factory_GetCreationFlags(IWineDXGIFactory
*iface
)
392 FIXME("iface %p stub!\n", iface
);
397 static HRESULT STDMETHODCALLTYPE
dxgi_factory_EnumAdapterByLuid(IWineDXGIFactory
*iface
,
398 LUID luid
, REFIID iid
, void **adapter
)
400 unsigned int adapter_index
;
401 DXGI_ADAPTER_DESC1 desc
;
402 IDXGIAdapter1
*adapter1
;
405 TRACE("iface %p, luid %08x:%08x, iid %s, adapter %p.\n",
406 iface
, luid
.HighPart
, luid
.LowPart
, debugstr_guid(iid
), adapter
);
409 return DXGI_ERROR_INVALID_CALL
;
412 while ((hr
= dxgi_factory_EnumAdapters1(iface
, adapter_index
, &adapter1
)) == S_OK
)
414 if (FAILED(hr
= IDXGIAdapter1_GetDesc1(adapter1
, &desc
)))
416 WARN("Failed to get adapter %u desc, hr %#x.\n", adapter_index
, hr
);
421 if (desc
.AdapterLuid
.LowPart
== luid
.LowPart
422 && desc
.AdapterLuid
.HighPart
== luid
.HighPart
)
424 hr
= IDXGIAdapter1_QueryInterface(adapter1
, iid
, adapter
);
425 IDXGIAdapter1_Release(adapter1
);
429 IDXGIAdapter1_Release(adapter1
);
432 if (hr
!= DXGI_ERROR_NOT_FOUND
)
433 WARN("Failed to enumerate adapters, hr %#x.\n", hr
);
435 WARN("Adapter could not be found.\n");
436 return DXGI_ERROR_NOT_FOUND
;
439 static HRESULT STDMETHODCALLTYPE
dxgi_factory_EnumWarpAdapter(IWineDXGIFactory
*iface
,
440 REFIID iid
, void **adapter
)
442 FIXME("iface %p, iid %s, adapter %p stub!\n", iface
, debugstr_guid(iid
), adapter
);
447 static HRESULT STDMETHODCALLTYPE
dxgi_factory_CheckFeatureSupport(IWineDXGIFactory
*iface
,
448 DXGI_FEATURE feature
, void *feature_data
, UINT data_size
)
450 TRACE("iface %p, feature %#x, feature_data %p, data_size %u.\n",
451 iface
, feature
, feature_data
, data_size
);
455 case DXGI_FEATURE_PRESENT_ALLOW_TEARING
:
456 if (data_size
!= sizeof(BOOL
))
457 return DXGI_ERROR_INVALID_CALL
;
458 *(BOOL
*)feature_data
= TRUE
;
462 WARN("Unsupported feature %#x.\n", feature
);
463 return DXGI_ERROR_INVALID_CALL
;
467 static HRESULT STDMETHODCALLTYPE
dxgi_factory_EnumAdapterByGpuPreference(IWineDXGIFactory
*iface
,
468 UINT adapter_idx
, DXGI_GPU_PREFERENCE gpu_preference
, REFIID iid
, void **adapter
)
470 IDXGIAdapter1
*adapter_object
;
473 TRACE("iface %p, adapter_idx %u, gpu_preference %#x, iid %s, adapter %p.\n",
474 iface
, adapter_idx
, gpu_preference
, debugstr_guid(iid
), adapter
);
476 if (gpu_preference
!= DXGI_GPU_PREFERENCE_UNSPECIFIED
)
477 FIXME("Ignoring GPU preference %#x.\n", gpu_preference
);
479 if (FAILED(hr
= dxgi_factory_EnumAdapters1(iface
, adapter_idx
, &adapter_object
)))
482 hr
= IDXGIAdapter1_QueryInterface(adapter_object
, iid
, adapter
);
483 IDXGIAdapter1_Release(adapter_object
);
487 static HRESULT STDMETHODCALLTYPE
dxgi_factory_RegisterAdaptersChangedEvent(IWineDXGIFactory
*iface
,
488 HANDLE event
, DWORD
*cookie
)
490 FIXME("iface %p, event %p, cookie %p stub!\n", iface
, event
, cookie
);
495 static HRESULT STDMETHODCALLTYPE
dxgi_factory_UnregisterAdaptersChangedEvent(IWineDXGIFactory
*iface
,
498 FIXME("iface %p, cookie %#x stub!\n", iface
, cookie
);
503 static const struct IWineDXGIFactoryVtbl dxgi_factory_vtbl
=
505 dxgi_factory_QueryInterface
,
507 dxgi_factory_Release
,
508 dxgi_factory_SetPrivateData
,
509 dxgi_factory_SetPrivateDataInterface
,
510 dxgi_factory_GetPrivateData
,
511 dxgi_factory_GetParent
,
512 dxgi_factory_EnumAdapters
,
513 dxgi_factory_MakeWindowAssociation
,
514 dxgi_factory_GetWindowAssociation
,
515 dxgi_factory_CreateSwapChain
,
516 dxgi_factory_CreateSoftwareAdapter
,
517 /* IDXGIFactory1 methods */
518 dxgi_factory_EnumAdapters1
,
519 dxgi_factory_IsCurrent
,
520 /* IDXGIFactory2 methods */
521 dxgi_factory_IsWindowedStereoEnabled
,
522 dxgi_factory_CreateSwapChainForHwnd
,
523 dxgi_factory_CreateSwapChainForCoreWindow
,
524 dxgi_factory_GetSharedResourceAdapterLuid
,
525 dxgi_factory_RegisterStereoStatusWindow
,
526 dxgi_factory_RegisterStereoStatusEvent
,
527 dxgi_factory_UnregisterStereoStatus
,
528 dxgi_factory_RegisterOcclusionStatusWindow
,
529 dxgi_factory_RegisterOcclusionStatusEvent
,
530 dxgi_factory_UnregisterOcclusionStatus
,
531 dxgi_factory_CreateSwapChainForComposition
,
532 /* IDXGIFactory3 methods */
533 dxgi_factory_GetCreationFlags
,
534 /* IDXGIFactory4 methods */
535 dxgi_factory_EnumAdapterByLuid
,
536 dxgi_factory_EnumWarpAdapter
,
537 /* IDXIGFactory5 methods */
538 dxgi_factory_CheckFeatureSupport
,
539 /* IDXGIFactory6 methods */
540 dxgi_factory_EnumAdapterByGpuPreference
,
541 /* IDXGIFactory7 methods */
542 dxgi_factory_RegisterAdaptersChangedEvent
,
543 dxgi_factory_UnregisterAdaptersChangedEvent
,
546 struct dxgi_factory
*unsafe_impl_from_IDXGIFactory(IDXGIFactory
*iface
)
548 IWineDXGIFactory
*wine_factory
;
549 struct dxgi_factory
*factory
;
554 if (FAILED(hr
= IDXGIFactory_QueryInterface(iface
, &IID_IWineDXGIFactory
, (void **)&wine_factory
)))
556 ERR("Failed to get IWineDXGIFactory interface, hr %#x.\n", hr
);
559 assert(wine_factory
->lpVtbl
== &dxgi_factory_vtbl
);
560 factory
= CONTAINING_RECORD(wine_factory
, struct dxgi_factory
, IWineDXGIFactory_iface
);
561 IWineDXGIFactory_Release(wine_factory
);
565 static HRESULT
dxgi_factory_init(struct dxgi_factory
*factory
, BOOL extended
)
567 factory
->IWineDXGIFactory_iface
.lpVtbl
= &dxgi_factory_vtbl
;
568 factory
->refcount
= 1;
569 wined3d_private_store_init(&factory
->private_store
);
571 wined3d_mutex_lock();
572 factory
->wined3d
= wined3d_create(0);
573 wined3d_mutex_unlock();
574 if (!factory
->wined3d
)
576 wined3d_private_store_cleanup(&factory
->private_store
);
577 return DXGI_ERROR_UNSUPPORTED
;
580 factory
->extended
= extended
;
585 HRESULT
dxgi_factory_create(REFIID riid
, void **factory
, BOOL extended
)
587 struct dxgi_factory
*object
;
590 if (!(object
= heap_alloc_zero(sizeof(*object
))))
591 return E_OUTOFMEMORY
;
593 if (FAILED(hr
= dxgi_factory_init(object
, extended
)))
595 WARN("Failed to initialize factory, hr %#x.\n", hr
);
600 TRACE("Created factory %p.\n", object
);
602 hr
= IWineDXGIFactory_QueryInterface(&object
->IWineDXGIFactory_iface
, riid
, factory
);
603 IWineDXGIFactory_Release(&object
->IWineDXGIFactory_iface
);
607 HWND
dxgi_factory_get_device_window(struct dxgi_factory
*factory
)
609 wined3d_mutex_lock();
611 if (!factory
->device_window
)
613 if (!(factory
->device_window
= CreateWindowA("static", "DXGI device window",
614 WS_DISABLED
, 0, 0, 0, 0, NULL
, NULL
, NULL
, NULL
)))
616 wined3d_mutex_unlock();
617 ERR("Failed to create a window.\n");
620 TRACE("Created device window %p for factory %p.\n", factory
->device_window
, factory
);
623 wined3d_mutex_unlock();
625 return factory
->device_window
;