Bug 1799258 - Share all-of-dcomp.h preamble, and deal with outdated mingw dcomp.h...
[gecko.git] / gfx / thebes / DeviceManagerDx.cpp
blob100cd3192afc6431b2d74cacddbfd23975537bff
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/WindowsVersion.h"
16 #include "mozilla/gfx/GPUParent.h"
17 #include "mozilla/gfx/GPUProcessManager.h"
18 #include "mozilla/gfx/GraphicsMessages.h"
19 #include "mozilla/gfx/Logging.h"
20 #include "mozilla/gfx/gfxVars.h"
21 #include "mozilla/layers/CompositorBridgeChild.h"
22 #include "mozilla/layers/CompositorThread.h"
23 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
24 #include "mozilla/Preferences.h"
25 #include "nsPrintfCString.h"
26 #include "nsString.h"
28 // -
30 #include "mozilla/gfx/AllOfDcomp.h"
31 #include <d3d11.h>
32 #include <ddraw.h>
33 #include <dxgi.h>
35 namespace mozilla {
36 namespace gfx {
38 using namespace mozilla::widget;
39 using namespace mozilla::layers;
41 StaticAutoPtr<DeviceManagerDx> DeviceManagerDx::sInstance;
43 // We don't have access to the D3D11CreateDevice type in gfxWindowsPlatform.h,
44 // since it doesn't include d3d11.h, so we use a static here. It should only
45 // be used within InitializeD3D11.
46 decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr;
48 // It should only be used within CreateDirectCompositionDevice.
49 decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr;
50 decltype(DCompositionCreateDevice3)* sDcompCreateDevice3Fn = nullptr;
52 // It should only be used within CreateDCompSurfaceHandle
53 decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn =
54 nullptr;
56 // We don't have access to the DirectDrawCreateEx type in gfxWindowsPlatform.h,
57 // since it doesn't include ddraw.h, so we use a static here. It should only
58 // be used within InitializeDirectDrawConfig.
59 decltype(DirectDrawCreateEx)* sDirectDrawCreateExFn = nullptr;
61 /* static */
62 void DeviceManagerDx::Init() { sInstance = new DeviceManagerDx(); }
64 /* static */
65 void DeviceManagerDx::Shutdown() { sInstance = nullptr; }
67 DeviceManagerDx::DeviceManagerDx()
68 : mDeviceLock("gfxWindowsPlatform.mDeviceLock"),
69 mCompositorDeviceSupportsVideo(false) {
70 // Set up the D3D11 feature levels we can ask for.
71 if (IsWin8OrLater()) {
72 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1);
74 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0);
75 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1);
76 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0);
77 MOZ_COUNT_CTOR(DeviceManagerDx);
80 DeviceManagerDx::~DeviceManagerDx() { MOZ_COUNT_DTOR(DeviceManagerDx); }
82 bool DeviceManagerDx::LoadD3D11() {
83 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
84 MOZ_ASSERT(d3d11.IsEnabled());
86 if (sD3D11CreateDeviceFn) {
87 return true;
90 nsModuleHandle module(LoadLibrarySystem32(L"d3d11.dll"));
91 if (!module) {
92 d3d11.SetFailed(FeatureStatus::Unavailable,
93 "Direct3D11 not available on this computer",
94 "FEATURE_FAILURE_D3D11_LIB"_ns);
95 return false;
98 sD3D11CreateDeviceFn =
99 (decltype(D3D11CreateDevice)*)GetProcAddress(module, "D3D11CreateDevice");
100 if (!sD3D11CreateDeviceFn) {
101 // We should just be on Windows Vista or XP in this case.
102 d3d11.SetFailed(FeatureStatus::Unavailable,
103 "Direct3D11 not available on this computer",
104 "FEATURE_FAILURE_D3D11_FUNCPTR"_ns);
105 return false;
108 mD3D11Module.steal(module);
109 return true;
112 bool DeviceManagerDx::LoadDcomp() {
113 MOZ_ASSERT(gfxConfig::GetFeature(Feature::D3D11_COMPOSITING).IsEnabled());
114 MOZ_ASSERT(gfxVars::UseWebRenderANGLE());
115 MOZ_ASSERT(gfxVars::UseWebRenderDCompWin());
117 if (sDcompCreateDevice2Fn) {
118 return true; // Already loaded.
121 nsModuleHandle module(LoadLibrarySystem32(L"dcomp.dll"));
122 if (!module) {
123 return false;
126 sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress(
127 module, "DCompositionCreateDevice2");
128 sDcompCreateDevice3Fn = (decltype(DCompositionCreateDevice3)*)GetProcAddress(
129 module, "DCompositionCreateDevice3");
130 if (!sDcompCreateDevice2Fn) {
131 return false;
134 // Load optional API for external compositing
135 sDcompCreateSurfaceHandleFn =
136 (decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress(
137 module, "DCompositionCreateSurfaceHandle");
139 mDcompModule.steal(module);
140 return true;
143 void DeviceManagerDx::ReleaseD3D11() {
144 MOZ_ASSERT(!mCompositorDevice);
145 MOZ_ASSERT(!mContentDevice);
146 MOZ_ASSERT(!mVRDevice);
147 MOZ_ASSERT(!mDecoderDevice);
149 mD3D11Module.reset();
150 sD3D11CreateDeviceFn = nullptr;
153 nsTArray<DXGI_OUTPUT_DESC1> DeviceManagerDx::EnumerateOutputs() {
154 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
156 if (!adapter) {
157 NS_WARNING("Failed to acquire a DXGI adapter for enumerating outputs.");
158 return nsTArray<DXGI_OUTPUT_DESC1>();
161 nsTArray<DXGI_OUTPUT_DESC1> outputs;
162 for (UINT i = 0;; ++i) {
163 RefPtr<IDXGIOutput> output = nullptr;
164 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) {
165 break;
168 RefPtr<IDXGIOutput6> output6 = nullptr;
169 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
170 getter_AddRefs(output6)))) {
171 break;
174 DXGI_OUTPUT_DESC1 desc;
175 if (FAILED(output6->GetDesc1(&desc))) {
176 break;
179 outputs.AppendElement(desc);
181 return outputs;
184 bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor,
185 RefPtr<IDXGIOutput>* aOutOutput) {
186 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
188 if (!adapter) {
189 NS_WARNING("Failed to acquire a DXGI adapter for GetOutputFromMonitor.");
190 return false;
193 for (UINT i = 0;; ++i) {
194 RefPtr<IDXGIOutput> output = nullptr;
195 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) {
196 break;
199 DXGI_OUTPUT_DESC desc;
200 if (FAILED(output->GetDesc(&desc))) {
201 continue;
204 if (desc.Monitor == monitor) {
205 *aOutOutput = output;
206 return true;
209 return false;
212 void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) {
213 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter();
215 if (!adapter) {
216 NS_WARNING(
217 "Failed to acquire a DXGI adapter for checking hardware stretching "
218 "support.");
219 ++aRv.mError;
220 return;
223 for (UINT i = 0;; ++i) {
224 RefPtr<IDXGIOutput> output = nullptr;
225 HRESULT result = adapter->EnumOutputs(i, getter_AddRefs(output));
226 if (result == DXGI_ERROR_NOT_FOUND) {
227 // No more outputs to check.
228 break;
231 if (FAILED(result)) {
232 ++aRv.mError;
233 break;
236 RefPtr<IDXGIOutput6> output6 = nullptr;
237 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6),
238 getter_AddRefs(output6)))) {
239 ++aRv.mError;
240 continue;
243 UINT flags = 0;
244 if (FAILED(output6->CheckHardwareCompositionSupport(&flags))) {
245 ++aRv.mError;
246 continue;
249 bool fullScreen = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN;
250 bool window = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED;
251 if (fullScreen && window) {
252 ++aRv.mBoth;
253 } else if (fullScreen) {
254 ++aRv.mFullScreenOnly;
255 } else if (window) {
256 ++aRv.mWindowOnly;
257 } else {
258 ++aRv.mNone;
263 #ifdef DEBUG
264 static inline bool ProcessOwnsCompositor() {
265 return XRE_GetProcessType() == GeckoProcessType_GPU ||
266 XRE_GetProcessType() == GeckoProcessType_VR ||
267 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS));
269 #endif
271 bool DeviceManagerDx::CreateCompositorDevices() {
272 MutexAutoLock lock(mDeviceLock);
273 return CreateCompositorDevicesLocked();
276 bool DeviceManagerDx::CreateCompositorDevicesLocked() {
277 MOZ_ASSERT(ProcessOwnsCompositor());
279 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
280 MOZ_ASSERT(d3d11.IsEnabled());
282 if (int32_t sleepSec =
283 StaticPrefs::gfx_direct3d11_sleep_on_create_device_AtStartup()) {
284 printf_stderr("Attach to PID: %lu\n", GetCurrentProcessId());
285 Sleep(sleepSec * 1000);
288 if (!LoadD3D11()) {
289 return false;
292 CreateCompositorDevice(d3d11);
294 if (!d3d11.IsEnabled()) {
295 MOZ_ASSERT(!mCompositorDevice);
296 ReleaseD3D11();
298 return false;
301 // We leak these everywhere and we need them our entire runtime anyway, let's
302 // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around
303 // as well for D2D1 and device resets.
304 mD3D11Module.disown();
306 MOZ_ASSERT(mCompositorDevice);
307 if (!d3d11.IsEnabled()) {
308 return false;
311 // When WR is used, do not preload attachments for D3D11 Non-WR compositor.
313 // Fallback from WR to D3D11 Non-WR compositor without re-creating gpu process
314 // could happen when WR causes error. In this case, the attachments are loaded
315 // synchronously.
316 if (gfx::gfxVars::UseSoftwareWebRender()) {
317 PreloadAttachmentsOnCompositorThread();
320 return true;
323 bool DeviceManagerDx::CreateVRDevice() {
324 MOZ_ASSERT(ProcessOwnsCompositor());
326 if (mVRDevice) {
327 return true;
330 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
331 NS_WARNING("Direct3D11 Compositing required for VR");
332 return false;
335 if (!LoadD3D11()) {
336 return false;
339 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
340 if (!adapter) {
341 NS_WARNING("Failed to acquire a DXGI adapter for VR");
342 return false;
345 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
347 HRESULT hr;
348 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, mVRDevice)) {
349 gfxCriticalError() << "Crash during D3D11 device creation for VR";
350 return false;
353 if (FAILED(hr) || !mVRDevice) {
354 NS_WARNING("Failed to acquire a D3D11 device for VR");
355 return false;
358 return true;
361 bool DeviceManagerDx::CreateCanvasDevice() {
362 MutexAutoLock lock(mDeviceLock);
363 return CreateCanvasDeviceLocked();
366 bool DeviceManagerDx::CreateCanvasDeviceLocked() {
367 MOZ_ASSERT(ProcessOwnsCompositor());
369 if (mCanvasDevice) {
370 return true;
373 if (!LoadD3D11()) {
374 return false;
377 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
378 if (!adapter) {
379 NS_WARNING("Failed to acquire a DXGI adapter for Canvas");
380 return false;
383 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
385 HRESULT hr;
386 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr,
387 mCanvasDevice)) {
388 gfxCriticalError() << "Crash during D3D11 device creation for Canvas";
389 return false;
392 if (StaticPrefs::
393 gfx_direct2d_target_independent_rasterization_disabled_AtStartup()) {
394 int creationFlags = 0x2; // disable target independent rasterization
395 const GUID D2D_INTERNAL_DEVICE_CREATION_OPTIONS = {
396 0xfb3a8e1a,
397 0x2e3c,
398 0x4de1,
399 {0x84, 0x42, 0x40, 0x43, 0xe0, 0xb0, 0x94, 0x95}};
400 mCanvasDevice->SetPrivateData(D2D_INTERNAL_DEVICE_CREATION_OPTIONS,
401 sizeof(creationFlags), &creationFlags);
404 if (FAILED(hr) || !mCanvasDevice) {
405 NS_WARNING("Failed to acquire a D3D11 device for Canvas");
406 return false;
409 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice)) {
410 mCanvasDevice = nullptr;
411 return false;
414 if (XRE_IsGPUProcess()) {
415 Factory::SetDirect3D11Device(mCanvasDevice);
418 return true;
421 void DeviceManagerDx::CreateDirectCompositionDevice() {
422 MutexAutoLock lock(mDeviceLock);
423 CreateDirectCompositionDeviceLocked();
426 void DeviceManagerDx::CreateDirectCompositionDeviceLocked() {
427 if (!gfxVars::UseWebRenderDCompWin()) {
428 return;
431 if (!mCompositorDevice) {
432 return;
435 if (!LoadDcomp()) {
436 return;
439 RefPtr<IDXGIDevice> dxgiDevice;
440 if (mCompositorDevice->QueryInterface(
441 IID_PPV_ARGS((IDXGIDevice**)getter_AddRefs(dxgiDevice))) != S_OK) {
442 return;
445 HRESULT hr;
446 RefPtr<IDCompositionDesktopDevice> desktopDevice;
447 MOZ_SEH_TRY {
448 hr = sDcompCreateDevice3Fn(
449 dxgiDevice.get(),
450 IID_PPV_ARGS(
451 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
452 if (!desktopDevice) {
453 hr = sDcompCreateDevice2Fn(
454 dxgiDevice.get(),
455 IID_PPV_ARGS(
456 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice)));
459 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; }
461 if (!SUCCEEDED(hr)) {
462 return;
465 RefPtr<IDCompositionDevice2> compositionDevice;
466 if (desktopDevice->QueryInterface(IID_PPV_ARGS(
467 (IDCompositionDevice2**)getter_AddRefs(compositionDevice))) != S_OK) {
468 return;
471 mDirectCompositionDevice = compositionDevice;
474 /* static */
475 HANDLE DeviceManagerDx::CreateDCompSurfaceHandle() {
476 if (!sDcompCreateSurfaceHandleFn) {
477 return 0;
480 HANDLE handle = 0;
481 HRESULT hr = sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS,
482 nullptr, &handle);
483 if (FAILED(hr)) {
484 return 0;
487 return handle;
490 void DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus) {
491 MOZ_ASSERT(!ProcessOwnsCompositor());
493 MutexAutoLock lock(mDeviceLock);
494 mDeviceStatus = Some(aDeviceStatus);
497 bool DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus* aOut) {
498 MutexAutoLock lock(mDeviceLock);
499 if (mDeviceStatus) {
500 *aOut = mDeviceStatus.value();
501 return true;
504 return false;
507 void DeviceManagerDx::CreateContentDevices() {
508 MutexAutoLock lock(mDeviceLock);
509 CreateContentDevicesLocked();
512 void DeviceManagerDx::CreateContentDevicesLocked() {
513 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING));
515 if (!LoadD3D11()) {
516 return;
519 // We should have been assigned a DeviceStatus from the parent process,
520 // GPU process, or the same process if using in-process compositing.
521 MOZ_ASSERT(mDeviceStatus);
523 if (CreateContentDevice() == FeatureStatus::CrashedInHandler) {
524 DisableD3D11AfterCrash();
528 already_AddRefed<IDXGIAdapter1> DeviceManagerDx::GetDXGIAdapter() {
529 MutexAutoLock lock(mDeviceLock);
530 return do_AddRef(GetDXGIAdapterLocked());
533 IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() {
534 if (mAdapter) {
535 return mAdapter;
538 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll"));
539 decltype(CreateDXGIFactory1)* createDXGIFactory1 =
540 (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgiModule,
541 "CreateDXGIFactory1");
542 if (!createDXGIFactory1) {
543 return nullptr;
545 static const auto fCreateDXGIFactory2 =
546 (decltype(CreateDXGIFactory2)*)GetProcAddress(dxgiModule,
547 "CreateDXGIFactory2");
549 // Try to use a DXGI 1.1 adapter in order to share resources
550 // across processes.
551 RefPtr<IDXGIFactory1> factory1;
552 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) {
553 RefPtr<IDXGIFactory2> factory2;
554 if (fCreateDXGIFactory2) {
555 auto hr = fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG,
556 __uuidof(IDXGIFactory2),
557 getter_AddRefs(factory2));
558 MOZ_ALWAYS_TRUE(!FAILED(hr));
559 } else {
560 NS_WARNING(
561 "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2.");
563 factory1 = factory2;
565 if (!factory1) {
566 HRESULT hr =
567 createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(factory1));
568 if (FAILED(hr) || !factory1) {
569 // This seems to happen with some people running the iZ3D driver.
570 // They won't get acceleration.
571 return nullptr;
575 if (!mDeviceStatus) {
576 // If we haven't created a device yet, and have no existing device status,
577 // then this must be the compositor device. Pick the first adapter we can.
578 if (FAILED(factory1->EnumAdapters1(0, getter_AddRefs(mAdapter)))) {
579 return nullptr;
581 } else {
582 // In the UI and GPU process, we clear mDeviceStatus on device reset, so we
583 // should never reach here. Furthermore, the UI process does not create
584 // devices when using a GPU process.
586 // So, this should only ever get called on the content process or RDD
587 // process
588 MOZ_ASSERT(XRE_IsContentProcess() || XRE_IsRDDProcess());
590 // In the child process, we search for the adapter that matches the parent
591 // process. The first adapter can be mismatched on dual-GPU systems.
592 for (UINT index = 0;; index++) {
593 RefPtr<IDXGIAdapter1> adapter;
594 if (FAILED(factory1->EnumAdapters1(index, getter_AddRefs(adapter)))) {
595 break;
598 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
600 DXGI_ADAPTER_DESC desc;
601 if (SUCCEEDED(adapter->GetDesc(&desc)) &&
602 desc.AdapterLuid.HighPart == preferred.AdapterLuid.HighPart &&
603 desc.AdapterLuid.LowPart == preferred.AdapterLuid.LowPart &&
604 desc.VendorId == preferred.VendorId &&
605 desc.DeviceId == preferred.DeviceId) {
606 mAdapter = adapter.forget();
607 break;
612 if (!mAdapter) {
613 return nullptr;
616 // We leak this module everywhere, we might as well do so here as well.
617 dxgiModule.disown();
618 return mAdapter;
621 bool DeviceManagerDx::CreateCompositorDeviceHelper(
622 FeatureState& aD3d11, IDXGIAdapter1* aAdapter, bool aAttemptVideoSupport,
623 RefPtr<ID3D11Device>& aOutDevice) {
624 // Check if a failure was injected for testing.
625 if (StaticPrefs::gfx_testing_device_fail()) {
626 aD3d11.SetFailed(FeatureStatus::Failed,
627 "Direct3D11 device failure simulated by preference",
628 "FEATURE_FAILURE_D3D11_SIM"_ns);
629 return false;
632 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
634 DXGI_ADAPTER_DESC desc;
635 aAdapter->GetDesc(&desc);
636 if (desc.VendorId != 0x1414) {
637 // 0x1414 is Microsoft (e.g. WARP)
638 // When not using WARP, use
639 // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS to prevent
640 // bug 1092260. IE 11 also uses this flag.
641 flags |= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
644 if (aAttemptVideoSupport) {
645 flags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
648 HRESULT hr;
649 RefPtr<ID3D11Device> device;
650 if (!CreateDevice(aAdapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
651 if (!aAttemptVideoSupport) {
652 gfxCriticalError() << "Crash during D3D11 device creation";
653 aD3d11.SetFailed(FeatureStatus::CrashedInHandler,
654 "Crashed trying to acquire a D3D11 device",
655 "FEATURE_FAILURE_D3D11_DEVICE1"_ns);
657 return false;
660 if (FAILED(hr) || !device) {
661 if (!aAttemptVideoSupport) {
662 aD3d11.SetFailed(FeatureStatus::Failed,
663 "Failed to acquire a D3D11 device",
664 "FEATURE_FAILURE_D3D11_DEVICE2"_ns);
666 return false;
668 if (!D3D11Checks::DoesDeviceWork()) {
669 if (!aAttemptVideoSupport) {
670 aD3d11.SetFailed(FeatureStatus::Broken,
671 "Direct3D11 device was determined to be broken",
672 "FEATURE_FAILURE_D3D11_BROKEN"_ns);
674 return false;
677 aOutDevice = device;
678 return true;
681 // Note that it's enough for us to just use a counter for a unique ID,
682 // even though the counter isn't synchronized between processes. If we
683 // start in the GPU process and wind up in the parent process, the
684 // whole graphics stack is blown away anyway. But just in case, we
685 // make gpu process IDs negative and parent process IDs positive.
686 static inline int32_t GetNextDeviceCounter() {
687 static int32_t sDeviceCounter = 0;
688 return XRE_IsGPUProcess() ? --sDeviceCounter : ++sDeviceCounter;
691 void DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11) {
692 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
693 CreateWARPCompositorDevice();
694 return;
697 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
698 if (!adapter) {
699 d3d11.SetFailed(FeatureStatus::Unavailable,
700 "Failed to acquire a DXGI adapter",
701 "FEATURE_FAILURE_D3D11_DXGI"_ns);
702 return;
705 if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter)) {
706 d3d11.SetFailed(FeatureStatus::Unavailable,
707 "DXGI does not support out-of-process presentation",
708 "FEATURE_FAILURE_D3D11_REMOTE_PRESENT"_ns);
709 return;
712 RefPtr<ID3D11Device> device;
713 if (!CreateCompositorDeviceHelper(d3d11, adapter, true, device)) {
714 // Try again without video support and record that it failed.
715 mCompositorDeviceSupportsVideo = false;
716 if (!CreateCompositorDeviceHelper(d3d11, adapter, false, device)) {
717 return;
719 } else {
720 mCompositorDeviceSupportsVideo = true;
723 // Only test this when not using WARP since it can fail and cause
724 // GetDeviceRemovedReason to return weird values.
725 bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
727 DXGI_ADAPTER_DESC desc;
728 PodZero(&desc);
729 adapter->GetDesc(&desc);
731 if (!textureSharingWorks) {
732 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken,
733 "Texture sharing doesn't work",
734 "FEATURE_FAILURE_HW_ANGLE_NEEDS_TEXTURE_SHARING"_ns);
736 if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device)) {
737 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken,
738 "RenderTargetViews need recreating",
739 "FEATURE_FAILURE_HW_ANGLE_NEEDS_RTV_RECREATION"_ns);
741 if (XRE_IsParentProcess()) {
742 // It seems like this may only happen when we're using the NVIDIA gpu
743 D3D11Checks::WarnOnAdapterMismatch(device);
746 uint32_t featureLevel = device->GetFeatureLevel();
747 auto formatOptions = D3D11Checks::FormatOptions(device);
748 mCompositorDevice = device;
750 int32_t sequenceNumber = GetNextDeviceCounter();
751 mDeviceStatus = Some(D3D11DeviceStatus(
752 false, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
753 sequenceNumber, formatOptions));
754 mCompositorDevice->SetExceptionMode(0);
757 bool DeviceManagerDx::CreateDevice(IDXGIAdapter* aAdapter,
758 D3D_DRIVER_TYPE aDriverType, UINT aFlags,
759 HRESULT& aResOut,
760 RefPtr<ID3D11Device>& aOutDevice) {
761 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup() ||
762 StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
763 aFlags |= D3D11_CREATE_DEVICE_DEBUG;
766 MOZ_SEH_TRY {
767 aResOut = sD3D11CreateDeviceFn(
768 aAdapter, aDriverType, nullptr, aFlags, mFeatureLevels.Elements(),
769 mFeatureLevels.Length(), D3D11_SDK_VERSION, getter_AddRefs(aOutDevice),
770 nullptr, nullptr);
772 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return false; }
774 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) {
775 do {
776 if (!aOutDevice) break;
778 RefPtr<ID3D11Debug> debug;
779 if (!SUCCEEDED(aOutDevice->QueryInterface(__uuidof(ID3D11Debug),
780 getter_AddRefs(debug))))
781 break;
783 RefPtr<ID3D11InfoQueue> infoQueue;
784 if (!SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue),
785 getter_AddRefs(infoQueue))))
786 break;
788 D3D11_INFO_QUEUE_FILTER filter;
789 PodZero(&filter);
791 // Disable warnings caused by Advanced Layers that are known and not
792 // problematic.
793 D3D11_MESSAGE_ID blockIDs[] = {
794 D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL};
795 filter.DenyList.NumIDs = MOZ_ARRAY_LENGTH(blockIDs);
796 filter.DenyList.pIDList = blockIDs;
797 infoQueue->PushStorageFilter(&filter);
799 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true);
800 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true);
801 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true);
802 } while (false);
805 return true;
808 void DeviceManagerDx::CreateWARPCompositorDevice() {
809 ScopedGfxFeatureReporter reporterWARP(
810 "D3D11-WARP", StaticPrefs::layers_d3d11_force_warp_AtStartup());
811 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
813 HRESULT hr;
814 RefPtr<ID3D11Device> device;
816 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS
817 // to prevent bug 1092260. IE 11 also uses this flag.
818 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
819 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, flags, hr, device)) {
820 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!";
821 d3d11.SetFailed(FeatureStatus::CrashedInHandler,
822 "Crashed creating a D3D11 WARP device",
823 "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns);
826 if (FAILED(hr) || !device) {
827 // This should always succeed... in theory.
828 gfxCriticalError() << "Failed to initialize WARP D3D11 device! "
829 << hexa(hr);
830 d3d11.SetFailed(FeatureStatus::Failed,
831 "Failed to create a D3D11 WARP device",
832 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns);
833 return;
836 // Only test for texture sharing on Windows 8 since it puts the device into
837 // an unusable state if used on Windows 7
838 bool textureSharingWorks = false;
839 if (IsWin8OrLater()) {
840 textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device);
843 DXGI_ADAPTER_DESC desc;
844 D3D11Checks::GetDxgiDesc(device, &desc);
846 int featureLevel = device->GetFeatureLevel();
848 auto formatOptions = D3D11Checks::FormatOptions(device);
849 mCompositorDevice = device;
851 int32_t sequenceNumber = GetNextDeviceCounter();
852 mDeviceStatus = Some(D3D11DeviceStatus(
853 true, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc),
854 sequenceNumber, formatOptions));
855 mCompositorDevice->SetExceptionMode(0);
857 reporterWARP.SetSuccessful();
860 FeatureStatus DeviceManagerDx::CreateContentDevice() {
861 RefPtr<IDXGIAdapter1> adapter;
862 if (!mDeviceStatus->isWARP()) {
863 adapter = GetDXGIAdapterLocked();
864 if (!adapter) {
865 gfxCriticalNote << "Could not get a DXGI adapter";
866 return FeatureStatus::Unavailable;
870 HRESULT hr;
871 RefPtr<ID3D11Device> device;
873 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
874 D3D_DRIVER_TYPE type =
875 mDeviceStatus->isWARP() ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN;
876 if (!CreateDevice(adapter, type, flags, hr, device)) {
877 gfxCriticalNote
878 << "Recovered from crash while creating a D3D11 content device";
879 gfxWindowsPlatform::RecordContentDeviceFailure(
880 TelemetryDeviceCode::Content);
881 return FeatureStatus::CrashedInHandler;
884 if (FAILED(hr) || !device) {
885 gfxCriticalNote << "Failed to create a D3D11 content device: " << hexa(hr);
886 gfxWindowsPlatform::RecordContentDeviceFailure(
887 TelemetryDeviceCode::Content);
888 return FeatureStatus::Failed;
891 // InitializeD2D() will abort early if the compositor device did not support
892 // texture sharing. If we're in the content process, we can't rely on the
893 // parent device alone: some systems have dual GPUs that are capable of
894 // binding the parent and child processes to different GPUs. As a safety net,
895 // we re-check texture sharing against the newly created D3D11 content device.
896 // If it fails, we won't use Direct2D.
897 if (XRE_IsContentProcess()) {
898 if (!D3D11Checks::DoesTextureSharingWork(device)) {
899 return FeatureStatus::Failed;
902 DebugOnly<bool> ok = ContentAdapterIsParentAdapter(device);
903 MOZ_ASSERT(ok);
906 mContentDevice = device;
907 mContentDevice->SetExceptionMode(0);
909 RefPtr<ID3D10Multithread> multi;
910 hr = mContentDevice->QueryInterface(__uuidof(ID3D10Multithread),
911 getter_AddRefs(multi));
912 if (SUCCEEDED(hr) && multi) {
913 multi->SetMultithreadProtected(TRUE);
915 return FeatureStatus::Available;
918 RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice(
919 bool aHardwareWebRender) {
920 MutexAutoLock lock(mDeviceLock);
922 if (!mDeviceStatus) {
923 return nullptr;
926 bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002;
927 bool reuseDevice = false;
928 if (gfxVars::ReuseDecoderDevice()) {
929 reuseDevice = true;
930 } else if (isAMD) {
931 reuseDevice = true;
932 gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD";
935 if (reuseDevice) {
936 // Use mCompositorDevice for decoder device only for hardware WebRender.
937 if (aHardwareWebRender && mCompositorDevice &&
938 mCompositorDeviceSupportsVideo && !mDecoderDevice) {
939 mDecoderDevice = mCompositorDevice;
941 RefPtr<ID3D10Multithread> multi;
942 mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread),
943 getter_AddRefs(multi));
944 if (multi) {
945 multi->SetMultithreadProtected(TRUE);
949 if (mDecoderDevice) {
950 RefPtr<ID3D11Device> dev = mDecoderDevice;
951 return dev.forget();
955 if (!sD3D11CreateDeviceFn) {
956 // We should just be on Windows Vista or XP in this case.
957 return nullptr;
960 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked();
961 if (!adapter) {
962 return nullptr;
965 HRESULT hr;
966 RefPtr<ID3D11Device> device;
968 UINT flags = D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS |
969 D3D11_CREATE_DEVICE_VIDEO_SUPPORT;
970 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) {
971 return nullptr;
973 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
974 return nullptr;
977 RefPtr<ID3D10Multithread> multi;
978 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
979 if (multi) {
980 multi->SetMultithreadProtected(TRUE);
982 if (reuseDevice) {
983 mDecoderDevice = device;
985 return device;
988 // ID3D11DeviceChild, IDXGIObject and ID3D11Device implement SetPrivateData with
989 // the exact same parameters.
990 template <typename T>
991 static HRESULT SetDebugName(T* d3d11Object, const char* debugString) {
992 return d3d11Object->SetPrivateData(WKPDID_D3DDebugObjectName,
993 strlen(debugString), debugString);
996 RefPtr<ID3D11Device> DeviceManagerDx::CreateMediaEngineDevice() {
997 MutexAutoLock lock(mDeviceLock);
998 if (!LoadD3D11()) {
999 return nullptr;
1002 HRESULT hr;
1003 RefPtr<ID3D11Device> device;
1004 UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT |
1005 D3D11_CREATE_DEVICE_BGRA_SUPPORT |
1006 D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS;
1007 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, flags, hr, device)) {
1008 return nullptr;
1010 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) {
1011 return nullptr;
1013 Unused << SetDebugName(device.get(), "MFMediaEngineDevice");
1015 RefPtr<ID3D10Multithread> multi;
1016 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi));
1017 if (multi) {
1018 multi->SetMultithreadProtected(TRUE);
1020 return device;
1023 void DeviceManagerDx::ResetDevices() {
1024 MutexAutoLock lock(mDeviceLock);
1025 ResetDevicesLocked();
1028 void DeviceManagerDx::ResetDevicesLocked() {
1029 mAdapter = nullptr;
1030 mCompositorAttachments = nullptr;
1031 mCompositorDevice = nullptr;
1032 mContentDevice = nullptr;
1033 mCanvasDevice = nullptr;
1034 mImageDevice = nullptr;
1035 mVRDevice = nullptr;
1036 mDecoderDevice = nullptr;
1037 mDirectCompositionDevice = nullptr;
1038 mDeviceStatus = Nothing();
1039 mDeviceResetReason = Nothing();
1040 Factory::SetDirect3D11Device(nullptr);
1043 bool DeviceManagerDx::MaybeResetAndReacquireDevices() {
1044 MutexAutoLock lock(mDeviceLock);
1046 DeviceResetReason resetReason;
1047 if (!HasDeviceResetLocked(&resetReason)) {
1048 return false;
1051 GPUProcessManager::RecordDeviceReset(resetReason);
1053 bool createCompositorDevice = !!mCompositorDevice;
1054 bool createContentDevice = !!mContentDevice;
1055 bool createCanvasDevice = !!mCanvasDevice;
1056 bool createDirectCompositionDevice = !!mDirectCompositionDevice;
1058 ResetDevicesLocked();
1060 if (createCompositorDevice && !CreateCompositorDevicesLocked()) {
1061 // Just stop, don't try anything more
1062 return true;
1064 if (createContentDevice) {
1065 CreateContentDevicesLocked();
1067 if (createCanvasDevice) {
1068 CreateCanvasDeviceLocked();
1070 if (createDirectCompositionDevice) {
1071 CreateDirectCompositionDeviceLocked();
1074 return true;
1077 bool DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device* device) {
1078 DXGI_ADAPTER_DESC desc;
1079 if (!D3D11Checks::GetDxgiDesc(device, &desc)) {
1080 gfxCriticalNote << "Could not query device DXGI adapter info";
1081 return false;
1084 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter();
1086 if (desc.VendorId != preferred.VendorId ||
1087 desc.DeviceId != preferred.DeviceId ||
1088 desc.SubSysId != preferred.SubSysId ||
1089 desc.AdapterLuid.HighPart != preferred.AdapterLuid.HighPart ||
1090 desc.AdapterLuid.LowPart != preferred.AdapterLuid.LowPart) {
1091 gfxCriticalNote << "VendorIDMismatch P " << hexa(preferred.VendorId) << " "
1092 << hexa(desc.VendorId);
1093 return false;
1096 return true;
1099 static DeviceResetReason HResultToResetReason(HRESULT hr) {
1100 switch (hr) {
1101 case DXGI_ERROR_DEVICE_HUNG:
1102 return DeviceResetReason::HUNG;
1103 case DXGI_ERROR_DEVICE_REMOVED:
1104 return DeviceResetReason::REMOVED;
1105 case DXGI_ERROR_DEVICE_RESET:
1106 return DeviceResetReason::RESET;
1107 case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
1108 return DeviceResetReason::DRIVER_ERROR;
1109 case DXGI_ERROR_INVALID_CALL:
1110 return DeviceResetReason::INVALID_CALL;
1111 case E_OUTOFMEMORY:
1112 return DeviceResetReason::OUT_OF_MEMORY;
1113 default:
1114 MOZ_ASSERT(false);
1116 return DeviceResetReason::OTHER;
1119 bool DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason) {
1120 MutexAutoLock lock(mDeviceLock);
1121 return HasDeviceResetLocked(aOutReason);
1124 bool DeviceManagerDx::HasDeviceResetLocked(DeviceResetReason* aOutReason) {
1125 if (mDeviceResetReason) {
1126 if (aOutReason) {
1127 *aOutReason = mDeviceResetReason.value();
1129 return true;
1132 DeviceResetReason reason;
1133 if (GetAnyDeviceRemovedReason(&reason)) {
1134 mDeviceResetReason = Some(reason);
1135 if (aOutReason) {
1136 *aOutReason = reason;
1138 return true;
1141 return false;
1144 static inline bool DidDeviceReset(const RefPtr<ID3D11Device>& aDevice,
1145 DeviceResetReason* aOutReason) {
1146 if (!aDevice) {
1147 return false;
1149 HRESULT hr = aDevice->GetDeviceRemovedReason();
1150 if (hr == S_OK) {
1151 return false;
1154 *aOutReason = HResultToResetReason(hr);
1155 return true;
1158 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) {
1159 if (DidDeviceReset(mCompositorDevice, aOutReason) ||
1160 DidDeviceReset(mContentDevice, aOutReason) ||
1161 DidDeviceReset(mCanvasDevice, aOutReason)) {
1162 return true;
1165 if (XRE_IsParentProcess() && NS_IsMainThread() &&
1166 StaticPrefs::gfx_testing_device_reset()) {
1167 Preferences::SetInt("gfx.testing.device-reset", 0);
1168 *aOutReason = DeviceResetReason::FORCED_RESET;
1169 return true;
1172 return false;
1175 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason) {
1176 Telemetry::Accumulate(Telemetry::FORCED_DEVICE_RESET_REASON,
1177 uint32_t(aReason));
1179 MutexAutoLock lock(mDeviceLock);
1180 if (!mDeviceResetReason) {
1181 mDeviceResetReason = Some(DeviceResetReason::FORCED_RESET);
1186 void DeviceManagerDx::DisableD3D11AfterCrash() {
1187 gfxConfig::Disable(Feature::D3D11_COMPOSITING,
1188 FeatureStatus::CrashedInHandler,
1189 "Crashed while acquiring a Direct3D11 device",
1190 "FEATURE_FAILURE_D3D11_CRASH"_ns);
1191 ResetDevices();
1194 RefPtr<ID3D11Device> DeviceManagerDx::GetCompositorDevice() {
1195 MutexAutoLock lock(mDeviceLock);
1196 return mCompositorDevice;
1199 RefPtr<ID3D11Device> DeviceManagerDx::GetContentDevice() {
1200 MOZ_ASSERT(XRE_IsGPUProcess() ||
1201 gfxPlatform::GetPlatform()->DevicesInitialized());
1203 MutexAutoLock lock(mDeviceLock);
1204 return mContentDevice;
1207 RefPtr<ID3D11Device> DeviceManagerDx::GetImageDevice() {
1208 MutexAutoLock lock(mDeviceLock);
1209 if (mImageDevice) {
1210 return mImageDevice;
1213 RefPtr<ID3D11Device> device = mContentDevice;
1214 if (!device) {
1215 device = mCompositorDevice;
1218 if (!device) {
1219 return nullptr;
1222 RefPtr<ID3D10Multithread> multi;
1223 HRESULT hr =
1224 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi));
1225 if (FAILED(hr) || !multi) {
1226 gfxWarning() << "Multithread safety interface not supported. " << hr;
1227 return nullptr;
1229 multi->SetMultithreadProtected(TRUE);
1231 mImageDevice = device;
1233 return mImageDevice;
1236 RefPtr<ID3D11Device> DeviceManagerDx::GetVRDevice() {
1237 MutexAutoLock lock(mDeviceLock);
1238 if (!mVRDevice) {
1239 CreateVRDevice();
1241 return mVRDevice;
1244 RefPtr<ID3D11Device> DeviceManagerDx::GetCanvasDevice() {
1245 MutexAutoLock lock(mDeviceLock);
1246 return mCanvasDevice;
1249 RefPtr<IDCompositionDevice2> DeviceManagerDx::GetDirectCompositionDevice() {
1250 MutexAutoLock lock(mDeviceLock);
1251 return mDirectCompositionDevice;
1254 unsigned DeviceManagerDx::GetCompositorFeatureLevel() const {
1255 MutexAutoLock lock(mDeviceLock);
1256 if (!mDeviceStatus) {
1257 return 0;
1259 return mDeviceStatus->featureLevel();
1262 bool DeviceManagerDx::TextureSharingWorks() {
1263 MutexAutoLock lock(mDeviceLock);
1264 if (!mDeviceStatus) {
1265 return false;
1267 return mDeviceStatus->textureSharingWorks();
1270 bool DeviceManagerDx::CanInitializeKeyedMutexTextures() {
1271 MutexAutoLock lock(mDeviceLock);
1272 return mDeviceStatus && StaticPrefs::gfx_direct3d11_allow_keyed_mutex() &&
1273 gfxVars::AllowD3D11KeyedMutex();
1276 bool DeviceManagerDx::HasCrashyInitData() {
1277 MutexAutoLock lock(mDeviceLock);
1278 if (!mDeviceStatus) {
1279 return false;
1282 return (mDeviceStatus->adapter().VendorId == 0x8086 && !IsWin10OrLater());
1285 bool DeviceManagerDx::CheckRemotePresentSupport() {
1286 MOZ_ASSERT(XRE_IsParentProcess());
1288 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapter();
1289 if (!adapter) {
1290 return false;
1292 if (!D3D11Checks::DoesRemotePresentWork(adapter)) {
1293 return false;
1295 return true;
1298 bool DeviceManagerDx::IsWARP() {
1299 MutexAutoLock lock(mDeviceLock);
1300 if (!mDeviceStatus) {
1301 return false;
1303 return mDeviceStatus->isWARP();
1306 bool DeviceManagerDx::CanUseNV12() {
1307 MutexAutoLock lock(mDeviceLock);
1308 if (!mDeviceStatus) {
1309 return false;
1311 return mDeviceStatus->formatOptions().contains(
1312 D3D11Checks::VideoFormatOption::NV12);
1315 bool DeviceManagerDx::CanUseP010() {
1316 MutexAutoLock lock(mDeviceLock);
1317 if (!mDeviceStatus) {
1318 return false;
1320 return mDeviceStatus->formatOptions().contains(
1321 D3D11Checks::VideoFormatOption::P010);
1324 bool DeviceManagerDx::CanUseP016() {
1325 MutexAutoLock lock(mDeviceLock);
1326 if (!mDeviceStatus) {
1327 return false;
1329 return mDeviceStatus->formatOptions().contains(
1330 D3D11Checks::VideoFormatOption::P016);
1333 bool DeviceManagerDx::CanUseDComp() {
1334 MutexAutoLock lock(mDeviceLock);
1335 return !!mDirectCompositionDevice;
1338 void DeviceManagerDx::InitializeDirectDraw() {
1339 MOZ_ASSERT(layers::CompositorThreadHolder::IsInCompositorThread());
1341 if (mDirectDraw) {
1342 // Already initialized.
1343 return;
1346 FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
1347 if (!ddraw.IsEnabled()) {
1348 return;
1351 // Check if DirectDraw is available on this system.
1352 mDirectDrawDLL.own(LoadLibrarySystem32(L"ddraw.dll"));
1353 if (!mDirectDrawDLL) {
1354 ddraw.SetFailed(FeatureStatus::Unavailable,
1355 "DirectDraw not available on this computer",
1356 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1357 return;
1360 sDirectDrawCreateExFn = (decltype(DirectDrawCreateEx)*)GetProcAddress(
1361 mDirectDrawDLL, "DirectDrawCreateEx");
1362 if (!sDirectDrawCreateExFn) {
1363 ddraw.SetFailed(FeatureStatus::Unavailable,
1364 "DirectDraw not available on this computer",
1365 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1366 return;
1369 HRESULT hr;
1370 MOZ_SEH_TRY {
1371 hr = sDirectDrawCreateExFn(nullptr, getter_AddRefs(mDirectDraw),
1372 IID_IDirectDraw7, nullptr);
1374 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1375 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1376 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1377 gfxCriticalNote << "DoesCreatingDirectDrawFailed";
1378 return;
1380 if (FAILED(hr)) {
1381 ddraw.SetFailed(FeatureStatus::Failed, "Failed to create DirectDraw",
1382 "FEATURE_FAILURE_DDRAW_LIB"_ns);
1383 gfxCriticalNote << "DoesCreatingDirectDrawFailed " << hexa(hr);
1384 return;
1388 IDirectDraw7* DeviceManagerDx::GetDirectDraw() { return mDirectDraw; }
1390 void DeviceManagerDx::GetCompositorDevices(
1391 RefPtr<ID3D11Device>* aOutDevice,
1392 RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments) {
1393 RefPtr<ID3D11Device> device;
1395 MutexAutoLock lock(mDeviceLock);
1396 if (!mCompositorDevice) {
1397 return;
1399 if (mCompositorAttachments) {
1400 *aOutDevice = mCompositorDevice;
1401 *aOutAttachments = mCompositorAttachments;
1402 return;
1405 // Otherwise, we'll try to create attachments outside the lock.
1406 device = mCompositorDevice;
1409 // We save the attachments object even if it fails to initialize, so the
1410 // compositor can grab the failure ID.
1411 RefPtr<layers::DeviceAttachmentsD3D11> attachments =
1412 layers::DeviceAttachmentsD3D11::Create(device);
1414 MutexAutoLock lock(mDeviceLock);
1415 if (device != mCompositorDevice) {
1416 return;
1418 mCompositorAttachments = attachments;
1421 *aOutDevice = device;
1422 *aOutAttachments = attachments;
1425 /* static */
1426 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() {
1427 if (!CompositorThread()) {
1428 return;
1431 RefPtr<Runnable> task = NS_NewRunnableFunction(
1432 "DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void {
1433 if (DeviceManagerDx* dm = DeviceManagerDx::Get()) {
1434 RefPtr<ID3D11Device> device;
1435 RefPtr<layers::DeviceAttachmentsD3D11> attachments;
1436 dm->GetCompositorDevices(&device, &attachments);
1439 CompositorThread()->Dispatch(task.forget());
1442 } // namespace gfx
1443 } // namespace mozilla