No bug - tagging 2af34b4c9adf8c8defd3251b569af9c38cc0a429 with FIREFOX_BETA_124_BASE...
[gecko.git] / gfx / thebes / DeviceManagerDx.cpp
blob18c5cea7db7c6ffad04543a3800d200a4bae568c
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::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) {
210 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
212 if (!adapter) {
213 NS_WARNING(
214 "Failed to acquire a DXGI adapter for checking hardware stretching "
215 "support.");
216 ++aRv.mError;
217 return;
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.
225 break;
228 if (FAILED(result)) {
229 ++aRv.mError;
230 break;
233 RefPtr<IDXGIOutput6> output6 = nullptr;
234 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
235 getter_AddRefs(output6)))) {
236 ++aRv.mError;
237 continue;
240 UINT flags = 0;
241 if (FAILED(output6->CheckHardwareCompositionSupport(&flags))) {
242 ++aRv.mError;
243 continue;
246 bool fullScreen = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN;
247 bool window = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED;
248 if (fullScreen && window) {
249 ++aRv.mBoth;
250 } else if (fullScreen) {
251 ++aRv.mFullScreenOnly;
252 } else if (window) {
253 ++aRv.mWindowOnly;
254 } else {
255 ++aRv.mNone;
260 #ifdef DEBUG
261 static inline bool ProcessOwnsCompositor() {
262 return XRE_GetProcessType() == GeckoProcessType_GPU ||
263 XRE_GetProcessType() == GeckoProcessType_VR ||
264 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS));
266 #endif
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);
285 if (!LoadD3D11()) {
286 return false;
289 CreateCompositorDevice(d3d11);
291 if (!d3d11.IsEnabled()) {
292 MOZ_ASSERT(!mCompositorDevice);
293 ReleaseD3D11();
295 return false;
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()) {
305 return false;
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
312 // synchronously.
313 if (gfx::gfxVars::UseSoftwareWebRender()) {
314 PreloadAttachmentsOnCompositorThread();
317 return true;
320 bool DeviceManagerDx::CreateVRDevice() {
321 MOZ_ASSERT(ProcessOwnsCompositor());
323 if (mVRDevice) {
324 return true;
327 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
328 NS_WARNING("Direct3D11 Compositing required for VR");
329 return false;
332 if (!LoadD3D11()) {
333 return false;
336 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
337 if (!adapter) {
338 NS_WARNING("Failed to acquire a DXGI adapter for VR");
339 return false;
342 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
344 HRESULT hr;
345 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, mVRDevice)) {
346 gfxCriticalError() << "Crash during D3D11 device creation for VR";
347 return false;
350 if (FAILED(hr) || !mVRDevice) {
351 NS_WARNING("Failed to acquire a D3D11 device for VR");
352 return false;
355 return true;
358 bool DeviceManagerDx::CreateCanvasDevice() {
359 MutexAutoLock lock(mDeviceLock);
360 return CreateCanvasDeviceLocked();
363 bool DeviceManagerDx::CreateCanvasDeviceLocked() {
364 MOZ_ASSERT(ProcessOwnsCompositor());
366 if (mCanvasDevice) {
367 return true;
370 if (!LoadD3D11()) {
371 return false;
374 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
375 if (!adapter) {
376 NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
377 return false;
380 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
382 HRESULT hr;
383 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr,
384 mCanvasDevice)) {
385 gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
386 return false;
389 if (StaticPrefs::
390 gfx_direct2d_target_independent_rasterization_disabled_AtStartup()) {
391 int creationFlags = 0x2; // disable target independent rasterization
392 const GUID D2D_INTERNAL_DEVICE_CREATION_OPTIONS = {
393 0xfb3a8e1a,
394 0x2e3c,
395 0x4de1,
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");
403 return false;
406 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice)) {
407 mCanvasDevice = nullptr;
408 return false;
411 if (XRE_IsGPUProcess()) {
412 Factory::SetDirect3D11Device(mCanvasDevice);
415 return true;
418 void DeviceManagerDx::CreateDirectCompositionDevice() {
419 MutexAutoLock lock(mDeviceLock);
420 CreateDirectCompositionDeviceLocked();
423 void DeviceManagerDx::CreateDirectCompositionDeviceLocked() {
424 if (!gfxVars::UseWebRenderDCompWin()) {
425 return;
428 if (!mCompositorDevice) {
429 return;
432 if (!LoadDcomp()) {
433 return;
436 RefPtr<IDXGIDevice> dxgiDevice;
437 if (mCompositorDevice->QueryInterface(
438 IID_PPV_ARGS((IDXGIDevice**)getter_AddRefs(dxgiDevice))) != S_OK) {
439 return;
442 HRESULT hr;
443 RefPtr<IDCompositionDesktopDevice> desktopDevice;
444 MOZ_SEH_TRY {
445 hr = sDcompCreateDevice3Fn(
446 dxgiDevice.get(),
447 IID_PPV_ARGS(
448 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
449 if (!desktopDevice) {
450 hr = sDcompCreateDevice2Fn(
451 dxgiDevice.get(),
452 IID_PPV_ARGS(
453 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
456 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; }
458 if (!SUCCEEDED(hr)) {
459 return;
462 RefPtr<IDCompositionDevice2> compositionDevice;
463 if (desktopDevice->QueryInterface(IID_PPV_ARGS(
464 (IDCompositionDevice2**)getter_AddRefs(compositionDevice))) != S_OK) {
465 return;
468 mDirectCompositionDevice = compositionDevice;
471 /* static */
472 HANDLE DeviceManagerDx::CreateDCompSurfaceHandle() {
473 if (!sDcompCreateSurfaceHandleFn) {
474 return 0;
477 HANDLE handle = 0;
478 HRESULT hr = sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS,
479 nullptr, &handle);
480 if (FAILED(hr)) {
481 return 0;
484 return handle;
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);
496 if (mDeviceStatus) {
497 *aOut = mDeviceStatus.value();
498 return true;
501 return false;
504 void DeviceManagerDx::CreateContentDevices() {
505 MutexAutoLock lock(mDeviceLock);
506 CreateContentDevicesLocked();
509 void DeviceManagerDx::CreateContentDevicesLocked() {
510 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING));
512 if (!LoadD3D11()) {
513 return;
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() {
531 if (mAdapter) {
532 return mAdapter;
535 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
536 decltype(CreateDXGIFactory1)* createDXGIFactory1 =
537 (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgiModule,
538 "CreateDXGIFactory1");
539 if (!createDXGIFactory1) {
540 return nullptr;
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
547 // across processes.
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));
556 } else {
557 NS_WARNING(
558 "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2.");
560 factory1 = factory2;
562 if (!factory1) {
563 HRESULT hr =
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.
568 return nullptr;
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)))) {
576 return nullptr;
578 } else {
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
584 // process
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)))) {
592 break;
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();
604 break;
609 if (!mAdapter) {
610 return nullptr;
613 // We leak this module everywhere, we might as well do so here as well.
614 dxgiModule.disown();
615 return mAdapter;
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);
626 return false;
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;
645 HRESULT hr;
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);
654 return false;
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);
663 return false;
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);
671 return false;
674 aOutDevice = device;
675 return true;
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();
691 return;
694 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
695 if (!adapter) {
696 d3d11.SetFailed(FeatureStatus::Unavailable,
697 "Failed to acquire a DXGI adapter",
698 "FEATURE_FAILURE_D3D11_DXGI"_ns);
699 return;
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);
706 return;
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)) {
714 return;
716 } else {
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;
725 PodZero(&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 RefPtr<ID3D10Multithread> multi;
744 HRESULT hr = device->QueryInterface(__uuidof(ID3D10Multithread),
745 getter_AddRefs(multi));
746 if (SUCCEEDED(hr) && multi) {
747 multi->SetMultithreadProtected(TRUE);
750 uint32_t featureLevel = device->GetFeatureLevel();
751 auto formatOptions = D3D11Checks::FormatOptions(device);
752 mCompositorDevice = device;
754 int32_t sequenceNumber = GetNextDeviceCounter();
755 mDeviceStatus = Some(D3D11DeviceStatus(
756 false, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
757 sequenceNumber, formatOptions));
758 mCompositorDevice->SetExceptionMode(0);
761 bool DeviceManagerDx::CreateDevice(IDXGIAdapter* aAdapter,
762 D3D_DRIVER_TYPE aDriverType, UINT aFlags,
763 HRESULT& aResOut,
764 RefPtr<ID3D11Device>& aOutDevice) {
765 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup() ||
766 StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
767 aFlags |= D3D11_CREATE_DEVICE_DEBUG;
770 MOZ_SEH_TRY {
771 aResOut = sD3D11CreateDeviceFn(
772 aAdapter, aDriverType, nullptr, aFlags, mFeatureLevels.Elements(),
773 mFeatureLevels.Length(), D3D11_SDK_VERSION, getter_AddRefs(aOutDevice),
774 nullptr, nullptr);
776 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return false; }
778 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
779 do {
780 if (!aOutDevice) break;
782 RefPtr<ID3D11Debug> debug;
783 if (!SUCCEEDED(aOutDevice->QueryInterface(__uuidof(ID3D11Debug),
784 getter_AddRefs(debug))))
785 break;
787 RefPtr<ID3D11InfoQueue> infoQueue;
788 if (!SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue),
789 getter_AddRefs(infoQueue))))
790 break;
792 D3D11_INFO_QUEUE_FILTER filter;
793 PodZero(&filter);
795 // Disable warnings caused by Advanced Layers that are known and not
796 // problematic.
797 D3D11_MESSAGE_ID blockIDs[] = {
798 D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL};
799 filter.DenyList.NumIDs = MOZ_ARRAY_LENGTH(blockIDs);
800 filter.DenyList.pIDList = blockIDs;
801 infoQueue->PushStorageFilter(&filter);
803 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
804 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
805 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
806 } while (false);
809 return true;
812 void DeviceManagerDx::CreateWARPCompositorDevice() {
813 ScopedGfxFeatureReporter reporterWARP(
814 "D3D11-WARP", StaticPrefs::layers_d3d11_force_warp_AtStartup());
815 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
817 HRESULT hr;
818 RefPtr<ID3D11Device> device;
820 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
821 // to prevent bug 1092260. IE 11 also uses this flag.
822 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
823 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, flags, hr, device)) {
824 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
825 d3d11.SetFailed(FeatureStatus::CrashedInHandler,
826 "Crashed creating a D3D11 WARP device",
827 "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns);
830 if (FAILED(hr) || !device) {
831 // This should always succeed... in theory.
832 gfxCriticalError() << "Failed to initialize WARP D3D11 device! "
833 << hexa(hr);
834 d3d11.SetFailed(FeatureStatus::Failed,
835 "Failed to create a D3D11 WARP device",
836 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns);
837 return;
840 bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
842 RefPtr<ID3D10Multithread> multi;
843 hr = device->QueryInterface(__uuidof(ID3D10Multithread),
844 getter_AddRefs(multi));
845 if (SUCCEEDED(hr) && multi) {
846 multi->SetMultithreadProtected(TRUE);
849 DXGI_ADAPTER_DESC desc;
850 D3D11Checks::GetDxgiDesc(device, &desc);
852 int featureLevel = device->GetFeatureLevel();
854 auto formatOptions = D3D11Checks::FormatOptions(device);
855 mCompositorDevice = device;
857 int32_t sequenceNumber = GetNextDeviceCounter();
858 mDeviceStatus = Some(D3D11DeviceStatus(
859 true, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
860 sequenceNumber, formatOptions));
861 mCompositorDevice->SetExceptionMode(0);
863 reporterWARP.SetSuccessful();
866 FeatureStatus DeviceManagerDx::CreateContentDevice() {
867 RefPtr<IDXGIAdapter1> adapter;
868 if (!mDeviceStatus->isWARP()) {
869 adapter = GetDXGIAdapterLocked();
870 if (!adapter) {
871 gfxCriticalNote << "Could not get a DXGI adapter";
872 return FeatureStatus::Unavailable;
876 HRESULT hr;
877 RefPtr<ID3D11Device> device;
879 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
880 D3D_DRIVER_TYPE type =
881 mDeviceStatus->isWARP() ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN;
882 if (!CreateDevice(adapter, type, flags, hr, device)) {
883 gfxCriticalNote
884 << "Recovered from crash while creating a D3D11 content device";
885 gfxWindowsPlatform::RecordContentDeviceFailure(
886 TelemetryDeviceCode::Content);
887 return FeatureStatus::CrashedInHandler;
890 if (FAILED(hr) || !device) {
891 gfxCriticalNote << "Failed to create a D3D11 content device: " << hexa(hr);
892 gfxWindowsPlatform::RecordContentDeviceFailure(
893 TelemetryDeviceCode::Content);
894 return FeatureStatus::Failed;
897 // InitializeD2D() will abort early if the compositor device did not support
898 // texture sharing. If we're in the content process, we can't rely on the
899 // parent device alone: some systems have dual GPUs that are capable of
900 // binding the parent and child processes to different GPUs. As a safety net,
901 // we re-check texture sharing against the newly created D3D11 content device.
902 // If it fails, we won't use Direct2D.
903 if (XRE_IsContentProcess()) {
904 if (!D3D11Checks::DoesTextureSharingWork(device)) {
905 return FeatureStatus::Failed;
908 DebugOnly<bool> ok = ContentAdapterIsParentAdapter(device);
909 MOZ_ASSERT(ok);
912 mContentDevice = device;
913 mContentDevice->SetExceptionMode(0);
915 RefPtr<ID3D10Multithread> multi;
916 hr = mContentDevice->QueryInterface(__uuidof(ID3D10Multithread),
917 getter_AddRefs(multi));
918 if (SUCCEEDED(hr) && multi) {
919 multi->SetMultithreadProtected(TRUE);
921 return FeatureStatus::Available;
924 RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice(
925 bool aHardwareWebRender) {
926 MutexAutoLock lock(mDeviceLock);
928 if (!mDeviceStatus) {
929 return nullptr;
932 bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002;
933 bool reuseDevice = false;
934 if (gfxVars::ReuseDecoderDevice()) {
935 reuseDevice = true;
936 } else if (isAMD) {
937 reuseDevice = true;
938 gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD";
941 if (reuseDevice) {
942 // Use mCompositorDevice for decoder device only for hardware WebRender.
943 if (aHardwareWebRender && mCompositorDevice &&
944 mCompositorDeviceSupportsVideo && !mDecoderDevice) {
945 mDecoderDevice = mCompositorDevice;
947 RefPtr<ID3D10Multithread> multi;
948 mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread),
949 getter_AddRefs(multi));
950 if (multi) {
951 MOZ_ASSERT(multi->GetMultithreadProtected());
955 if (mDecoderDevice) {
956 RefPtr<ID3D11Device> dev = mDecoderDevice;
957 return dev.forget();
961 if (!sD3D11CreateDeviceFn) {
962 // We should just be on Windows Vista or XP in this case.
963 return nullptr;
966 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
967 if (!adapter) {
968 return nullptr;
971 HRESULT hr;
972 RefPtr<ID3D11Device> device;
974 UINT flags = D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS |
975 D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
976 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
977 return nullptr;
979 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
980 return nullptr;
983 RefPtr<ID3D10Multithread> multi;
984 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
985 if (multi) {
986 multi->SetMultithreadProtected(TRUE);
988 if (reuseDevice) {
989 mDecoderDevice = device;
991 return device;
994 // ID3D11DeviceChild, IDXGIObject and ID3D11Device implement SetPrivateData with
995 // the exact same parameters.
996 template <typename T>
997 static HRESULT SetDebugName(T* d3d11Object, const char* debugString) {
998 return d3d11Object->SetPrivateData(WKPDID_D3DDebugObjectName,
999 strlen(debugString), debugString);
1002 RefPtr<ID3D11Device> DeviceManagerDx::CreateMediaEngineDevice() {
1003 MutexAutoLock lock(mDeviceLock);
1004 if (!LoadD3D11()) {
1005 return nullptr;
1008 HRESULT hr;
1009 RefPtr<ID3D11Device> device;
1010 UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT |
1011 D3D11_CREATE_DEVICE_BGRA_SUPPORT |
1012 D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
1013 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, flags, hr, device)) {
1014 return nullptr;
1016 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
1017 return nullptr;
1019 Unused << SetDebugName(device.get(), "MFMediaEngineDevice");
1021 RefPtr<ID3D10Multithread> multi;
1022 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
1023 if (multi) {
1024 multi->SetMultithreadProtected(TRUE);
1026 return device;
1029 void DeviceManagerDx::ResetDevices() {
1030 MutexAutoLock lock(mDeviceLock);
1031 ResetDevicesLocked();
1034 void DeviceManagerDx::ResetDevicesLocked() {
1035 mAdapter = nullptr;
1036 mCompositorAttachments = nullptr;
1037 mCompositorDevice = nullptr;
1038 mContentDevice = nullptr;
1039 mCanvasDevice = nullptr;
1040 mImageDevice = nullptr;
1041 mVRDevice = nullptr;
1042 mDecoderDevice = nullptr;
1043 mDirectCompositionDevice = nullptr;
1044 mDeviceStatus = Nothing();
1045 mDeviceResetReason = Nothing();
1046 Factory::SetDirect3D11Device(nullptr);
1049 bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
1050 MutexAutoLock lock(mDeviceLock);
1052 DeviceResetReason resetReason;
1053 if (!HasDeviceResetLocked(&resetReason)) {
1054 return false;
1057 GPUProcessManager::RecordDeviceReset(resetReason);
1059 bool createCompositorDevice = !!mCompositorDevice;
1060 bool createContentDevice = !!mContentDevice;
1061 bool createCanvasDevice = !!mCanvasDevice;
1062 bool createDirectCompositionDevice = !!mDirectCompositionDevice;
1064 ResetDevicesLocked();
1066 if (createCompositorDevice && !CreateCompositorDevicesLocked()) {
1067 // Just stop, don't try anything more
1068 return true;
1070 if (createContentDevice) {
1071 CreateContentDevicesLocked();
1073 if (createCanvasDevice) {
1074 CreateCanvasDeviceLocked();
1076 if (createDirectCompositionDevice) {
1077 CreateDirectCompositionDeviceLocked();
1080 return true;
1083 bool DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device* device) {
1084 DXGI_ADAPTER_DESC desc;
1085 if (!D3D11Checks::GetDxgiDesc(device, &desc)) {
1086 gfxCriticalNote << "Could not query device DXGI adapter info";
1087 return false;
1090 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
1092 if (desc.VendorId != preferred.VendorId ||
1093 desc.DeviceId != preferred.DeviceId ||
1094 desc.SubSysId != preferred.SubSysId ||
1095 desc.AdapterLuid.HighPart != preferred.AdapterLuid.HighPart ||
1096 desc.AdapterLuid.LowPart != preferred.AdapterLuid.LowPart) {
1097 gfxCriticalNote << "VendorIDMismatch P " << hexa(preferred.VendorId) << " "
1098 << hexa(desc.VendorId);
1099 return false;
1102 return true;
1105 static DeviceResetReason HResultToResetReason(HRESULT hr) {
1106 switch (hr) {
1107 case DXGI_ERROR_DEVICE_HUNG:
1108 return DeviceResetReason::HUNG;
1109 case DXGI_ERROR_DEVICE_REMOVED:
1110 return DeviceResetReason::REMOVED;
1111 case DXGI_ERROR_DEVICE_RESET:
1112 return DeviceResetReason::RESET;
1113 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
1114 return DeviceResetReason::DRIVER_ERROR;
1115 case DXGI_ERROR_INVALID_CALL:
1116 return DeviceResetReason::INVALID_CALL;
1117 case E_OUTOFMEMORY:
1118 return DeviceResetReason::OUT_OF_MEMORY;
1119 default:
1120 MOZ_ASSERT(false);
1122 return DeviceResetReason::OTHER;
1125 bool DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason) {
1126 MutexAutoLock lock(mDeviceLock);
1127 return HasDeviceResetLocked(aOutReason);
1130 bool DeviceManagerDx::HasDeviceResetLocked(DeviceResetReason* aOutReason) {
1131 if (mDeviceResetReason) {
1132 if (aOutReason) {
1133 *aOutReason = mDeviceResetReason.value();
1135 return true;
1138 DeviceResetReason reason;
1139 if (GetAnyDeviceRemovedReason(&reason)) {
1140 mDeviceResetReason = Some(reason);
1141 if (aOutReason) {
1142 *aOutReason = reason;
1144 return true;
1147 return false;
1150 static inline bool DidDeviceReset(const RefPtr<ID3D11Device>& aDevice,
1151 DeviceResetReason* aOutReason) {
1152 if (!aDevice) {
1153 return false;
1155 HRESULT hr = aDevice->GetDeviceRemovedReason();
1156 if (hr == S_OK) {
1157 return false;
1160 *aOutReason = HResultToResetReason(hr);
1161 return true;
1164 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) {
1165 if (DidDeviceReset(mCompositorDevice, aOutReason) ||
1166 DidDeviceReset(mContentDevice, aOutReason) ||
1167 DidDeviceReset(mCanvasDevice, aOutReason)) {
1168 return true;
1171 if (XRE_IsParentProcess() && NS_IsMainThread() &&
1172 StaticPrefs::gfx_testing_device_reset()) {
1173 Preferences::SetInt("gfx.testing.device-reset", 0);
1174 *aOutReason = DeviceResetReason::FORCED_RESET;
1175 return true;
1178 return false;
1181 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason) {
1182 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON,
1183 uint32_t(aReason));
1185 MutexAutoLock lock(mDeviceLock);
1186 if (!mDeviceResetReason) {
1187 mDeviceResetReason = Some(DeviceResetReason::FORCED_RESET);
1192 void DeviceManagerDx::DisableD3D11AfterCrash() {
1193 gfxConfig::Disable(Feature::D3D11_COMPOSITING,
1194 FeatureStatus::CrashedInHandler,
1195 "Crashed while acquiring a Direct3D11 device",
1196 "FEATURE_FAILURE_D3D11_CRASH"_ns);
1197 ResetDevices();
1200 RefPtr<ID3D11Device> DeviceManagerDx::GetCompositorDevice() {
1201 /// ID3D11Device is thread-safe. We need the lock to read the
1202 /// mDeviceLockPointer, but manipulating the pointee outside of the lock is
1203 /// safe. See
1204 /// https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-render-multi-thread-intro
1205 MutexAutoLock lock(mDeviceLock);
1206 return mCompositorDevice;
1209 RefPtr<ID3D11Device> DeviceManagerDx::GetContentDevice() {
1210 MOZ_ASSERT(XRE_IsGPUProcess() ||
1211 gfxPlatform::GetPlatform()->DevicesInitialized());
1213 MutexAutoLock lock(mDeviceLock);
1214 return mContentDevice;
1217 RefPtr<ID3D11Device> DeviceManagerDx::GetImageDevice() {
1218 MutexAutoLock lock(mDeviceLock);
1219 if (mImageDevice) {
1220 return mImageDevice;
1223 RefPtr<ID3D11Device> device = mContentDevice;
1224 if (!device) {
1225 device = mCompositorDevice;
1228 if (!device) {
1229 return nullptr;
1232 RefPtr<ID3D10Multithread> multi;
1233 HRESULT hr =
1234 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi));
1235 if (FAILED(hr) || !multi) {
1236 gfxWarning() << "Multithread safety interface not supported. " << hr;
1237 return nullptr;
1238 } else {
1239 MOZ_ASSERT(multi->GetMultithreadProtected());
1242 mImageDevice = device;
1244 return mImageDevice;
1247 RefPtr<ID3D11Device> DeviceManagerDx::GetVRDevice() {
1248 MutexAutoLock lock(mDeviceLock);
1249 if (!mVRDevice) {
1250 CreateVRDevice();
1252 return mVRDevice;
1255 RefPtr<ID3D11Device> DeviceManagerDx::GetCanvasDevice() {
1256 MutexAutoLock lock(mDeviceLock);
1257 return mCanvasDevice;
1260 RefPtr<IDCompositionDevice2> DeviceManagerDx::GetDirectCompositionDevice() {
1261 MutexAutoLock lock(mDeviceLock);
1262 return mDirectCompositionDevice;
1265 unsigned DeviceManagerDx::GetCompositorFeatureLevel() const {
1266 MutexAutoLock lock(mDeviceLock);
1267 if (!mDeviceStatus) {
1268 return 0;
1270 return mDeviceStatus->featureLevel();
1273 bool DeviceManagerDx::TextureSharingWorks() {
1274 MutexAutoLock lock(mDeviceLock);
1275 if (!mDeviceStatus) {
1276 return false;
1278 return mDeviceStatus->textureSharingWorks();
1281 bool DeviceManagerDx::CanInitializeKeyedMutexTextures() {
1282 MutexAutoLock lock(mDeviceLock);
1283 return mDeviceStatus && StaticPrefs::gfx_direct3d11_allow_keyed_mutex() &&
1284 gfxVars::AllowD3D11KeyedMutex();
1287 bool DeviceManagerDx::IsWARP() {
1288 MutexAutoLock lock(mDeviceLock);
1289 if (!mDeviceStatus) {
1290 return false;
1292 return mDeviceStatus->isWARP();
1295 bool DeviceManagerDx::CanUseNV12() {
1296 MutexAutoLock lock(mDeviceLock);
1297 if (!mDeviceStatus) {
1298 return false;
1300 return mDeviceStatus->formatOptions().contains(
1301 D3D11Checks::VideoFormatOption::NV12);
1304 bool DeviceManagerDx::CanUseP010() {
1305 MutexAutoLock lock(mDeviceLock);
1306 if (!mDeviceStatus) {
1307 return false;
1309 return mDeviceStatus->formatOptions().contains(
1310 D3D11Checks::VideoFormatOption::P010);
1313 bool DeviceManagerDx::CanUseP016() {
1314 MutexAutoLock lock(mDeviceLock);
1315 if (!mDeviceStatus) {
1316 return false;
1318 return mDeviceStatus->formatOptions().contains(
1319 D3D11Checks::VideoFormatOption::P016);
1322 bool DeviceManagerDx::CanUseDComp() {
1323 MutexAutoLock lock(mDeviceLock);
1324 return !!mDirectCompositionDevice;
1327 void DeviceManagerDx::InitializeDirectDraw() {
1328 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
1330 if (mDirectDraw) {
1331 // Already initialized.
1332 return;
1335 FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1336 if (!ddraw.IsEnabled()) {
1337 return;
1340 // Check if DirectDraw is available on this system.
1341 mDirectDrawDLL.own(LoadLibrarySystem32(L"ddraw.dll"));
1342 if (!mDirectDrawDLL) {
1343 ddraw.SetFailed(FeatureStatus::Unavailable,
1344 "DirectDraw not available on this computer",
1345 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1346 return;
1349 sDirectDrawCreateExFn = (decltype(DirectDrawCreateEx)*)GetProcAddress(
1350 mDirectDrawDLL, "DirectDrawCreateEx");
1351 if (!sDirectDrawCreateExFn) {
1352 ddraw.SetFailed(FeatureStatus::Unavailable,
1353 "DirectDraw not available on this computer",
1354 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1355 return;
1358 HRESULT hr;
1359 MOZ_SEH_TRY {
1360 hr = sDirectDrawCreateExFn(nullptr, getter_AddRefs(mDirectDraw),
1361 IID_IDirectDraw7, nullptr);
1363 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1364 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1365 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1366 gfxCriticalNote << "DoesCreatingDirectDrawFailed";
1367 return;
1369 if (FAILED(hr)) {
1370 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1371 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1372 gfxCriticalNote << "DoesCreatingDirectDrawFailed " << hexa(hr);
1373 return;
1377 IDirectDraw7* DeviceManagerDx::GetDirectDraw() { return mDirectDraw; }
1379 void DeviceManagerDx::GetCompositorDevices(
1380 RefPtr<ID3D11Device>* aOutDevice,
1381 RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments) {
1382 RefPtr<ID3D11Device> device;
1384 MutexAutoLock lock(mDeviceLock);
1385 if (!mCompositorDevice) {
1386 return;
1388 if (mCompositorAttachments) {
1389 *aOutDevice = mCompositorDevice;
1390 *aOutAttachments = mCompositorAttachments;
1391 return;
1394 // Otherwise, we'll try to create attachments outside the lock.
1395 device = mCompositorDevice;
1398 // We save the attachments object even if it fails to initialize, so the
1399 // compositor can grab the failure ID.
1400 RefPtr<layers::DeviceAttachmentsD3D11> attachments =
1401 layers::DeviceAttachmentsD3D11::Create(device);
1403 MutexAutoLock lock(mDeviceLock);
1404 if (device != mCompositorDevice) {
1405 return;
1407 mCompositorAttachments = attachments;
1410 *aOutDevice = device;
1411 *aOutAttachments = attachments;
1414 /* static */
1415 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
1416 if (!CompositorThread()) {
1417 return;
1420 RefPtr<Runnable> task = NS_NewRunnableFunction(
1421 "DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void {
1422 if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
1423 RefPtr<ID3D11Device> device;
1424 RefPtr<layers::DeviceAttachmentsD3D11> attachments;
1425 dm->GetCompositorDevices(&device, &attachments);
1428 CompositorThread()->Dispatch(task.forget());
1431 } // namespace gfx
1432 } // namespace mozilla