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::CheckHardwareStretchingSupport(HwStretchingSupport
& aRv
) {
210 RefPtr
<IDXGIAdapter
> adapter
= GetDXGIAdapter();
214 "Failed to acquire a DXGI adapter for checking hardware stretching "
220 for (UINT i
= 0;; ++i
) {
221 RefPtr
<IDXGIOutput
> output
= nullptr;
222 HRESULT result
= adapter
->EnumOutputs(i
, getter_AddRefs(output
));
223 if (result
== DXGI_ERROR_NOT_FOUND
) {
224 // No more outputs to check.
228 if (FAILED(result
)) {
233 RefPtr
<IDXGIOutput6
> output6
= nullptr;
234 if (FAILED(output
->QueryInterface(__uuidof(IDXGIOutput6
),
235 getter_AddRefs(output6
)))) {
241 if (FAILED(output6
->CheckHardwareCompositionSupport(&flags
))) {
246 bool fullScreen
= flags
& DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN
;
247 bool window
= flags
& DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED
;
248 if (fullScreen
&& window
) {
250 } else if (fullScreen
) {
251 ++aRv
.mFullScreenOnly
;
261 static inline bool ProcessOwnsCompositor() {
262 return XRE_GetProcessType() == GeckoProcessType_GPU
||
263 XRE_GetProcessType() == GeckoProcessType_VR
||
264 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS
));
268 bool DeviceManagerDx::CreateCompositorDevices() {
269 MutexAutoLock
lock(mDeviceLock
);
270 return CreateCompositorDevicesLocked();
273 bool DeviceManagerDx::CreateCompositorDevicesLocked() {
274 MOZ_ASSERT(ProcessOwnsCompositor());
276 FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
277 MOZ_ASSERT(d3d11
.IsEnabled());
279 if (int32_t sleepSec
=
280 StaticPrefs::gfx_direct3d11_sleep_on_create_device_AtStartup()) {
281 printf_stderr("Attach to PID: %lu\n", GetCurrentProcessId());
282 Sleep(sleepSec
* 1000);
289 CreateCompositorDevice(d3d11
);
291 if (!d3d11
.IsEnabled()) {
292 MOZ_ASSERT(!mCompositorDevice
);
298 // We leak these everywhere and we need them our entire runtime anyway, let's
299 // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
300 // as well for D2D1 and device resets.
301 mD3D11Module
.disown();
303 MOZ_ASSERT(mCompositorDevice
);
304 if (!d3d11
.IsEnabled()) {
308 // When WR is used, do not preload attachments for D3D11 Non-WR compositor.
310 // Fallback from WR to D3D11 Non-WR compositor without re-creating gpu process
311 // could happen when WR causes error. In this case, the attachments are loaded
313 if (gfx::gfxVars::UseSoftwareWebRender()) {
314 PreloadAttachmentsOnCompositorThread();
320 bool DeviceManagerDx::CreateVRDevice() {
321 MOZ_ASSERT(ProcessOwnsCompositor());
327 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
)) {
328 NS_WARNING("Direct3D11 Compositing required for VR");
336 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
338 NS_WARNING("Failed to acquire a DXGI adapter for VR");
342 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
345 if (!CreateDevice(adapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
, mVRDevice
)) {
346 gfxCriticalError() << "Crash during D3D11 device creation for VR";
350 if (FAILED(hr
) || !mVRDevice
) {
351 NS_WARNING("Failed to acquire a D3D11 device for VR");
358 bool DeviceManagerDx::CreateCanvasDevice() {
359 MutexAutoLock
lock(mDeviceLock
);
360 return CreateCanvasDeviceLocked();
363 bool DeviceManagerDx::CreateCanvasDeviceLocked() {
364 MOZ_ASSERT(ProcessOwnsCompositor());
374 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
376 NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
380 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
383 if (!CreateDevice(adapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
,
385 gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
390 gfx_direct2d_target_independent_rasterization_disabled_AtStartup()) {
391 int creationFlags
= 0x2; // disable target independent rasterization
392 const GUID D2D_INTERNAL_DEVICE_CREATION_OPTIONS
= {
396 {0x84, 0x42, 0x40, 0x43, 0xe0, 0xb0, 0x94, 0x95}};
397 mCanvasDevice
->SetPrivateData(D2D_INTERNAL_DEVICE_CREATION_OPTIONS
,
398 sizeof(creationFlags
), &creationFlags
);
401 if (FAILED(hr
) || !mCanvasDevice
) {
402 NS_WARNING("Failed to acquire a D3D11 device for Canvas");
406 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice
)) {
407 mCanvasDevice
= nullptr;
411 if (XRE_IsGPUProcess()) {
412 Factory::SetDirect3D11Device(mCanvasDevice
);
418 void DeviceManagerDx::CreateDirectCompositionDevice() {
419 MutexAutoLock
lock(mDeviceLock
);
420 CreateDirectCompositionDeviceLocked();
423 void DeviceManagerDx::CreateDirectCompositionDeviceLocked() {
424 if (!gfxVars::UseWebRenderDCompWin()) {
428 if (!mCompositorDevice
) {
436 RefPtr
<IDXGIDevice
> dxgiDevice
;
437 if (mCompositorDevice
->QueryInterface(
438 IID_PPV_ARGS((IDXGIDevice
**)getter_AddRefs(dxgiDevice
))) != S_OK
) {
443 RefPtr
<IDCompositionDesktopDevice
> desktopDevice
;
445 hr
= sDcompCreateDevice3Fn(
448 (IDCompositionDesktopDevice
**)getter_AddRefs(desktopDevice
)));
449 if (!desktopDevice
) {
450 hr
= sDcompCreateDevice2Fn(
453 (IDCompositionDesktopDevice
**)getter_AddRefs(desktopDevice
)));
456 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) { return; }
458 if (!SUCCEEDED(hr
)) {
462 RefPtr
<IDCompositionDevice2
> compositionDevice
;
463 if (desktopDevice
->QueryInterface(IID_PPV_ARGS(
464 (IDCompositionDevice2
**)getter_AddRefs(compositionDevice
))) != S_OK
) {
468 mDirectCompositionDevice
= compositionDevice
;
472 HANDLE
DeviceManagerDx::CreateDCompSurfaceHandle() {
473 if (!sDcompCreateSurfaceHandleFn
) {
478 HRESULT hr
= sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS
,
487 void DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus
& aDeviceStatus
) {
488 MOZ_ASSERT(!ProcessOwnsCompositor());
490 MutexAutoLock
lock(mDeviceLock
);
491 mDeviceStatus
= Some(aDeviceStatus
);
494 bool DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus
* aOut
) {
495 MutexAutoLock
lock(mDeviceLock
);
497 *aOut
= mDeviceStatus
.value();
504 void DeviceManagerDx::CreateContentDevices() {
505 MutexAutoLock
lock(mDeviceLock
);
506 CreateContentDevicesLocked();
509 void DeviceManagerDx::CreateContentDevicesLocked() {
510 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING
));
516 // We should have been assigned a DeviceStatus from the parent process,
517 // GPU process, or the same process if using in-process compositing.
518 MOZ_ASSERT(mDeviceStatus
);
520 if (CreateContentDevice() == FeatureStatus::CrashedInHandler
) {
521 DisableD3D11AfterCrash();
525 already_AddRefed
<IDXGIAdapter1
> DeviceManagerDx::GetDXGIAdapter() {
526 MutexAutoLock
lock(mDeviceLock
);
527 return do_AddRef(GetDXGIAdapterLocked());
530 IDXGIAdapter1
* DeviceManagerDx::GetDXGIAdapterLocked() {
535 nsModuleHandle
dxgiModule(LoadLibrarySystem32(L
"dxgi.dll"));
536 decltype(CreateDXGIFactory1
)* createDXGIFactory1
=
537 (decltype(CreateDXGIFactory1
)*)GetProcAddress(dxgiModule
,
538 "CreateDXGIFactory1");
539 if (!createDXGIFactory1
) {
542 static const auto fCreateDXGIFactory2
=
543 (decltype(CreateDXGIFactory2
)*)GetProcAddress(dxgiModule
,
544 "CreateDXGIFactory2");
546 // Try to use a DXGI 1.1 adapter in order to share resources
548 RefPtr
<IDXGIFactory1
> factory1
;
549 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) {
550 RefPtr
<IDXGIFactory2
> factory2
;
551 if (fCreateDXGIFactory2
) {
552 auto hr
= fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG
,
553 __uuidof(IDXGIFactory2
),
554 getter_AddRefs(factory2
));
555 MOZ_ALWAYS_TRUE(!FAILED(hr
));
558 "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2.");
564 createDXGIFactory1(__uuidof(IDXGIFactory1
), getter_AddRefs(factory1
));
565 if (FAILED(hr
) || !factory1
) {
566 // This seems to happen with some people running the iZ3D driver.
567 // They won't get acceleration.
572 if (!mDeviceStatus
) {
573 // If we haven't created a device yet, and have no existing device status,
574 // then this must be the compositor device. Pick the first adapter we can.
575 if (FAILED(factory1
->EnumAdapters1(0, getter_AddRefs(mAdapter
)))) {
579 // In the UI and GPU process, we clear mDeviceStatus on device reset, so we
580 // should never reach here. Furthermore, the UI process does not create
581 // devices when using a GPU process.
583 // So, this should only ever get called on the content process or RDD
585 MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsRDDProcess());
587 // In the child process, we search for the adapter that matches the parent
588 // process. The first adapter can be mismatched on dual-GPU systems.
589 for (UINT index
= 0;; index
++) {
590 RefPtr
<IDXGIAdapter1
> adapter
;
591 if (FAILED(factory1
->EnumAdapters1(index
, getter_AddRefs(adapter
)))) {
595 const DxgiAdapterDesc
& preferred
= mDeviceStatus
->adapter();
597 DXGI_ADAPTER_DESC desc
;
598 if (SUCCEEDED(adapter
->GetDesc(&desc
)) &&
599 desc
.AdapterLuid
.HighPart
== preferred
.AdapterLuid
.HighPart
&&
600 desc
.AdapterLuid
.LowPart
== preferred
.AdapterLuid
.LowPart
&&
601 desc
.VendorId
== preferred
.VendorId
&&
602 desc
.DeviceId
== preferred
.DeviceId
) {
603 mAdapter
= adapter
.forget();
613 // We leak this module everywhere, we might as well do so here as well.
618 bool DeviceManagerDx::CreateCompositorDeviceHelper(
619 FeatureState
& aD3d11
, IDXGIAdapter1
* aAdapter
, bool aAttemptVideoSupport
,
620 RefPtr
<ID3D11Device
>& aOutDevice
) {
621 // Check if a failure was injected for testing.
622 if (StaticPrefs::gfx_testing_device_fail()) {
623 aD3d11
.SetFailed(FeatureStatus::Failed
,
624 "Direct3D11 device failure simulated by preference",
625 "FEATURE_FAILURE_D3D11_SIM"_ns
);
629 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
631 DXGI_ADAPTER_DESC desc
;
632 aAdapter
->GetDesc(&desc
);
633 if (desc
.VendorId
!= 0x1414) {
634 // 0x1414 is Microsoft (e.g. WARP)
635 // When not using WARP, use
636 // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS to prevent
637 // bug 1092260. IE 11 also uses this flag.
638 flags
|= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
;
641 if (aAttemptVideoSupport
) {
642 flags
|= D3D11_CREATE_DEVICE_VIDEO_SUPPORT
;
646 RefPtr
<ID3D11Device
> device
;
647 if (!CreateDevice(aAdapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
, device
)) {
648 if (!aAttemptVideoSupport
) {
649 gfxCriticalError() << "Crash during D3D11 device creation";
650 aD3d11
.SetFailed(FeatureStatus::CrashedInHandler
,
651 "Crashed trying to acquire a D3D11 device",
652 "FEATURE_FAILURE_D3D11_DEVICE1"_ns
);
657 if (FAILED(hr
) || !device
) {
658 if (!aAttemptVideoSupport
) {
659 aD3d11
.SetFailed(FeatureStatus::Failed
,
660 "Failed to acquire a D3D11 device",
661 "FEATURE_FAILURE_D3D11_DEVICE2"_ns
);
665 if (!D3D11Checks::DoesDeviceWork()) {
666 if (!aAttemptVideoSupport
) {
667 aD3d11
.SetFailed(FeatureStatus::Broken
,
668 "Direct3D11 device was determined to be broken",
669 "FEATURE_FAILURE_D3D11_BROKEN"_ns
);
678 // Note that it's enough for us to just use a counter for a unique ID,
679 // even though the counter isn't synchronized between processes. If we
680 // start in the GPU process and wind up in the parent process, the
681 // whole graphics stack is blown away anyway. But just in case, we
682 // make gpu process IDs negative and parent process IDs positive.
683 static inline int32_t GetNextDeviceCounter() {
684 static int32_t sDeviceCounter
= 0;
685 return XRE_IsGPUProcess() ? --sDeviceCounter
: ++sDeviceCounter
;
688 void DeviceManagerDx::CreateCompositorDevice(FeatureState
& d3d11
) {
689 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
690 CreateWARPCompositorDevice();
694 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
696 d3d11
.SetFailed(FeatureStatus::Unavailable
,
697 "Failed to acquire a DXGI adapter",
698 "FEATURE_FAILURE_D3D11_DXGI"_ns
);
702 if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter
)) {
703 d3d11
.SetFailed(FeatureStatus::Unavailable
,
704 "DXGI does not support out-of-process presentation",
705 "FEATURE_FAILURE_D3D11_REMOTE_PRESENT"_ns
);
709 RefPtr
<ID3D11Device
> device
;
710 if (!CreateCompositorDeviceHelper(d3d11
, adapter
, true, device
)) {
711 // Try again without video support and record that it failed.
712 mCompositorDeviceSupportsVideo
= false;
713 if (!CreateCompositorDeviceHelper(d3d11
, adapter
, false, device
)) {
717 mCompositorDeviceSupportsVideo
= true;
720 // Only test this when not using WARP since it can fail and cause
721 // GetDeviceRemovedReason to return weird values.
722 bool textureSharingWorks
= D3D11Checks::DoesTextureSharingWork(device
);
724 DXGI_ADAPTER_DESC desc
;
726 adapter
->GetDesc(&desc
);
728 if (!textureSharingWorks
) {
729 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE
, FeatureStatus::Broken
,
730 "Texture sharing doesn't work",
731 "FEATURE_FAILURE_HW_ANGLE_NEEDS_TEXTURE_SHARING"_ns
);
733 if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device
)) {
734 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE
, FeatureStatus::Broken
,
735 "RenderTargetViews need recreating",
736 "FEATURE_FAILURE_HW_ANGLE_NEEDS_RTV_RECREATION"_ns
);
738 if (XRE_IsParentProcess()) {
739 // It seems like this may only happen when we're using the NVIDIA gpu
740 D3D11Checks::WarnOnAdapterMismatch(device
);
743 uint32_t featureLevel
= device
->GetFeatureLevel();
744 auto formatOptions
= D3D11Checks::FormatOptions(device
);
745 mCompositorDevice
= device
;
747 int32_t sequenceNumber
= GetNextDeviceCounter();
748 mDeviceStatus
= Some(D3D11DeviceStatus(
749 false, textureSharingWorks
, featureLevel
, DxgiAdapterDesc::From(desc
),
750 sequenceNumber
, formatOptions
));
751 mCompositorDevice
->SetExceptionMode(0);
754 bool DeviceManagerDx::CreateDevice(IDXGIAdapter
* aAdapter
,
755 D3D_DRIVER_TYPE aDriverType
, UINT aFlags
,
757 RefPtr
<ID3D11Device
>& aOutDevice
) {
758 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup() ||
759 StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
760 aFlags
|= D3D11_CREATE_DEVICE_DEBUG
;
764 aResOut
= sD3D11CreateDeviceFn(
765 aAdapter
, aDriverType
, nullptr, aFlags
, mFeatureLevels
.Elements(),
766 mFeatureLevels
.Length(), D3D11_SDK_VERSION
, getter_AddRefs(aOutDevice
),
769 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) { return false; }
771 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
773 if (!aOutDevice
) break;
775 RefPtr
<ID3D11Debug
> debug
;
776 if (!SUCCEEDED(aOutDevice
->QueryInterface(__uuidof(ID3D11Debug
),
777 getter_AddRefs(debug
))))
780 RefPtr
<ID3D11InfoQueue
> infoQueue
;
781 if (!SUCCEEDED(debug
->QueryInterface(__uuidof(ID3D11InfoQueue
),
782 getter_AddRefs(infoQueue
))))
785 D3D11_INFO_QUEUE_FILTER filter
;
788 // Disable warnings caused by Advanced Layers that are known and not
790 D3D11_MESSAGE_ID blockIDs
[] = {
791 D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL
};
792 filter
.DenyList
.NumIDs
= MOZ_ARRAY_LENGTH(blockIDs
);
793 filter
.DenyList
.pIDList
= blockIDs
;
794 infoQueue
->PushStorageFilter(&filter
);
796 infoQueue
->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION
, true);
797 infoQueue
->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR
, true);
798 infoQueue
->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING
, true);
805 void DeviceManagerDx::CreateWARPCompositorDevice() {
806 ScopedGfxFeatureReporter
reporterWARP(
807 "D3D11-WARP", StaticPrefs::layers_d3d11_force_warp_AtStartup());
808 FeatureState
& d3d11
= gfxConfig::GetFeature(Feature::D3D11_COMPOSITING
);
811 RefPtr
<ID3D11Device
> device
;
813 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
814 // to prevent bug 1092260. IE 11 also uses this flag.
815 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
816 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP
, flags
, hr
, device
)) {
817 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
818 d3d11
.SetFailed(FeatureStatus::CrashedInHandler
,
819 "Crashed creating a D3D11 WARP device",
820 "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns
);
823 if (FAILED(hr
) || !device
) {
824 // This should always succeed... in theory.
825 gfxCriticalError() << "Failed to initialize WARP D3D11 device! "
827 d3d11
.SetFailed(FeatureStatus::Failed
,
828 "Failed to create a D3D11 WARP device",
829 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns
);
833 bool textureSharingWorks
= D3D11Checks::DoesTextureSharingWork(device
);
835 DXGI_ADAPTER_DESC desc
;
836 D3D11Checks::GetDxgiDesc(device
, &desc
);
838 int featureLevel
= device
->GetFeatureLevel();
840 auto formatOptions
= D3D11Checks::FormatOptions(device
);
841 mCompositorDevice
= device
;
843 int32_t sequenceNumber
= GetNextDeviceCounter();
844 mDeviceStatus
= Some(D3D11DeviceStatus(
845 true, textureSharingWorks
, featureLevel
, DxgiAdapterDesc::From(desc
),
846 sequenceNumber
, formatOptions
));
847 mCompositorDevice
->SetExceptionMode(0);
849 reporterWARP
.SetSuccessful();
852 FeatureStatus
DeviceManagerDx::CreateContentDevice() {
853 RefPtr
<IDXGIAdapter1
> adapter
;
854 if (!mDeviceStatus
->isWARP()) {
855 adapter
= GetDXGIAdapterLocked();
857 gfxCriticalNote
<< "Could not get a DXGI adapter";
858 return FeatureStatus::Unavailable
;
863 RefPtr
<ID3D11Device
> device
;
865 UINT flags
= D3D11_CREATE_DEVICE_BGRA_SUPPORT
;
866 D3D_DRIVER_TYPE type
=
867 mDeviceStatus
->isWARP() ? D3D_DRIVER_TYPE_WARP
: D3D_DRIVER_TYPE_UNKNOWN
;
868 if (!CreateDevice(adapter
, type
, flags
, hr
, device
)) {
870 << "Recovered from crash while creating a D3D11 content device";
871 gfxWindowsPlatform::RecordContentDeviceFailure(
872 TelemetryDeviceCode::Content
);
873 return FeatureStatus::CrashedInHandler
;
876 if (FAILED(hr
) || !device
) {
877 gfxCriticalNote
<< "Failed to create a D3D11 content device: " << hexa(hr
);
878 gfxWindowsPlatform::RecordContentDeviceFailure(
879 TelemetryDeviceCode::Content
);
880 return FeatureStatus::Failed
;
883 // InitializeD2D() will abort early if the compositor device did not support
884 // texture sharing. If we're in the content process, we can't rely on the
885 // parent device alone: some systems have dual GPUs that are capable of
886 // binding the parent and child processes to different GPUs. As a safety net,
887 // we re-check texture sharing against the newly created D3D11 content device.
888 // If it fails, we won't use Direct2D.
889 if (XRE_IsContentProcess()) {
890 if (!D3D11Checks::DoesTextureSharingWork(device
)) {
891 return FeatureStatus::Failed
;
894 DebugOnly
<bool> ok
= ContentAdapterIsParentAdapter(device
);
898 mContentDevice
= device
;
899 mContentDevice
->SetExceptionMode(0);
901 RefPtr
<ID3D10Multithread
> multi
;
902 hr
= mContentDevice
->QueryInterface(__uuidof(ID3D10Multithread
),
903 getter_AddRefs(multi
));
904 if (SUCCEEDED(hr
) && multi
) {
905 multi
->SetMultithreadProtected(TRUE
);
907 return FeatureStatus::Available
;
910 RefPtr
<ID3D11Device
> DeviceManagerDx::CreateDecoderDevice(
911 bool aHardwareWebRender
) {
912 MutexAutoLock
lock(mDeviceLock
);
914 if (!mDeviceStatus
) {
918 bool isAMD
= mDeviceStatus
->adapter().VendorId
== 0x1002;
919 bool reuseDevice
= false;
920 if (gfxVars::ReuseDecoderDevice()) {
924 gfxCriticalNoteOnce
<< "Always have to reuse decoder device on AMD";
928 // Use mCompositorDevice for decoder device only for hardware WebRender.
929 if (aHardwareWebRender
&& mCompositorDevice
&&
930 mCompositorDeviceSupportsVideo
&& !mDecoderDevice
) {
931 mDecoderDevice
= mCompositorDevice
;
933 RefPtr
<ID3D10Multithread
> multi
;
934 mDecoderDevice
->QueryInterface(__uuidof(ID3D10Multithread
),
935 getter_AddRefs(multi
));
937 multi
->SetMultithreadProtected(TRUE
);
941 if (mDecoderDevice
) {
942 RefPtr
<ID3D11Device
> dev
= mDecoderDevice
;
947 if (!sD3D11CreateDeviceFn
) {
948 // We should just be on Windows Vista or XP in this case.
952 RefPtr
<IDXGIAdapter1
> adapter
= GetDXGIAdapterLocked();
958 RefPtr
<ID3D11Device
> device
;
960 UINT flags
= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
|
961 D3D11_CREATE_DEVICE_VIDEO_SUPPORT
;
962 if (!CreateDevice(adapter
, D3D_DRIVER_TYPE_UNKNOWN
, flags
, hr
, device
)) {
965 if (FAILED(hr
) || !device
|| !D3D11Checks::DoesDeviceWork()) {
969 RefPtr
<ID3D10Multithread
> multi
;
970 device
->QueryInterface(__uuidof(ID3D10Multithread
), getter_AddRefs(multi
));
972 multi
->SetMultithreadProtected(TRUE
);
975 mDecoderDevice
= device
;
980 // ID3D11DeviceChild, IDXGIObject and ID3D11Device implement SetPrivateData with
981 // the exact same parameters.
982 template <typename T
>
983 static HRESULT
SetDebugName(T
* d3d11Object
, const char* debugString
) {
984 return d3d11Object
->SetPrivateData(WKPDID_D3DDebugObjectName
,
985 strlen(debugString
), debugString
);
988 RefPtr
<ID3D11Device
> DeviceManagerDx::CreateMediaEngineDevice() {
989 MutexAutoLock
lock(mDeviceLock
);
995 RefPtr
<ID3D11Device
> device
;
996 UINT flags
= D3D11_CREATE_DEVICE_VIDEO_SUPPORT
|
997 D3D11_CREATE_DEVICE_BGRA_SUPPORT
|
998 D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
;
999 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE
, flags
, hr
, device
)) {
1002 if (FAILED(hr
) || !device
|| !D3D11Checks::DoesDeviceWork()) {
1005 Unused
<< SetDebugName(device
.get(), "MFMediaEngineDevice");
1007 RefPtr
<ID3D10Multithread
> multi
;
1008 device
->QueryInterface(__uuidof(ID3D10Multithread
), getter_AddRefs(multi
));
1010 multi
->SetMultithreadProtected(TRUE
);
1015 void DeviceManagerDx::ResetDevices() {
1016 MutexAutoLock
lock(mDeviceLock
);
1017 ResetDevicesLocked();
1020 void DeviceManagerDx::ResetDevicesLocked() {
1022 mCompositorAttachments
= nullptr;
1023 mCompositorDevice
= nullptr;
1024 mContentDevice
= nullptr;
1025 mCanvasDevice
= nullptr;
1026 mImageDevice
= nullptr;
1027 mVRDevice
= nullptr;
1028 mDecoderDevice
= nullptr;
1029 mDirectCompositionDevice
= nullptr;
1030 mDeviceStatus
= Nothing();
1031 mDeviceResetReason
= Nothing();
1032 Factory::SetDirect3D11Device(nullptr);
1035 bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
1036 MutexAutoLock
lock(mDeviceLock
);
1038 DeviceResetReason resetReason
;
1039 if (!HasDeviceResetLocked(&resetReason
)) {
1043 GPUProcessManager::RecordDeviceReset(resetReason
);
1045 bool createCompositorDevice
= !!mCompositorDevice
;
1046 bool createContentDevice
= !!mContentDevice
;
1047 bool createCanvasDevice
= !!mCanvasDevice
;
1048 bool createDirectCompositionDevice
= !!mDirectCompositionDevice
;
1050 ResetDevicesLocked();
1052 if (createCompositorDevice
&& !CreateCompositorDevicesLocked()) {
1053 // Just stop, don't try anything more
1056 if (createContentDevice
) {
1057 CreateContentDevicesLocked();
1059 if (createCanvasDevice
) {
1060 CreateCanvasDeviceLocked();
1062 if (createDirectCompositionDevice
) {
1063 CreateDirectCompositionDeviceLocked();
1069 bool DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device
* device
) {
1070 DXGI_ADAPTER_DESC desc
;
1071 if (!D3D11Checks::GetDxgiDesc(device
, &desc
)) {
1072 gfxCriticalNote
<< "Could not query device DXGI adapter info";
1076 const DxgiAdapterDesc
& preferred
= mDeviceStatus
->adapter();
1078 if (desc
.VendorId
!= preferred
.VendorId
||
1079 desc
.DeviceId
!= preferred
.DeviceId
||
1080 desc
.SubSysId
!= preferred
.SubSysId
||
1081 desc
.AdapterLuid
.HighPart
!= preferred
.AdapterLuid
.HighPart
||
1082 desc
.AdapterLuid
.LowPart
!= preferred
.AdapterLuid
.LowPart
) {
1083 gfxCriticalNote
<< "VendorIDMismatch P " << hexa(preferred
.VendorId
) << " "
1084 << hexa(desc
.VendorId
);
1091 static DeviceResetReason
HResultToResetReason(HRESULT hr
) {
1093 case DXGI_ERROR_DEVICE_HUNG
:
1094 return DeviceResetReason::HUNG
;
1095 case DXGI_ERROR_DEVICE_REMOVED
:
1096 return DeviceResetReason::REMOVED
;
1097 case DXGI_ERROR_DEVICE_RESET
:
1098 return DeviceResetReason::RESET
;
1099 case DXGI_ERROR_DRIVER_INTERNAL_ERROR
:
1100 return DeviceResetReason::DRIVER_ERROR
;
1101 case DXGI_ERROR_INVALID_CALL
:
1102 return DeviceResetReason::INVALID_CALL
;
1104 return DeviceResetReason::OUT_OF_MEMORY
;
1108 return DeviceResetReason::OTHER
;
1111 bool DeviceManagerDx::HasDeviceReset(DeviceResetReason
* aOutReason
) {
1112 MutexAutoLock
lock(mDeviceLock
);
1113 return HasDeviceResetLocked(aOutReason
);
1116 bool DeviceManagerDx::HasDeviceResetLocked(DeviceResetReason
* aOutReason
) {
1117 if (mDeviceResetReason
) {
1119 *aOutReason
= mDeviceResetReason
.value();
1124 DeviceResetReason reason
;
1125 if (GetAnyDeviceRemovedReason(&reason
)) {
1126 mDeviceResetReason
= Some(reason
);
1128 *aOutReason
= reason
;
1136 static inline bool DidDeviceReset(const RefPtr
<ID3D11Device
>& aDevice
,
1137 DeviceResetReason
* aOutReason
) {
1141 HRESULT hr
= aDevice
->GetDeviceRemovedReason();
1146 *aOutReason
= HResultToResetReason(hr
);
1150 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason
* aOutReason
) {
1151 if (DidDeviceReset(mCompositorDevice
, aOutReason
) ||
1152 DidDeviceReset(mContentDevice
, aOutReason
) ||
1153 DidDeviceReset(mCanvasDevice
, aOutReason
)) {
1157 if (XRE_IsParentProcess() && NS_IsMainThread() &&
1158 StaticPrefs::gfx_testing_device_reset()) {
1159 Preferences::SetInt("gfx.testing.device-reset", 0);
1160 *aOutReason
= DeviceResetReason::FORCED_RESET
;
1167 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason
) {
1168 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON
,
1171 MutexAutoLock
lock(mDeviceLock
);
1172 if (!mDeviceResetReason
) {
1173 mDeviceResetReason
= Some(DeviceResetReason::FORCED_RESET
);
1178 void DeviceManagerDx::DisableD3D11AfterCrash() {
1179 gfxConfig::Disable(Feature::D3D11_COMPOSITING
,
1180 FeatureStatus::CrashedInHandler
,
1181 "Crashed while acquiring a Direct3D11 device",
1182 "FEATURE_FAILURE_D3D11_CRASH"_ns
);
1186 RefPtr
<ID3D11Device
> DeviceManagerDx::GetCompositorDevice() {
1187 MutexAutoLock
lock(mDeviceLock
);
1188 return mCompositorDevice
;
1191 RefPtr
<ID3D11Device
> DeviceManagerDx::GetContentDevice() {
1192 MOZ_ASSERT(XRE_IsGPUProcess() ||
1193 gfxPlatform::GetPlatform()->DevicesInitialized());
1195 MutexAutoLock
lock(mDeviceLock
);
1196 return mContentDevice
;
1199 RefPtr
<ID3D11Device
> DeviceManagerDx::GetImageDevice() {
1200 MutexAutoLock
lock(mDeviceLock
);
1202 return mImageDevice
;
1205 RefPtr
<ID3D11Device
> device
= mContentDevice
;
1207 device
= mCompositorDevice
;
1214 RefPtr
<ID3D10Multithread
> multi
;
1216 device
->QueryInterface((ID3D10Multithread
**)getter_AddRefs(multi
));
1217 if (FAILED(hr
) || !multi
) {
1218 gfxWarning() << "Multithread safety interface not supported. " << hr
;
1221 multi
->SetMultithreadProtected(TRUE
);
1223 mImageDevice
= device
;
1225 return mImageDevice
;
1228 RefPtr
<ID3D11Device
> DeviceManagerDx::GetVRDevice() {
1229 MutexAutoLock
lock(mDeviceLock
);
1236 RefPtr
<ID3D11Device
> DeviceManagerDx::GetCanvasDevice() {
1237 MutexAutoLock
lock(mDeviceLock
);
1238 return mCanvasDevice
;
1241 RefPtr
<IDCompositionDevice2
> DeviceManagerDx::GetDirectCompositionDevice() {
1242 MutexAutoLock
lock(mDeviceLock
);
1243 return mDirectCompositionDevice
;
1246 unsigned DeviceManagerDx::GetCompositorFeatureLevel() const {
1247 MutexAutoLock
lock(mDeviceLock
);
1248 if (!mDeviceStatus
) {
1251 return mDeviceStatus
->featureLevel();
1254 bool DeviceManagerDx::TextureSharingWorks() {
1255 MutexAutoLock
lock(mDeviceLock
);
1256 if (!mDeviceStatus
) {
1259 return mDeviceStatus
->textureSharingWorks();
1262 bool DeviceManagerDx::CanInitializeKeyedMutexTextures() {
1263 MutexAutoLock
lock(mDeviceLock
);
1264 return mDeviceStatus
&& StaticPrefs::gfx_direct3d11_allow_keyed_mutex() &&
1265 gfxVars::AllowD3D11KeyedMutex();
1268 bool DeviceManagerDx::IsWARP() {
1269 MutexAutoLock
lock(mDeviceLock
);
1270 if (!mDeviceStatus
) {
1273 return mDeviceStatus
->isWARP();
1276 bool DeviceManagerDx::CanUseNV12() {
1277 MutexAutoLock
lock(mDeviceLock
);
1278 if (!mDeviceStatus
) {
1281 return mDeviceStatus
->formatOptions().contains(
1282 D3D11Checks::VideoFormatOption::NV12
);
1285 bool DeviceManagerDx::CanUseP010() {
1286 MutexAutoLock
lock(mDeviceLock
);
1287 if (!mDeviceStatus
) {
1290 return mDeviceStatus
->formatOptions().contains(
1291 D3D11Checks::VideoFormatOption::P010
);
1294 bool DeviceManagerDx::CanUseP016() {
1295 MutexAutoLock
lock(mDeviceLock
);
1296 if (!mDeviceStatus
) {
1299 return mDeviceStatus
->formatOptions().contains(
1300 D3D11Checks::VideoFormatOption::P016
);
1303 bool DeviceManagerDx::CanUseDComp() {
1304 MutexAutoLock
lock(mDeviceLock
);
1305 return !!mDirectCompositionDevice
;
1308 void DeviceManagerDx::InitializeDirectDraw() {
1309 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
1312 // Already initialized.
1316 FeatureState
& ddraw
= gfxConfig::GetFeature(Feature::DIRECT_DRAW
);
1317 if (!ddraw
.IsEnabled()) {
1321 // Check if DirectDraw is available on this system.
1322 mDirectDrawDLL
.own(LoadLibrarySystem32(L
"ddraw.dll"));
1323 if (!mDirectDrawDLL
) {
1324 ddraw
.SetFailed(FeatureStatus::Unavailable
,
1325 "DirectDraw not available on this computer",
1326 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1330 sDirectDrawCreateExFn
= (decltype(DirectDrawCreateEx
)*)GetProcAddress(
1331 mDirectDrawDLL
, "DirectDrawCreateEx");
1332 if (!sDirectDrawCreateExFn
) {
1333 ddraw
.SetFailed(FeatureStatus::Unavailable
,
1334 "DirectDraw not available on this computer",
1335 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1341 hr
= sDirectDrawCreateExFn(nullptr, getter_AddRefs(mDirectDraw
),
1342 IID_IDirectDraw7
, nullptr);
1344 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1345 ddraw
.SetFailed(FeatureStatus::Failed
, "Failed to create DirectDraw",
1346 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1347 gfxCriticalNote
<< "DoesCreatingDirectDrawFailed";
1351 ddraw
.SetFailed(FeatureStatus::Failed
, "Failed to create DirectDraw",
1352 "FEATURE_FAILURE_DDRAW_LIB"_ns
);
1353 gfxCriticalNote
<< "DoesCreatingDirectDrawFailed " << hexa(hr
);
1358 IDirectDraw7
* DeviceManagerDx::GetDirectDraw() { return mDirectDraw
; }
1360 void DeviceManagerDx::GetCompositorDevices(
1361 RefPtr
<ID3D11Device
>* aOutDevice
,
1362 RefPtr
<layers::DeviceAttachmentsD3D11
>* aOutAttachments
) {
1363 RefPtr
<ID3D11Device
> device
;
1365 MutexAutoLock
lock(mDeviceLock
);
1366 if (!mCompositorDevice
) {
1369 if (mCompositorAttachments
) {
1370 *aOutDevice
= mCompositorDevice
;
1371 *aOutAttachments
= mCompositorAttachments
;
1375 // Otherwise, we'll try to create attachments outside the lock.
1376 device
= mCompositorDevice
;
1379 // We save the attachments object even if it fails to initialize, so the
1380 // compositor can grab the failure ID.
1381 RefPtr
<layers::DeviceAttachmentsD3D11
> attachments
=
1382 layers::DeviceAttachmentsD3D11::Create(device
);
1384 MutexAutoLock
lock(mDeviceLock
);
1385 if (device
!= mCompositorDevice
) {
1388 mCompositorAttachments
= attachments
;
1391 *aOutDevice
= device
;
1392 *aOutAttachments
= attachments
;
1396 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
1397 if (!CompositorThread()) {
1401 RefPtr
<Runnable
> task
= NS_NewRunnableFunction(
1402 "DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void {
1403 if (DeviceManagerDx
* dm
= DeviceManagerDx::Get()) {
1404 RefPtr
<ID3D11Device
> device
;
1405 RefPtr
<layers::DeviceAttachmentsD3D11
> attachments
;
1406 dm
->GetCompositorDevices(&device
, &attachments
);
1409 CompositorThread()->Dispatch(task
.forget());
1413 } // namespace mozilla