Bug 1932613 - temporarily disable browser_ml_end_to_end.js for permanent failures...
[gecko.git] / gfx / thebes / DeviceManagerDx.cpp
blob2985db25b516de15adcf664afc660b225f846d94
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"
8 #include "gfxConfig.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"
25 #include "nsString.h"
27 // -
29 #include <d3d11.h>
30 #include <dcomp.h>
31 #include <ddraw.h>
32 #include <dxgi.h>
34 namespace mozilla {
35 namespace gfx {
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 =
53 nullptr;
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;
60 /* static */
61 void DeviceManagerDx::Init() { sInstance = new DeviceManagerDx(); }
63 /* static */
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) {
84 return true;
87 nsModuleHandle module(LoadLibrarySystem32(L"d3d11.dll"));
88 if (!module) {
89 d3d11.SetFailed(FeatureStatus::Unavailable,
90 "Direct3D11 not available on this computer",
91 "FEATURE_FAILURE_D3D11_LIB"_ns);
92 return false;
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);
102 return false;
105 mD3D11Module.steal(module);
106 return true;
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"));
119 if (!module) {
120 return false;
123 sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress(
124 module, "DCompositionCreateDevice2");
125 sDcompCreateDevice3Fn = (decltype(DCompositionCreateDevice3)*)GetProcAddress(
126 module, "DCompositionCreateDevice3");
127 if (!sDcompCreateDevice2Fn) {
128 return false;
131 // Load optional API for external compositing
132 sDcompCreateSurfaceHandleFn =
133 (decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress(
134 module, "DCompositionCreateSurfaceHandle");
136 mDcompModule.steal(module);
137 return true;
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();
153 if (!adapter) {
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)))) {
162 break;
165 RefPtr<IDXGIOutput6> output6 = nullptr;
166 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
167 getter_AddRefs(output6)))) {
168 break;
171 DXGI_OUTPUT_DESC1 desc;
172 if (FAILED(output6->GetDesc1(&desc))) {
173 break;
176 outputs.AppendElement(desc);
178 return outputs;
181 bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor,
182 RefPtr<IDXGIOutput>* aOutOutput) {
183 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
185 if (!adapter) {
186 NS_WARNING("Failed to acquire a DXGI adapter for GetOutputFromMonitor.");
187 return false;
190 for (UINT i = 0;; ++i) {
191 RefPtr<IDXGIOutput> output = nullptr;
192 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) {
193 break;
196 DXGI_OUTPUT_DESC desc;
197 if (FAILED(output->GetDesc(&desc))) {
198 continue;
201 if (desc.Monitor == monitor) {
202 *aOutOutput = output;
203 return true;
206 return false;
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) {
216 return;
219 auto* holder = CompositorThreadHolder::GetSingleton();
220 if (!holder) {
221 return;
224 mUpdateMonitorInfoRunnable = NS_NewRunnableFunction(
225 "DeviceManagerDx::PostUpdateMonitorInfo::Runnable", []() -> void {
226 auto* dm = gfx::DeviceManagerDx::Get();
227 if (dm) {
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).
255 // Further reading:
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);
260 return isHDR;
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();
290 UpdateMonitorInfo();
292 MutexAutoLock lock(mDeviceLock);
293 return mSystemHdrEnabled.ref();
296 bool DeviceManagerDx::WindowHDREnabled(HWND aWindow) {
297 MOZ_ASSERT(aWindow);
299 HMONITOR monitor = ::MonitorFromWindow(aWindow, MONITOR_DEFAULTTONEAREST);
300 return MonitorHDREnabled(monitor);
303 bool DeviceManagerDx::MonitorHDREnabled(HMONITOR aMonitor) {
304 if (!aMonitor) {
305 return false;
308 bool needInit = false;
311 MutexAutoLock lock(mDeviceLock);
312 if (mSystemHdrEnabled.isNothing()) {
313 needInit = true;
317 if (needInit) {
318 UpdateMonitorInfo();
321 MutexAutoLock lock(mDeviceLock);
322 MOZ_ASSERT(mSystemHdrEnabled.isSome());
324 auto it = mHdrMonitors.find(aMonitor);
325 if (it == mHdrMonitors.end()) {
326 return false;
329 return true;
332 void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) {
333 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
335 if (!adapter) {
336 NS_WARNING(
337 "Failed to acquire a DXGI adapter for checking hardware stretching "
338 "support.");
339 ++aRv.mError;
340 return;
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.
348 break;
351 if (FAILED(result)) {
352 ++aRv.mError;
353 break;
356 RefPtr<IDXGIOutput6> output6 = nullptr;
357 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
358 getter_AddRefs(output6)))) {
359 ++aRv.mError;
360 continue;
363 UINT flags = 0;
364 if (FAILED(output6->CheckHardwareCompositionSupport(&flags))) {
365 ++aRv.mError;
366 continue;
369 bool fullScreen = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN;
370 bool window = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED;
371 if (fullScreen && window) {
372 ++aRv.mBoth;
373 } else if (fullScreen) {
374 ++aRv.mFullScreenOnly;
375 } else if (window) {
376 ++aRv.mWindowOnly;
377 } else {
378 ++aRv.mNone;
383 #ifdef DEBUG
384 static inline bool ProcessOwnsCompositor() {
385 return XRE_GetProcessType() == GeckoProcessType_GPU ||
386 XRE_GetProcessType() == GeckoProcessType_VR ||
387 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS));
389 #endif
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);
408 if (!LoadD3D11()) {
409 return false;
412 CreateCompositorDevice(d3d11);
414 if (!d3d11.IsEnabled()) {
415 MOZ_ASSERT(!mCompositorDevice);
416 ReleaseD3D11();
418 return false;
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()) {
428 return false;
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
435 // synchronously.
436 if (gfx::gfxVars::UseSoftwareWebRender()) {
437 PreloadAttachmentsOnCompositorThread();
440 return true;
443 bool DeviceManagerDx::CreateVRDevice() {
444 MOZ_ASSERT(ProcessOwnsCompositor());
446 if (mVRDevice) {
447 return true;
450 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
451 NS_WARNING("Direct3D11 Compositing required for VR");
452 return false;
455 if (!LoadD3D11()) {
456 return false;
459 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
460 if (!adapter) {
461 NS_WARNING("Failed to acquire a DXGI adapter for VR");
462 return false;
465 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
467 HRESULT hr;
468 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, mVRDevice)) {
469 gfxCriticalError() << "Crash during D3D11 device creation for VR";
470 return false;
473 if (FAILED(hr) || !mVRDevice) {
474 NS_WARNING("Failed to acquire a D3D11 device for VR");
475 return false;
478 return true;
481 bool DeviceManagerDx::CreateCanvasDevice() {
482 MutexAutoLock lock(mDeviceLock);
483 return CreateCanvasDeviceLocked();
486 bool DeviceManagerDx::CreateCanvasDeviceLocked() {
487 MOZ_ASSERT(ProcessOwnsCompositor());
489 if (mCanvasDevice) {
490 return true;
493 if (!LoadD3D11()) {
494 return false;
497 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
498 if (!adapter) {
499 NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
500 return false;
503 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
505 HRESULT hr;
506 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr,
507 mCanvasDevice)) {
508 gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
509 return false;
512 if (StaticPrefs::
513 gfx_direct2d_target_independent_rasterization_disabled_AtStartup()) {
514 int creationFlags = 0x2; // disable target independent rasterization
515 const GUID D2D_INTERNAL_DEVICE_CREATION_OPTIONS = {
516 0xfb3a8e1a,
517 0x2e3c,
518 0x4de1,
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");
526 return false;
529 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice)) {
530 mCanvasDevice = nullptr;
531 return false;
534 if (XRE_IsGPUProcess()) {
535 Factory::SetDirect3D11Device(mCanvasDevice);
538 return true;
541 void DeviceManagerDx::CreateDirectCompositionDevice() {
542 MutexAutoLock lock(mDeviceLock);
543 CreateDirectCompositionDeviceLocked();
546 void DeviceManagerDx::CreateDirectCompositionDeviceLocked() {
547 if (!gfxVars::UseWebRenderDCompWin()) {
548 return;
551 if (!mCompositorDevice) {
552 return;
555 if (!LoadDcomp()) {
556 return;
559 RefPtr<IDXGIDevice> dxgiDevice;
560 if (mCompositorDevice->QueryInterface(
561 IID_PPV_ARGS((IDXGIDevice**)getter_AddRefs(dxgiDevice))) != S_OK) {
562 return;
565 HRESULT hr;
566 RefPtr<IDCompositionDesktopDevice> desktopDevice;
567 MOZ_SEH_TRY {
568 hr = sDcompCreateDevice3Fn(
569 dxgiDevice.get(),
570 IID_PPV_ARGS(
571 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
572 if (!desktopDevice) {
573 hr = sDcompCreateDevice2Fn(
574 dxgiDevice.get(),
575 IID_PPV_ARGS(
576 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
579 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; }
581 if (!SUCCEEDED(hr)) {
582 return;
585 RefPtr<IDCompositionDevice2> compositionDevice;
586 if (desktopDevice->QueryInterface(IID_PPV_ARGS(
587 (IDCompositionDevice2**)getter_AddRefs(compositionDevice))) != S_OK) {
588 return;
591 mDirectCompositionDevice = compositionDevice;
594 /* static */
595 HANDLE DeviceManagerDx::CreateDCompSurfaceHandle() {
596 if (!sDcompCreateSurfaceHandleFn) {
597 return 0;
600 HANDLE handle = 0;
601 HRESULT hr = sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS,
602 nullptr, &handle);
603 if (FAILED(hr)) {
604 return 0;
607 return handle;
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);
619 if (mDeviceStatus) {
620 *aOut = mDeviceStatus.value();
621 return true;
624 return false;
627 void DeviceManagerDx::CreateContentDevices() {
628 MutexAutoLock lock(mDeviceLock);
629 CreateContentDevicesLocked();
632 void DeviceManagerDx::CreateContentDevicesLocked() {
633 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING));
635 if (!LoadD3D11()) {
636 return;
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()) {
655 return mAdapter;
657 mAdapter = nullptr;
658 mFactory = nullptr;
660 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
661 decltype(CreateDXGIFactory1)* createDXGIFactory1 =
662 (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgiModule,
663 "CreateDXGIFactory1");
664 if (!createDXGIFactory1) {
665 return nullptr;
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
672 // across processes.
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));
679 } else {
680 NS_WARNING(
681 "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2.");
684 if (!mFactory) {
685 HRESULT hr =
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.
690 return nullptr;
694 if (mDeviceStatus) {
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)))) {
699 break;
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();
711 break;
716 if (!mAdapter) {
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.
723 dxgiModule.disown();
724 return mAdapter;
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);
735 return false;
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;
754 HRESULT hr;
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);
763 return false;
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);
772 return false;
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);
780 return false;
783 aOutDevice = device;
784 return true;
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();
800 return;
803 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
804 if (!adapter) {
805 d3d11.SetFailed(FeatureStatus::Unavailable,
806 "Failed to acquire a DXGI adapter",
807 "FEATURE_FAILURE_D3D11_DXGI"_ns);
808 return;
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);
815 return;
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)) {
823 return;
825 } else {
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;
834 PodZero(&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,
872 HRESULT& aResOut,
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;
879 MOZ_SEH_TRY {
880 aResOut = sD3D11CreateDeviceFn(
881 aAdapter, aDriverType, nullptr, aFlags, mFeatureLevels.Elements(),
882 mFeatureLevels.Length(), D3D11_SDK_VERSION, getter_AddRefs(aOutDevice),
883 nullptr, nullptr);
885 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return false; }
887 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
888 do {
889 if (!aOutDevice) break;
891 RefPtr<ID3D11Debug> debug;
892 if (!SUCCEEDED(aOutDevice->QueryInterface(__uuidof(ID3D11Debug),
893 getter_AddRefs(debug))))
894 break;
896 RefPtr<ID3D11InfoQueue> infoQueue;
897 if (!SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue),
898 getter_AddRefs(infoQueue))))
899 break;
901 D3D11_INFO_QUEUE_FILTER filter;
902 PodZero(&filter);
904 // Disable warnings caused by Advanced Layers that are known and not
905 // problematic.
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);
915 } while (false);
918 return 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);
926 HRESULT hr;
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! "
942 << hexa(hr);
943 d3d11.SetFailed(FeatureStatus::Failed,
944 "Failed to create a D3D11 WARP device",
945 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns);
946 return;
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();
979 if (!adapter) {
980 gfxCriticalNote << "Could not get a DXGI adapter";
981 return FeatureStatus::Unavailable;
985 HRESULT hr;
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)) {
992 gfxCriticalNote
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);
1018 MOZ_ASSERT(ok);
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) {
1038 return nullptr;
1041 bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002;
1042 bool reuseDevice = false;
1043 if (gfxVars::ReuseDecoderDevice()) {
1044 reuseDevice = true;
1045 } else if (isAMD) {
1046 reuseDevice = true;
1047 gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD";
1050 if (reuseDevice) {
1051 // Use mCompositorDevice for decoder device only for hardware WebRender.
1052 if (aFlags.contains(DeviceFlag::isHardwareWebRenderInUse) &&
1053 mCompositorDevice && mCompositorDeviceSupportsVideo &&
1054 !mDecoderDevice) {
1055 mDecoderDevice = mCompositorDevice;
1057 RefPtr<ID3D10Multithread> multi;
1058 mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread),
1059 getter_AddRefs(multi));
1060 if (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.
1073 return nullptr;
1076 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
1077 if (!adapter) {
1078 return nullptr;
1081 HRESULT hr;
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)) {
1087 return nullptr;
1089 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
1090 return nullptr;
1093 RefPtr<ID3D10Multithread> multi;
1094 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
1095 if (multi) {
1096 multi->SetMultithreadProtected(TRUE);
1098 if (reuseDevice) {
1099 mDecoderDevice = device;
1101 return 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);
1114 if (!LoadD3D11()) {
1115 return nullptr;
1118 HRESULT hr;
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)) {
1124 return nullptr;
1126 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
1127 return nullptr;
1129 Unused << SetDebugName(device.get(), "MFMediaEngineDevice");
1131 RefPtr<ID3D10Multithread> multi;
1132 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
1133 if (multi) {
1134 multi->SetMultithreadProtected(TRUE);
1136 return device;
1139 void DeviceManagerDx::ResetDevices() {
1140 MutexAutoLock lock(mDeviceLock);
1141 ResetDevicesLocked();
1144 void DeviceManagerDx::ResetDevicesLocked() {
1145 mAdapter = nullptr;
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)) {
1164 return false;
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
1178 return true;
1180 if (createContentDevice) {
1181 CreateContentDevicesLocked();
1183 if (createCanvasDevice) {
1184 CreateCanvasDeviceLocked();
1186 if (createDirectCompositionDevice) {
1187 CreateDirectCompositionDeviceLocked();
1190 return true;
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";
1197 return false;
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);
1209 return false;
1212 return true;
1215 static DeviceResetReason HResultToResetReason(HRESULT hr) {
1216 switch (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;
1227 case E_OUTOFMEMORY:
1228 return DeviceResetReason::OUT_OF_MEMORY;
1229 default:
1230 MOZ_ASSERT(false);
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) {
1242 if (aOutReason) {
1243 *aOutReason = mDeviceResetReason.value();
1245 return true;
1248 DeviceResetReason reason;
1249 if (GetAnyDeviceRemovedReason(&reason)) {
1250 mDeviceResetReason = Some(reason);
1251 if (aOutReason) {
1252 *aOutReason = reason;
1254 return true;
1257 return false;
1260 static inline bool DidDeviceReset(const RefPtr<ID3D11Device>& aDevice,
1261 DeviceResetReason* aOutReason) {
1262 if (!aDevice) {
1263 return false;
1265 HRESULT hr = aDevice->GetDeviceRemovedReason();
1266 if (hr == S_OK) {
1267 return false;
1270 *aOutReason = HResultToResetReason(hr);
1271 return true;
1274 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) {
1275 if (DidDeviceReset(mCompositorDevice, aOutReason) ||
1276 DidDeviceReset(mContentDevice, aOutReason) ||
1277 DidDeviceReset(mCanvasDevice, aOutReason)) {
1278 return true;
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;
1285 return true;
1288 return false;
1291 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason) {
1292 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON,
1293 uint32_t(aReason));
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);
1307 ResetDevices();
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
1313 /// safe. See
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);
1329 if (mImageDevice) {
1330 return mImageDevice;
1333 RefPtr<ID3D11Device> device = mContentDevice;
1334 if (!device) {
1335 device = mCompositorDevice;
1338 if (!device) {
1339 return nullptr;
1342 RefPtr<ID3D10Multithread> multi;
1343 HRESULT hr =
1344 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi));
1345 if (FAILED(hr) || !multi) {
1346 gfxWarning() << "Multithread safety interface not supported. " << hr;
1347 return nullptr;
1348 } else {
1349 MOZ_ASSERT(multi->GetMultithreadProtected());
1352 mImageDevice = device;
1354 return mImageDevice;
1357 RefPtr<ID3D11Device> DeviceManagerDx::GetVRDevice() {
1358 MutexAutoLock lock(mDeviceLock);
1359 if (!mVRDevice) {
1360 CreateVRDevice();
1362 return mVRDevice;
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) {
1378 return 0;
1380 return mDeviceStatus->featureLevel();
1383 bool DeviceManagerDx::TextureSharingWorks() {
1384 MutexAutoLock lock(mDeviceLock);
1385 if (!mDeviceStatus) {
1386 return false;
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) {
1400 return false;
1402 return mDeviceStatus->isWARP();
1405 bool DeviceManagerDx::CanUseNV12() {
1406 MutexAutoLock lock(mDeviceLock);
1407 if (!mDeviceStatus) {
1408 return false;
1410 return mDeviceStatus->formatOptions().contains(
1411 D3D11Checks::VideoFormatOption::NV12);
1414 bool DeviceManagerDx::CanUseP010() {
1415 MutexAutoLock lock(mDeviceLock);
1416 if (!mDeviceStatus) {
1417 return false;
1419 return mDeviceStatus->formatOptions().contains(
1420 D3D11Checks::VideoFormatOption::P010);
1423 bool DeviceManagerDx::CanUseP016() {
1424 MutexAutoLock lock(mDeviceLock);
1425 if (!mDeviceStatus) {
1426 return false;
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());
1440 if (mDirectDraw) {
1441 // Already initialized.
1442 return;
1445 FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1446 if (!ddraw.IsEnabled()) {
1447 return;
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);
1456 return;
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);
1465 return;
1468 HRESULT hr;
1469 MOZ_SEH_TRY {
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";
1477 return;
1479 if (FAILED(hr)) {
1480 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1481 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1482 gfxCriticalNote << "DoesCreatingDirectDrawFailed " << hexa(hr);
1483 return;
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) {
1496 return;
1498 if (mCompositorAttachments) {
1499 *aOutDevice = mCompositorDevice;
1500 *aOutAttachments = mCompositorAttachments;
1501 return;
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) {
1515 return;
1517 mCompositorAttachments = attachments;
1520 *aOutDevice = device;
1521 *aOutAttachments = attachments;
1524 /* static */
1525 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
1526 if (!CompositorThread()) {
1527 return;
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());
1541 } // namespace gfx
1542 } // namespace mozilla