1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "DeviceManagerDx.h"
7 #include "D3D11Checks.h"
9 #include "GfxDriverInfo.h"
10 #include "gfxWindowsPlatform.h"
11 #include "mozilla/D3DMessageUtils.h"
12 #include "mozilla/StaticPrefs_gfx.h"
13 #include "mozilla/StaticPrefs_layers.h"
14 #include "mozilla/Telemetry.h"
15 #include "mozilla/gfx/GPUParent.h"
16 #include "mozilla/gfx/GPUProcessManager.h"
17 #include "mozilla/gfx/GraphicsMessages.h"
18 #include "mozilla/gfx/Logging.h"
19 #include "mozilla/gfx/gfxVars.h"
20 #include "mozilla/layers/CompositorBridgeChild.h"
21 #include "mozilla/layers/CompositorThread.h"
22 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
23 #include "mozilla/Preferences.h"
24 #include "nsPrintfCString.h"
37 using namespace mozilla::widget
;
38 using namespace mozilla::layers
;
40 StaticAutoPtr
<DeviceManagerDx
> DeviceManagerDx::sInstance
;
42 // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
43 // since it doesn't include d3d11.h, so we use a static here. It should only
44 // be used within InitializeD3D11.
45 decltype(D3D11CreateDevice
)* sD3D11CreateDeviceFn
= nullptr;
47 // It should only be used within CreateDirectCompositionDevice.
48 decltype(DCompositionCreateDevice2
)* sDcompCreateDevice2Fn
= nullptr;
49 decltype(DCompositionCreateDevice3
)* sDcompCreateDevice3Fn
= nullptr;
51 // It should only be used within CreateDCompSurfaceHandle
52 decltype(DCompositionCreateSurfaceHandle
)* sDcompCreateSurfaceHandleFn
=
55 // We don't have access to the DirectDrawCreateEx type in gfxWindowsPlatform.h,
56 // since it doesn't include ddraw.h, so we use a static here. It should only
57 // be used within InitializeDirectDrawConfig.
58 decltype(DirectDrawCreateEx
)* sDirectDrawCreateExFn
= nullptr;
61 void DeviceManagerDx::Init() { sInstance
= new DeviceManagerDx(); }
64 void DeviceManagerDx::Shutdown() { sInstance
= nullptr; }
66 DeviceManagerDx::DeviceManagerDx()
67 : mDeviceLock("gfxWindowsPlatform.mDeviceLock"),
68 mCompositorDeviceSupportsVideo(false) {
69 // Set up the D3D11 feature levels we can ask for.
70 mFeatureLevels
.AppendElement(D3D_FEATURE_LEVEL_11_1
);
71 mFeatureLevels
.AppendElement(D3D_FEATURE_LEVEL_11_0
);
72 mFeatureLevels
.AppendElement(D3D_FEATURE_LEVEL_10_1
);
73 mFeatureLevels
.AppendElement(D3D_FEATURE_LEVEL_10_0
);
74 MOZ_COUNT_CTOR(DeviceManagerDx
);
77 DeviceManagerDx::~DeviceManagerDx() { MOZ_COUNT_DTOR(DeviceManagerDx
); }
79 bool DeviceManagerDx::LoadD3D11() {
80 FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
81 MOZ_ASSERT(d3d11
.IsEnabled());
83 if (sD3D11CreateDeviceFn
) {
87 nsModuleHandle
module(LoadLibrarySystem32(L
"d3d11.dll"));
89 d3d11
.SetFailed(FeatureStatus::Unavailable
,
90 "Direct3D11 not available on this computer",
91 "FEATURE_FAILURE_D3D11_LIB"_ns
);
95 sD3D11CreateDeviceFn
=
96 (decltype(D3D11CreateDevice
)*)GetProcAddress(module
, "D3D11CreateDevice");
97 if (!sD3D11CreateDeviceFn
) {
98 // We should just be on Windows Vista or XP in this case.
99 d3d11
.SetFailed(FeatureStatus::Unavailable
,
100 "Direct3D11 not available on this computer",
101 "FEATURE_FAILURE_D3D11_FUNCPTR"_ns
);
105 mD3D11Module
.steal(module
);
109 bool DeviceManagerDx::LoadDcomp() {
110 MOZ_ASSERT(gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
).IsEnabled());
111 MOZ_ASSERT(gfxVars::UseWebRenderANGLE());
112 MOZ_ASSERT(gfxVars::UseWebRenderDCompWin());
114 if (sDcompCreateDevice2Fn
) {
115 return true; // Already loaded.
118 nsModuleHandle
module(LoadLibrarySystem32(L
"dcomp.dll"));
123 sDcompCreateDevice2Fn
= (decltype(DCompositionCreateDevice2
)*)GetProcAddress(
124 module
, "DCompositionCreateDevice2");
125 sDcompCreateDevice3Fn
= (decltype(DCompositionCreateDevice3
)*)GetProcAddress(
126 module
, "DCompositionCreateDevice3");
127 if (!sDcompCreateDevice2Fn
) {
131 // Load optional API for external compositing
132 sDcompCreateSurfaceHandleFn
=
133 (decltype(DCompositionCreateSurfaceHandle
)*)::GetProcAddress(
134 module
, "DCompositionCreateSurfaceHandle");
136 mDcompModule
.steal(module
);
140 void DeviceManagerDx::ReleaseD3D11() {
141 MOZ_ASSERT(!mCompositorDevice
);
142 MOZ_ASSERT(!mContentDevice
);
143 MOZ_ASSERT(!mVRDevice
);
144 MOZ_ASSERT(!mDecoderDevice
);
146 mD3D11Module
.reset();
147 sD3D11CreateDeviceFn
= nullptr;
150 nsTArray
<DXGI_OUTPUT_DESC1
> DeviceManagerDx::EnumerateOutputs() {
151 RefPtr
<IDXGIAdapter
> adapter
= GetDXGIAdapter();
154 NS_WARNING("Failed to acquire a DXGI adapter for enumerating outputs.");
155 return nsTArray
<DXGI_OUTPUT_DESC1
>();
158 nsTArray
<DXGI_OUTPUT_DESC1
> outputs
;
159 for (UINT i
= 0;; ++i
) {
160 RefPtr
<IDXGIOutput
> output
= nullptr;
161 if (FAILED(adapter
->EnumOutputs(i
, getter_AddRefs(output
)))) {
165 RefPtr
<IDXGIOutput6
> output6
= nullptr;
166 if (FAILED(output
->QueryInterface(__uuidof(IDXGIOutput6
),
167 getter_AddRefs(output6
)))) {
171 DXGI_OUTPUT_DESC1 desc
;
172 if (FAILED(output6
->GetDesc1(&desc
))) {
176 outputs
.AppendElement(desc
);
181 bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor
,
182 RefPtr
<IDXGIOutput
>* aOutOutput
) {
183 RefPtr
<IDXGIAdapter
> adapter
= GetDXGIAdapter();
186 NS_WARNING("Failed to acquire a DXGI adapter for GetOutputFromMonitor.");
190 for (UINT i
= 0;; ++i
) {
191 RefPtr
<IDXGIOutput
> output
= nullptr;
192 if (FAILED(adapter
->EnumOutputs(i
, getter_AddRefs(output
)))) {
196 DXGI_OUTPUT_DESC desc
;
197 if (FAILED(output
->GetDesc(&desc
))) {
201 if (desc
.Monitor
== monitor
) {
202 *aOutOutput
= output
;
209 void DeviceManagerDx::PostUpdateMonitorInfo() {
210 MOZ_ASSERT(XRE_IsGPUProcess());
211 MOZ_ASSERT(NS_IsMainThread());
213 MutexAutoLock
lock(mDeviceLock
);
214 // Reduce frequency of UpdateMonitorInfo() call.
215 if (mUpdateMonitorInfoRunnable
) {
219 auto* holder
= CompositorThreadHolder::GetSingleton();
224 mUpdateMonitorInfoRunnable
= NS_NewRunnableFunction(
225 "DeviceManagerDx::PostUpdateMonitorInfo::Runnable", []() -> void {
226 auto* dm
= gfx::DeviceManagerDx::Get();
228 dm
->UpdateMonitorInfo();
232 const uint32_t kDelayMS
= 100;
233 RefPtr
<Runnable
> runnable
= mUpdateMonitorInfoRunnable
;
234 holder
->GetCompositorThread()->DelayedDispatch(runnable
.forget(), kDelayMS
);
237 static bool ColorSpaceIsHDR(const DXGI_OUTPUT_DESC1
& aDesc
) {
238 // Set isHDR to true if the output has a BT2020 colorspace with EOTF2084
239 // gamma curve, this indicates the system is sending an HDR format to
240 // this monitor. The colorspace returned by DXGI is very vague - we only
241 // see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR and
242 // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the
243 // monitor is using something like YCbCr444 according to Settings
244 // (System -> Display Settings -> Advanced Display). To get more specific
245 // info we would need to query the DISPLAYCONFIG values in WinGDI.
247 // Note that we don't check bit depth here, since as of Windows 11 22H2,
248 // HDR is supported with 8bpc for lower bandwidth, where DWM converts to
249 // dithered RGB8 rather than RGB10, which doesn't really matter here.
251 // Since RefreshScreens(), the caller of this function, is triggered
252 // by WM_DISPLAYCHANGE, this will pick up changes to the monitors in
253 // all the important cases (resolution/color changes by the user).
256 // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range
257 // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level
258 bool isHDR
= (aDesc
.ColorSpace
== DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020
);
263 void DeviceManagerDx::UpdateMonitorInfo() {
264 bool systemHdrEnabled
= false;
265 std::set
<HMONITOR
> hdrMonitors
;
267 for (const auto desc
: EnumerateOutputs()) {
268 if (ColorSpaceIsHDR(desc
)) {
269 systemHdrEnabled
= true;
270 hdrMonitors
.emplace(desc
.Monitor
);
275 MutexAutoLock
lock(mDeviceLock
);
276 mSystemHdrEnabled
= Some(systemHdrEnabled
);
277 mHdrMonitors
.swap(hdrMonitors
);
278 mUpdateMonitorInfoRunnable
= nullptr;
282 bool DeviceManagerDx::SystemHDREnabled() {
284 MutexAutoLock
lock(mDeviceLock
);
285 if (mSystemHdrEnabled
.isSome()) {
286 return mSystemHdrEnabled
.ref();
292 MutexAutoLock
lock(mDeviceLock
);
293 return mSystemHdrEnabled
.ref();
296 bool DeviceManagerDx::WindowHDREnabled(HWND aWindow
) {
299 HMONITOR monitor
= ::MonitorFromWindow(aWindow
, MONITOR_DEFAULTTONEAREST
);
300 return MonitorHDREnabled(monitor
);
303 bool DeviceManagerDx::MonitorHDREnabled(HMONITOR aMonitor
) {
308 bool needInit
= false;
311 MutexAutoLock
lock(mDeviceLock
);
312 if (mSystemHdrEnabled
.isNothing()) {
321 MutexAutoLock
lock(mDeviceLock
);
322 MOZ_ASSERT(mSystemHdrEnabled
.isSome());
324 auto it
= mHdrMonitors
.find(aMonitor
);
325 if (it
== mHdrMonitors
.end()) {
332 void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport
& aRv
) {
333 RefPtr
<IDXGIAdapter
> adapter
= GetDXGIAdapter();
337 "Failed to acquire a DXGI adapter for checking hardware stretching "
343 for (UINT i
= 0;; ++i
) {
344 RefPtr
<IDXGIOutput
> output
= nullptr;
345 HRESULT result
= adapter
->EnumOutputs(i
, getter_AddRefs(output
));
346 if (result
== DXGI_ERROR_NOT_FOUND
) {
347 // No more outputs to check.
351 if (FAILED(result
)) {
356 RefPtr
<IDXGIOutput6
> output6
= nullptr;
357 if (FAILED(output
->QueryInterface(__uuidof(IDXGIOutput6
),
358 getter_AddRefs(output6
)))) {
364 if (FAILED(output6
->CheckHardwareCompositionSupport(&flags
))) {
369 bool fullScreen
= flags
& DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN
;
370 bool window
= flags
& DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED
;
371 if (fullScreen
&& window
) {
373 } else if (fullScreen
) {
374 ++aRv
.mFullScreenOnly
;
384 static inline bool ProcessOwnsCompositor() {
385 return XRE_GetProcessType() == GeckoProcessType_GPU
||
386 XRE_GetProcessType() == GeckoProcessType_VR
||
387 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS
));
391 bool DeviceManagerDx::CreateCompositorDevices() {
392 MutexAutoLock
lock(mDeviceLock
);
393 return CreateCompositorDevicesLocked();
396 bool DeviceManagerDx::CreateCompositorDevicesLocked() {
397 MOZ_ASSERT(ProcessOwnsCompositor());
399 FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
400 MOZ_ASSERT(d3d11
.IsEnabled());
402 if (int32_t sleepSec
=
403 StaticPrefs::gfx_direct3d11_sleep_on_create_device_AtStartup()) {
404 printf_stderr("Attach to PID: %lu\n", GetCurrentProcessId());
405 Sleep(sleepSec
* 1000);
412 CreateCompositorDevice(d3d11
);
414 if (!d3d11
.IsEnabled()) {
415 MOZ_ASSERT(!mCompositorDevice
);
421 // We leak these everywhere and we need them our entire runtime anyway, let's
422 // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
423 // as well for D2D1 and device resets.
424 mD3D11Module
.disown();
426 MOZ_ASSERT(mCompositorDevice
);
427 if (!d3d11
.IsEnabled()) {
431 // When WR is used, do not preload attachments for D3D11 Non-WR compositor.
433 // Fallback from WR to D3D11 Non-WR compositor without re-creating gpu process
434 // could happen when WR causes error. In this case, the attachments are loaded
436 if (gfx::gfxVars::UseSoftwareWebRender()) {
437 PreloadAttachmentsOnCompositorThread();
443 bool DeviceManagerDx::CreateVRDevice() {
444 MOZ_ASSERT(ProcessOwnsCompositor());
450 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
451 NS_WARNING("Direct3D11 Compositing required for VR");
459 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
461 NS_WARNING("Failed to acquire a DXGI adapter for VR");
465 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
468 if (!CreateDevice(adapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
, mVRDevice
)) {
469 gfxCriticalError() << "Crash during D3D11 device creation for VR";
473 if (FAILED(hr
) || !mVRDevice
) {
474 NS_WARNING("Failed to acquire a D3D11 device for VR");
481 bool DeviceManagerDx::CreateCanvasDevice() {
482 MutexAutoLock
lock(mDeviceLock
);
483 return CreateCanvasDeviceLocked();
486 bool DeviceManagerDx::CreateCanvasDeviceLocked() {
487 MOZ_ASSERT(ProcessOwnsCompositor());
497 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
499 NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
503 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
506 if (!CreateDevice(adapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
,
508 gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
513 gfx_direct2d_target_independent_rasterization_disabled_AtStartup()) {
514 int creationFlags
= 0x2; // disable target independent rasterization
515 const GUID D2D_INTERNAL_DEVICE_CREATION_OPTIONS
= {
519 {0x84, 0x42, 0x40, 0x43, 0xe0, 0xb0, 0x94, 0x95}};
520 mCanvasDevice
->SetPrivateData(D2D_INTERNAL_DEVICE_CREATION_OPTIONS
,
521 sizeof(creationFlags
), &creationFlags
);
524 if (FAILED(hr
) || !mCanvasDevice
) {
525 NS_WARNING("Failed to acquire a D3D11 device for Canvas");
529 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice
)) {
530 mCanvasDevice
= nullptr;
534 if (XRE_IsGPUProcess()) {
535 Factory::SetDirect3D11Device(mCanvasDevice
);
541 void DeviceManagerDx::CreateDirectCompositionDevice() {
542 MutexAutoLock
lock(mDeviceLock
);
543 CreateDirectCompositionDeviceLocked();
546 void DeviceManagerDx::CreateDirectCompositionDeviceLocked() {
547 if (!gfxVars::UseWebRenderDCompWin()) {
551 if (!mCompositorDevice
) {
559 RefPtr
<IDXGIDevice
> dxgiDevice
;
560 if (mCompositorDevice
->QueryInterface(
561 IID_PPV_ARGS((IDXGIDevice
**)getter_AddRefs(dxgiDevice
))) != S_OK
) {
566 RefPtr
<IDCompositionDesktopDevice
> desktopDevice
;
568 hr
= sDcompCreateDevice3Fn(
571 (IDCompositionDesktopDevice
**)getter_AddRefs(desktopDevice
)));
572 if (!desktopDevice
) {
573 hr
= sDcompCreateDevice2Fn(
576 (IDCompositionDesktopDevice
**)getter_AddRefs(desktopDevice
)));
579 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) { return; }
581 if (!SUCCEEDED(hr
)) {
585 RefPtr
<IDCompositionDevice2
> compositionDevice
;
586 if (desktopDevice
->QueryInterface(IID_PPV_ARGS(
587 (IDCompositionDevice2
**)getter_AddRefs(compositionDevice
))) != S_OK
) {
591 mDirectCompositionDevice
= compositionDevice
;
595 HANDLE
DeviceManagerDx::CreateDCompSurfaceHandle() {
596 if (!sDcompCreateSurfaceHandleFn
) {
601 HRESULT hr
= sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS
,
610 void DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus
& aDeviceStatus
) {
611 MOZ_ASSERT(!ProcessOwnsCompositor());
613 MutexAutoLock
lock(mDeviceLock
);
614 mDeviceStatus
= Some(aDeviceStatus
);
617 bool DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus
* aOut
) {
618 MutexAutoLock
lock(mDeviceLock
);
620 *aOut
= mDeviceStatus
.value();
627 void DeviceManagerDx::CreateContentDevices() {
628 MutexAutoLock
lock(mDeviceLock
);
629 CreateContentDevicesLocked();
632 void DeviceManagerDx::CreateContentDevicesLocked() {
633 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
));
639 // We should have been assigned a DeviceStatus from the parent process,
640 // GPU process, or the same process if using in-process compositing.
641 MOZ_RELEASE_ASSERT(mDeviceStatus
);
643 if (CreateContentDevice() == FeatureStatus::CrashedInHandler
) {
644 DisableD3D11AfterCrash();
648 already_AddRefed
<IDXGIAdapter1
> DeviceManagerDx::GetDXGIAdapter() {
649 MutexAutoLock
lock(mDeviceLock
);
650 return do_AddRef(GetDXGIAdapterLocked());
653 IDXGIAdapter1
* DeviceManagerDx::GetDXGIAdapterLocked() {
654 if (mAdapter
&& mFactory
&& mFactory
->IsCurrent()) {
660 nsModuleHandle
dxgiModule(LoadLibrarySystem32(L
"dxgi.dll"));
661 decltype(CreateDXGIFactory1
)* createDXGIFactory1
=
662 (decltype(CreateDXGIFactory1
)*)GetProcAddress(dxgiModule
,
663 "CreateDXGIFactory1");
664 if (!createDXGIFactory1
) {
667 static const auto fCreateDXGIFactory2
=
668 (decltype(CreateDXGIFactory2
)*)GetProcAddress(dxgiModule
,
669 "CreateDXGIFactory2");
671 // Try to use a DXGI 1.1 adapter in order to share resources
673 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) {
674 if (fCreateDXGIFactory2
) {
675 auto hr
= fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG
,
676 __uuidof(IDXGIFactory2
),
677 getter_AddRefs(mFactory
));
678 MOZ_ALWAYS_TRUE(!FAILED(hr
));
681 "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2.");
686 createDXGIFactory1(__uuidof(IDXGIFactory1
), getter_AddRefs(mFactory
));
687 if (FAILED(hr
) || !mFactory
) {
688 // This seems to happen with some people running the iZ3D driver.
689 // They won't get acceleration.
695 // Match the adapter to our mDeviceStatus, if possible.
696 for (UINT index
= 0;; index
++) {
697 RefPtr
<IDXGIAdapter1
> adapter
;
698 if (FAILED(mFactory
->EnumAdapters1(index
, getter_AddRefs(adapter
)))) {
702 const DxgiAdapterDesc
& preferred
= mDeviceStatus
->adapter();
704 DXGI_ADAPTER_DESC desc
;
705 if (SUCCEEDED(adapter
->GetDesc(&desc
)) &&
706 desc
.AdapterLuid
.HighPart
== preferred
.AdapterLuid
.HighPart
&&
707 desc
.AdapterLuid
.LowPart
== preferred
.AdapterLuid
.LowPart
&&
708 desc
.VendorId
== preferred
.VendorId
&&
709 desc
.DeviceId
== preferred
.DeviceId
) {
710 mAdapter
= adapter
.forget();
717 mDeviceStatus
.reset();
718 // Pick the first adapter available.
719 mFactory
->EnumAdapters1(0, getter_AddRefs(mAdapter
));
722 // We leak this module everywhere, we might as well do so here as well.
727 bool DeviceManagerDx::CreateCompositorDeviceHelper(
728 FeatureState
& aD3d11
, IDXGIAdapter1
* aAdapter
, bool aAttemptVideoSupport
,
729 RefPtr
<ID3D11Device
>& aOutDevice
) {
730 // Check if a failure was injected for testing.
731 if (StaticPrefs::gfx_testing_device_fail()) {
732 aD3d11
.SetFailed(FeatureStatus::Failed
,
733 "Direct3D11 device failure simulated by preference",
734 "FEATURE_FAILURE_D3D11_SIM"_ns
);
738 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
740 DXGI_ADAPTER_DESC desc
;
741 aAdapter
->GetDesc(&desc
);
742 if (desc
.VendorId
!= 0x1414) {
743 // 0x1414 is Microsoft (e.g. WARP)
744 // When not using WARP, use
745 // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS to prevent
746 // bug 1092260. IE 11 also uses this flag.
747 flags
|= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
;
750 if (aAttemptVideoSupport
) {
751 flags
|= D3D11_CREATE_DEVICE_VIDEO_SUPPORT
;
755 RefPtr
<ID3D11Device
> device
;
756 if (!CreateDevice(aAdapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
, device
)) {
757 if (!aAttemptVideoSupport
) {
758 gfxCriticalError() << "Crash during D3D11 device creation";
759 aD3d11
.SetFailed(FeatureStatus::CrashedInHandler
,
760 "Crashed trying to acquire a D3D11 device",
761 "FEATURE_FAILURE_D3D11_DEVICE1"_ns
);
766 if (FAILED(hr
) || !device
) {
767 if (!aAttemptVideoSupport
) {
768 aD3d11
.SetFailed(FeatureStatus::Failed
,
769 "Failed to acquire a D3D11 device",
770 "FEATURE_FAILURE_D3D11_DEVICE2"_ns
);
774 if (!D3D11Checks::DoesDeviceWork()) {
775 if (!aAttemptVideoSupport
) {
776 aD3d11
.SetFailed(FeatureStatus::Broken
,
777 "Direct3D11 device was determined to be broken",
778 "FEATURE_FAILURE_D3D11_BROKEN"_ns
);
787 // Note that it's enough for us to just use a counter for a unique ID,
788 // even though the counter isn't synchronized between processes. If we
789 // start in the GPU process and wind up in the parent process, the
790 // whole graphics stack is blown away anyway. But just in case, we
791 // make gpu process IDs negative and parent process IDs positive.
792 static inline int32_t GetNextDeviceCounter() {
793 static int32_t sDeviceCounter
= 0;
794 return XRE_IsGPUProcess() ? --sDeviceCounter
: ++sDeviceCounter
;
797 void DeviceManagerDx::CreateCompositorDevice(FeatureState
& d3d11
) {
798 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
799 CreateWARPCompositorDevice();
803 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
805 d3d11
.SetFailed(FeatureStatus::Unavailable
,
806 "Failed to acquire a DXGI adapter",
807 "FEATURE_FAILURE_D3D11_DXGI"_ns
);
811 if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter
)) {
812 d3d11
.SetFailed(FeatureStatus::Unavailable
,
813 "DXGI does not support out-of-process presentation",
814 "FEATURE_FAILURE_D3D11_REMOTE_PRESENT"_ns
);
818 RefPtr
<ID3D11Device
> device
;
819 if (!CreateCompositorDeviceHelper(d3d11
, adapter
, true, device
)) {
820 // Try again without video support and record that it failed.
821 mCompositorDeviceSupportsVideo
= false;
822 if (!CreateCompositorDeviceHelper(d3d11
, adapter
, false, device
)) {
826 mCompositorDeviceSupportsVideo
= true;
829 // Only test this when not using WARP since it can fail and cause
830 // GetDeviceRemovedReason to return weird values.
831 bool textureSharingWorks
= D3D11Checks::DoesTextureSharingWork(device
);
833 DXGI_ADAPTER_DESC desc
;
835 adapter
->GetDesc(&desc
);
837 if (!textureSharingWorks
) {
838 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE
, FeatureStatus::Broken
,
839 "Texture sharing doesn't work",
840 "FEATURE_FAILURE_HW_ANGLE_NEEDS_TEXTURE_SHARING"_ns
);
842 if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device
)) {
843 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE
, FeatureStatus::Broken
,
844 "RenderTargetViews need recreating",
845 "FEATURE_FAILURE_HW_ANGLE_NEEDS_RTV_RECREATION"_ns
);
847 if (XRE_IsParentProcess()) {
848 // It seems like this may only happen when we're using the NVIDIA gpu
849 D3D11Checks::WarnOnAdapterMismatch(device
);
852 RefPtr
<ID3D10Multithread
> multi
;
853 HRESULT hr
= device
->QueryInterface(__uuidof(ID3D10Multithread
),
854 getter_AddRefs(multi
));
855 if (SUCCEEDED(hr
) && multi
) {
856 multi
->SetMultithreadProtected(TRUE
);
859 uint32_t featureLevel
= device
->GetFeatureLevel();
860 auto formatOptions
= D3D11Checks::FormatOptions(device
);
861 mCompositorDevice
= device
;
863 int32_t sequenceNumber
= GetNextDeviceCounter();
864 mDeviceStatus
= Some(D3D11DeviceStatus(
865 false, textureSharingWorks
, featureLevel
, DxgiAdapterDesc::From(desc
),
866 sequenceNumber
, formatOptions
));
867 mCompositorDevice
->SetExceptionMode(0);
870 bool DeviceManagerDx::CreateDevice(IDXGIAdapter
* aAdapter
,
871 D3D_DRIVER_TYPE aDriverType
, UINT aFlags
,
873 RefPtr
<ID3D11Device
>& aOutDevice
) {
874 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup() ||
875 StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
876 aFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
880 aResOut
= sD3D11CreateDeviceFn(
881 aAdapter
, aDriverType
, nullptr, aFlags
, mFeatureLevels
.Elements(),
882 mFeatureLevels
.Length(), D3D11_SDK_VERSION
, getter_AddRefs(aOutDevice
),
885 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) { return false; }
887 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
889 if (!aOutDevice
) break;
891 RefPtr
<ID3D11Debug
> debug
;
892 if (!SUCCEEDED(aOutDevice
->QueryInterface(__uuidof(ID3D11Debug
),
893 getter_AddRefs(debug
))))
896 RefPtr
<ID3D11InfoQueue
> infoQueue
;
897 if (!SUCCEEDED(debug
->QueryInterface(__uuidof(ID3D11InfoQueue
),
898 getter_AddRefs(infoQueue
))))
901 D3D11_INFO_QUEUE_FILTER filter
;
904 // Disable warnings caused by Advanced Layers that are known and not
906 D3D11_MESSAGE_ID blockIDs
[] = {
907 D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL
};
908 filter
.DenyList
.NumIDs
= std::size(blockIDs
);
909 filter
.DenyList
.pIDList
= blockIDs
;
910 infoQueue
->PushStorageFilter(&filter
);
912 infoQueue
->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION
, true);
913 infoQueue
->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR
, true);
914 infoQueue
->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING
, true);
921 void DeviceManagerDx::CreateWARPCompositorDevice() {
922 ScopedGfxFeatureReporter
reporterWARP(
923 "D3D11-WARP", StaticPrefs::layers_d3d11_force_warp_AtStartup());
924 FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
927 RefPtr
<ID3D11Device
> device
;
929 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
930 // to prevent bug 1092260. IE 11 also uses this flag.
931 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
932 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP
, flags
, hr
, device
)) {
933 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
934 d3d11
.SetFailed(FeatureStatus::CrashedInHandler
,
935 "Crashed creating a D3D11 WARP device",
936 "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns
);
939 if (FAILED(hr
) || !device
) {
940 // This should always succeed... in theory.
941 gfxCriticalError() << "Failed to initialize WARP D3D11 device! "
943 d3d11
.SetFailed(FeatureStatus::Failed
,
944 "Failed to create a D3D11 WARP device",
945 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns
);
949 bool textureSharingWorks
= D3D11Checks::DoesTextureSharingWork(device
);
951 RefPtr
<ID3D10Multithread
> multi
;
952 hr
= device
->QueryInterface(__uuidof(ID3D10Multithread
),
953 getter_AddRefs(multi
));
954 if (SUCCEEDED(hr
) && multi
) {
955 multi
->SetMultithreadProtected(TRUE
);
958 DXGI_ADAPTER_DESC desc
;
959 D3D11Checks::GetDxgiDesc(device
, &desc
);
961 int featureLevel
= device
->GetFeatureLevel();
963 auto formatOptions
= D3D11Checks::FormatOptions(device
);
964 mCompositorDevice
= device
;
966 int32_t sequenceNumber
= GetNextDeviceCounter();
967 mDeviceStatus
= Some(D3D11DeviceStatus(
968 true, textureSharingWorks
, featureLevel
, DxgiAdapterDesc::From(desc
),
969 sequenceNumber
, formatOptions
));
970 mCompositorDevice
->SetExceptionMode(0);
972 reporterWARP
.SetSuccessful();
975 FeatureStatus
DeviceManagerDx::CreateContentDevice() {
976 RefPtr
<IDXGIAdapter1
> adapter
;
977 if (!mDeviceStatus
->isWARP()) {
978 adapter
= GetDXGIAdapterLocked();
980 gfxCriticalNote
<< "Could not get a DXGI adapter";
981 return FeatureStatus::Unavailable
;
986 RefPtr
<ID3D11Device
> device
;
988 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
989 D3D_DRIVER_TYPE type
=
990 mDeviceStatus
->isWARP() ? D3D_DRIVER_TYPE_WARP
: D3D_DRIVER_TYPE_UNKNOWN
;
991 if (!CreateDevice(adapter
, type
, flags
, hr
, device
)) {
993 << "Recovered from crash while creating a D3D11 content device";
994 gfxWindowsPlatform::RecordContentDeviceFailure(
995 TelemetryDeviceCode::Content
);
996 return FeatureStatus::CrashedInHandler
;
999 if (FAILED(hr
) || !device
) {
1000 gfxCriticalNote
<< "Failed to create a D3D11 content device: " << hexa(hr
);
1001 gfxWindowsPlatform::RecordContentDeviceFailure(
1002 TelemetryDeviceCode::Content
);
1003 return FeatureStatus::Failed
;
1006 // InitializeD2D() will abort early if the compositor device did not support
1007 // texture sharing. If we're in the content process, we can't rely on the
1008 // parent device alone: some systems have dual GPUs that are capable of
1009 // binding the parent and child processes to different GPUs. As a safety net,
1010 // we re-check texture sharing against the newly created D3D11 content device.
1011 // If it fails, we won't use Direct2D.
1012 if (XRE_IsContentProcess()) {
1013 if (!D3D11Checks::DoesTextureSharingWork(device
)) {
1014 return FeatureStatus::Failed
;
1017 DebugOnly
<bool> ok
= ContentAdapterIsParentAdapter(device
);
1021 mContentDevice
= device
;
1022 mContentDevice
->SetExceptionMode(0);
1024 RefPtr
<ID3D10Multithread
> multi
;
1025 hr
= mContentDevice
->QueryInterface(__uuidof(ID3D10Multithread
),
1026 getter_AddRefs(multi
));
1027 if (SUCCEEDED(hr
) && multi
) {
1028 multi
->SetMultithreadProtected(TRUE
);
1030 return FeatureStatus::Available
;
1033 RefPtr
<ID3D11Device
> DeviceManagerDx::CreateDecoderDevice(
1034 DeviceFlagSet aFlags
) {
1035 MutexAutoLock
lock(mDeviceLock
);
1037 if (!mDeviceStatus
) {
1041 bool isAMD
= mDeviceStatus
->adapter().VendorId
== 0x1002;
1042 bool reuseDevice
= false;
1043 if (gfxVars::ReuseDecoderDevice()) {
1047 gfxCriticalNoteOnce
<< "Always have to reuse decoder device on AMD";
1051 // Use mCompositorDevice for decoder device only for hardware WebRender.
1052 if (aFlags
.contains(DeviceFlag::isHardwareWebRenderInUse
) &&
1053 mCompositorDevice
&& mCompositorDeviceSupportsVideo
&&
1055 mDecoderDevice
= mCompositorDevice
;
1057 RefPtr
<ID3D10Multithread
> multi
;
1058 mDecoderDevice
->QueryInterface(__uuidof(ID3D10Multithread
),
1059 getter_AddRefs(multi
));
1061 MOZ_ASSERT(multi
->GetMultithreadProtected());
1065 if (mDecoderDevice
) {
1066 RefPtr
<ID3D11Device
> dev
= mDecoderDevice
;
1067 return dev
.forget();
1071 if (!sD3D11CreateDeviceFn
) {
1072 // We should just be on Windows Vista or XP in this case.
1076 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
1082 RefPtr
<ID3D11Device
> device
;
1084 UINT flags
= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
1085 D3D11_CREATE_DEVICE_VIDEO_SUPPORT
;
1086 if (!CreateDevice(adapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
, device
)) {
1089 if (FAILED(hr
) || !device
|| !D3D11Checks::DoesDeviceWork()) {
1093 RefPtr
<ID3D10Multithread
> multi
;
1094 device
->QueryInterface(__uuidof(ID3D10Multithread
), getter_AddRefs(multi
));
1096 multi
->SetMultithreadProtected(TRUE
);
1099 mDecoderDevice
= device
;
1104 // ID3D11DeviceChild, IDXGIObject and ID3D11Device implement SetPrivateData with
1105 // the exact same parameters.
1106 template <typename T
>
1107 static HRESULT
SetDebugName(T
* d3d11Object
, const char* debugString
) {
1108 return d3d11Object
->SetPrivateData(WKPDID_D3DDebugObjectName
,
1109 strlen(debugString
), debugString
);
1112 RefPtr
<ID3D11Device
> DeviceManagerDx::CreateMediaEngineDevice() {
1113 MutexAutoLock
lock(mDeviceLock
);
1119 RefPtr
<ID3D11Device
> device
;
1120 UINT flags
= D3D11_CREATE_DEVICE_VIDEO_SUPPORT
|
1121 D3D11_CREATE_DEVICE_BGRA_SUPPORT
|
1122 D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
;
1123 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE
, flags
, hr
, device
)) {
1126 if (FAILED(hr
) || !device
|| !D3D11Checks::DoesDeviceWork()) {
1129 Unused
<< SetDebugName(device
.get(), "MFMediaEngineDevice");
1131 RefPtr
<ID3D10Multithread
> multi
;
1132 device
->QueryInterface(__uuidof(ID3D10Multithread
), getter_AddRefs(multi
));
1134 multi
->SetMultithreadProtected(TRUE
);
1139 void DeviceManagerDx::ResetDevices() {
1140 MutexAutoLock
lock(mDeviceLock
);
1141 ResetDevicesLocked();
1144 void DeviceManagerDx::ResetDevicesLocked() {
1146 mCompositorAttachments
= nullptr;
1147 mCompositorDevice
= nullptr;
1148 mContentDevice
= nullptr;
1149 mCanvasDevice
= nullptr;
1150 mImageDevice
= nullptr;
1151 mVRDevice
= nullptr;
1152 mDecoderDevice
= nullptr;
1153 mDirectCompositionDevice
= nullptr;
1154 mDeviceStatus
= Nothing();
1155 mDeviceResetReason
= Nothing();
1156 Factory::SetDirect3D11Device(nullptr);
1159 bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
1160 MutexAutoLock
lock(mDeviceLock
);
1162 DeviceResetReason resetReason
;
1163 if (!HasDeviceResetLocked(&resetReason
)) {
1167 GPUProcessManager::RecordDeviceReset(resetReason
);
1169 bool createCompositorDevice
= !!mCompositorDevice
;
1170 bool createContentDevice
= !!mContentDevice
;
1171 bool createCanvasDevice
= !!mCanvasDevice
;
1172 bool createDirectCompositionDevice
= !!mDirectCompositionDevice
;
1174 ResetDevicesLocked();
1176 if (createCompositorDevice
&& !CreateCompositorDevicesLocked()) {
1177 // Just stop, don't try anything more
1180 if (createContentDevice
) {
1181 CreateContentDevicesLocked();
1183 if (createCanvasDevice
) {
1184 CreateCanvasDeviceLocked();
1186 if (createDirectCompositionDevice
) {
1187 CreateDirectCompositionDeviceLocked();
1193 bool DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device
* device
) {
1194 DXGI_ADAPTER_DESC desc
;
1195 if (!D3D11Checks::GetDxgiDesc(device
, &desc
)) {
1196 gfxCriticalNote
<< "Could not query device DXGI adapter info";
1200 const DxgiAdapterDesc
& preferred
= mDeviceStatus
->adapter();
1202 if (desc
.VendorId
!= preferred
.VendorId
||
1203 desc
.DeviceId
!= preferred
.DeviceId
||
1204 desc
.SubSysId
!= preferred
.SubSysId
||
1205 desc
.AdapterLuid
.HighPart
!= preferred
.AdapterLuid
.HighPart
||
1206 desc
.AdapterLuid
.LowPart
!= preferred
.AdapterLuid
.LowPart
) {
1207 gfxCriticalNote
<< "VendorIDMismatch P " << hexa(preferred
.VendorId
) << " "
1208 << hexa(desc
.VendorId
);
1215 static DeviceResetReason
HResultToResetReason(HRESULT hr
) {
1217 case DXGI_ERROR_DEVICE_HUNG
:
1218 return DeviceResetReason::HUNG
;
1219 case DXGI_ERROR_DEVICE_REMOVED
:
1220 return DeviceResetReason::REMOVED
;
1221 case DXGI_ERROR_DEVICE_RESET
:
1222 return DeviceResetReason::RESET
;
1223 case DXGI_ERROR_DRIVER_INTERNAL_ERROR
:
1224 return DeviceResetReason::DRIVER_ERROR
;
1225 case DXGI_ERROR_INVALID_CALL
:
1226 return DeviceResetReason::INVALID_CALL
;
1228 return DeviceResetReason::OUT_OF_MEMORY
;
1232 return DeviceResetReason::OTHER
;
1235 bool DeviceManagerDx::HasDeviceReset(DeviceResetReason
* aOutReason
) {
1236 MutexAutoLock
lock(mDeviceLock
);
1237 return HasDeviceResetLocked(aOutReason
);
1240 bool DeviceManagerDx::HasDeviceResetLocked(DeviceResetReason
* aOutReason
) {
1241 if (mDeviceResetReason
) {
1243 *aOutReason
= mDeviceResetReason
.value();
1248 DeviceResetReason reason
;
1249 if (GetAnyDeviceRemovedReason(&reason
)) {
1250 mDeviceResetReason
= Some(reason
);
1252 *aOutReason
= reason
;
1260 static inline bool DidDeviceReset(const RefPtr
<ID3D11Device
>& aDevice
,
1261 DeviceResetReason
* aOutReason
) {
1265 HRESULT hr
= aDevice
->GetDeviceRemovedReason();
1270 *aOutReason
= HResultToResetReason(hr
);
1274 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason
* aOutReason
) {
1275 if (DidDeviceReset(mCompositorDevice
, aOutReason
) ||
1276 DidDeviceReset(mContentDevice
, aOutReason
) ||
1277 DidDeviceReset(mCanvasDevice
, aOutReason
)) {
1281 if (XRE_IsParentProcess() && NS_IsMainThread() &&
1282 StaticPrefs::gfx_testing_device_reset()) {
1283 Preferences::SetInt("gfx.testing.device-reset", 0);
1284 *aOutReason
= DeviceResetReason::FORCED_RESET
;
1291 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason
) {
1292 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON
,
1295 MutexAutoLock
lock(mDeviceLock
);
1296 if (!mDeviceResetReason
) {
1297 mDeviceResetReason
= Some(DeviceResetReason::FORCED_RESET
);
1302 void DeviceManagerDx::DisableD3D11AfterCrash() {
1303 gfxConfig::Disable(Feature::D3D11_COMPOSITING
,
1304 FeatureStatus::CrashedInHandler
,
1305 "Crashed while acquiring a Direct3D11 device",
1306 "FEATURE_FAILURE_D3D11_CRASH"_ns
);
1310 RefPtr
<ID3D11Device
> DeviceManagerDx::GetCompositorDevice() {
1311 /// ID3D11Device is thread-safe. We need the lock to read the
1312 /// mDeviceLockPointer, but manipulating the pointee outside of the lock is
1314 /// https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-render-multi-thread-intro
1315 MutexAutoLock
lock(mDeviceLock
);
1316 return mCompositorDevice
;
1319 RefPtr
<ID3D11Device
> DeviceManagerDx::GetContentDevice() {
1320 MOZ_ASSERT(XRE_IsGPUProcess() ||
1321 gfxPlatform::GetPlatform()->DevicesInitialized());
1323 MutexAutoLock
lock(mDeviceLock
);
1324 return mContentDevice
;
1327 RefPtr
<ID3D11Device
> DeviceManagerDx::GetImageDevice() {
1328 MutexAutoLock
lock(mDeviceLock
);
1330 return mImageDevice
;
1333 RefPtr
<ID3D11Device
> device
= mContentDevice
;
1335 device
= mCompositorDevice
;
1342 RefPtr
<ID3D10Multithread
> multi
;
1344 device
->QueryInterface((ID3D10Multithread
**)getter_AddRefs(multi
));
1345 if (FAILED(hr
) || !multi
) {
1346 gfxWarning() << "Multithread safety interface not supported. " << hr
;
1349 MOZ_ASSERT(multi
->GetMultithreadProtected());
1352 mImageDevice
= device
;
1354 return mImageDevice
;
1357 RefPtr
<ID3D11Device
> DeviceManagerDx::GetVRDevice() {
1358 MutexAutoLock
lock(mDeviceLock
);
1365 RefPtr
<ID3D11Device
> DeviceManagerDx::GetCanvasDevice() {
1366 MutexAutoLock
lock(mDeviceLock
);
1367 return mCanvasDevice
;
1370 RefPtr
<IDCompositionDevice2
> DeviceManagerDx::GetDirectCompositionDevice() {
1371 MutexAutoLock
lock(mDeviceLock
);
1372 return mDirectCompositionDevice
;
1375 unsigned DeviceManagerDx::GetCompositorFeatureLevel() const {
1376 MutexAutoLock
lock(mDeviceLock
);
1377 if (!mDeviceStatus
) {
1380 return mDeviceStatus
->featureLevel();
1383 bool DeviceManagerDx::TextureSharingWorks() {
1384 MutexAutoLock
lock(mDeviceLock
);
1385 if (!mDeviceStatus
) {
1388 return mDeviceStatus
->textureSharingWorks();
1391 bool DeviceManagerDx::CanInitializeKeyedMutexTextures() {
1392 MutexAutoLock
lock(mDeviceLock
);
1393 return mDeviceStatus
&& StaticPrefs::gfx_direct3d11_allow_keyed_mutex() &&
1394 gfxVars::AllowD3D11KeyedMutex();
1397 bool DeviceManagerDx::IsWARP() {
1398 MutexAutoLock
lock(mDeviceLock
);
1399 if (!mDeviceStatus
) {
1402 return mDeviceStatus
->isWARP();
1405 bool DeviceManagerDx::CanUseNV12() {
1406 MutexAutoLock
lock(mDeviceLock
);
1407 if (!mDeviceStatus
) {
1410 return mDeviceStatus
->formatOptions().contains(
1411 D3D11Checks::VideoFormatOption::NV12
);
1414 bool DeviceManagerDx::CanUseP010() {
1415 MutexAutoLock
lock(mDeviceLock
);
1416 if (!mDeviceStatus
) {
1419 return mDeviceStatus
->formatOptions().contains(
1420 D3D11Checks::VideoFormatOption::P010
);
1423 bool DeviceManagerDx::CanUseP016() {
1424 MutexAutoLock
lock(mDeviceLock
);
1425 if (!mDeviceStatus
) {
1428 return mDeviceStatus
->formatOptions().contains(
1429 D3D11Checks::VideoFormatOption::P016
);
1432 bool DeviceManagerDx::CanUseDComp() {
1433 MutexAutoLock
lock(mDeviceLock
);
1434 return !!mDirectCompositionDevice
;
1437 void DeviceManagerDx::InitializeDirectDraw() {
1438 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
1441 // Already initialized.
1445 FeatureState
& ddraw
= gfxConfig::GetFeature(Feature::DIRECT_DRAW
);
1446 if (!ddraw
.IsEnabled()) {
1450 // Check if DirectDraw is available on this system.
1451 mDirectDrawDLL
.own(LoadLibrarySystem32(L
"ddraw.dll"));
1452 if (!mDirectDrawDLL
) {
1453 ddraw
.SetFailed(FeatureStatus::Unavailable
,
1454 "DirectDraw not available on this computer",
1455 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1459 sDirectDrawCreateExFn
= (decltype(DirectDrawCreateEx
)*)GetProcAddress(
1460 mDirectDrawDLL
, "DirectDrawCreateEx");
1461 if (!sDirectDrawCreateExFn
) {
1462 ddraw
.SetFailed(FeatureStatus::Unavailable
,
1463 "DirectDraw not available on this computer",
1464 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1470 hr
= sDirectDrawCreateExFn(nullptr, getter_AddRefs(mDirectDraw
),
1471 IID_IDirectDraw7
, nullptr);
1473 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1474 ddraw
.SetFailed(FeatureStatus::Failed
, "Failed to create DirectDraw",
1475 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1476 gfxCriticalNote
<< "DoesCreatingDirectDrawFailed";
1480 ddraw
.SetFailed(FeatureStatus::Failed
, "Failed to create DirectDraw",
1481 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1482 gfxCriticalNote
<< "DoesCreatingDirectDrawFailed " << hexa(hr
);
1487 IDirectDraw7
* DeviceManagerDx::GetDirectDraw() { return mDirectDraw
; }
1489 void DeviceManagerDx::GetCompositorDevices(
1490 RefPtr
<ID3D11Device
>* aOutDevice
,
1491 RefPtr
<layers::DeviceAttachmentsD3D11
>* aOutAttachments
) {
1492 RefPtr
<ID3D11Device
> device
;
1494 MutexAutoLock
lock(mDeviceLock
);
1495 if (!mCompositorDevice
) {
1498 if (mCompositorAttachments
) {
1499 *aOutDevice
= mCompositorDevice
;
1500 *aOutAttachments
= mCompositorAttachments
;
1504 // Otherwise, we'll try to create attachments outside the lock.
1505 device
= mCompositorDevice
;
1508 // We save the attachments object even if it fails to initialize, so the
1509 // compositor can grab the failure ID.
1510 RefPtr
<layers::DeviceAttachmentsD3D11
> attachments
=
1511 layers::DeviceAttachmentsD3D11::Create(device
);
1513 MutexAutoLock
lock(mDeviceLock
);
1514 if (device
!= mCompositorDevice
) {
1517 mCompositorAttachments
= attachments
;
1520 *aOutDevice
= device
;
1521 *aOutAttachments
= attachments
;
1525 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
1526 if (!CompositorThread()) {
1530 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
1531 "DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void {
1532 if (DeviceManagerDx
* dm
= DeviceManagerDx::Get()) {
1533 RefPtr
<ID3D11Device
> device
;
1534 RefPtr
<layers::DeviceAttachmentsD3D11
> attachments
;
1535 dm
->GetCompositorDevices(&device
, &attachments
);
1538 CompositorThread()->Dispatch(task
.forget());
1542 } // namespace mozilla