DeviceManagerDx.cpp (44299B)
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/. */ 5 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/glean/GfxMetrics.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" 26 27 // - 28 29 #include <d3d11.h> 30 #include <dcomp.h> 31 #include <ddraw.h> 32 #include <dxgi.h> 33 34 namespace mozilla { 35 namespace gfx { 36 37 using namespace mozilla::widget; 38 using namespace mozilla::layers; 39 40 StaticAutoPtr<DeviceManagerDx> DeviceManagerDx::sInstance; 41 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; 46 47 // It should only be used within CreateDirectCompositionDevice. 48 decltype(DCompositionCreateDevice2)* sDcompCreateDevice2Fn = nullptr; 49 decltype(DCompositionCreateDevice3)* sDcompCreateDevice3Fn = nullptr; 50 51 // It should only be used within CreateDCompSurfaceHandle 52 decltype(DCompositionCreateSurfaceHandle)* sDcompCreateSurfaceHandleFn = 53 nullptr; 54 55 /* static */ 56 void DeviceManagerDx::Init() { sInstance = new DeviceManagerDx(); } 57 58 /* static */ 59 void DeviceManagerDx::Shutdown() { sInstance = nullptr; } 60 61 DeviceManagerDx::DeviceManagerDx() 62 : mDeviceLock("gfxWindowsPlatform.mDeviceLock"), 63 mCompositorDeviceSupportsVideo(false), 64 mSupportsDCompositionTexture(false) { 65 // Set up the D3D11 feature levels we can ask for. 66 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); 67 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); 68 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); 69 mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); 70 MOZ_COUNT_CTOR(DeviceManagerDx); 71 } 72 73 DeviceManagerDx::~DeviceManagerDx() { MOZ_COUNT_DTOR(DeviceManagerDx); } 74 75 bool DeviceManagerDx::LoadD3D11() { 76 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); 77 MOZ_ASSERT(d3d11.IsEnabled()); 78 79 if (sD3D11CreateDeviceFn) { 80 return true; 81 } 82 83 nsModuleHandle module(LoadLibrarySystem32(L"d3d11.dll")); 84 if (!module) { 85 d3d11.SetFailed(FeatureStatus::Unavailable, 86 "Direct3D11 not available on this computer", 87 "FEATURE_FAILURE_D3D11_LIB"_ns); 88 return false; 89 } 90 91 sD3D11CreateDeviceFn = 92 (decltype(D3D11CreateDevice)*)GetProcAddress(module, "D3D11CreateDevice"); 93 if (!sD3D11CreateDeviceFn) { 94 // We should just be on Windows Vista or XP in this case. 95 d3d11.SetFailed(FeatureStatus::Unavailable, 96 "Direct3D11 not available on this computer", 97 "FEATURE_FAILURE_D3D11_FUNCPTR"_ns); 98 return false; 99 } 100 101 mD3D11Module.steal(module); 102 return true; 103 } 104 105 bool DeviceManagerDx::LoadDcomp() { 106 MOZ_ASSERT(gfxConfig::GetFeature(Feature::D3D11_COMPOSITING).IsEnabled()); 107 MOZ_ASSERT(gfxVars::UseWebRenderANGLE()); 108 MOZ_ASSERT(gfxVars::UseWebRenderDCompWin()); 109 110 if (sDcompCreateDevice2Fn) { 111 return true; // Already loaded. 112 } 113 114 nsModuleHandle module(LoadLibrarySystem32(L"dcomp.dll")); 115 if (!module) { 116 return false; 117 } 118 119 sDcompCreateDevice2Fn = (decltype(DCompositionCreateDevice2)*)GetProcAddress( 120 module, "DCompositionCreateDevice2"); 121 sDcompCreateDevice3Fn = (decltype(DCompositionCreateDevice3)*)GetProcAddress( 122 module, "DCompositionCreateDevice3"); 123 if (!sDcompCreateDevice2Fn) { 124 return false; 125 } 126 127 // Load optional API for external compositing 128 sDcompCreateSurfaceHandleFn = 129 (decltype(DCompositionCreateSurfaceHandle)*)::GetProcAddress( 130 module, "DCompositionCreateSurfaceHandle"); 131 132 mDcompModule.steal(module); 133 return true; 134 } 135 136 void DeviceManagerDx::ReleaseD3D11() { 137 MOZ_ASSERT(!mCompositorDevice); 138 MOZ_ASSERT(!mContentDevice); 139 MOZ_ASSERT(!mVRDevice); 140 MOZ_ASSERT(!mDecoderDevice); 141 142 mD3D11Module.reset(); 143 sD3D11CreateDeviceFn = nullptr; 144 } 145 146 nsTArray<DXGI_OUTPUT_DESC1> DeviceManagerDx::EnumerateOutputs() { 147 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter(); 148 149 if (!adapter) { 150 NS_WARNING("Failed to acquire a DXGI adapter for enumerating outputs."); 151 return nsTArray<DXGI_OUTPUT_DESC1>(); 152 } 153 154 nsTArray<DXGI_OUTPUT_DESC1> outputs; 155 for (UINT i = 0;; ++i) { 156 RefPtr<IDXGIOutput> output = nullptr; 157 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) { 158 break; 159 } 160 161 RefPtr<IDXGIOutput6> output6 = nullptr; 162 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6), 163 getter_AddRefs(output6)))) { 164 break; 165 } 166 167 DXGI_OUTPUT_DESC1 desc; 168 if (FAILED(output6->GetDesc1(&desc))) { 169 break; 170 } 171 172 outputs.AppendElement(desc); 173 } 174 return outputs; 175 } 176 177 bool DeviceManagerDx::GetOutputFromMonitor(HMONITOR monitor, 178 RefPtr<IDXGIOutput>* aOutOutput) { 179 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter(); 180 181 if (!adapter) { 182 NS_WARNING("Failed to acquire a DXGI adapter for GetOutputFromMonitor."); 183 return false; 184 } 185 186 for (UINT i = 0;; ++i) { 187 RefPtr<IDXGIOutput> output = nullptr; 188 if (FAILED(adapter->EnumOutputs(i, getter_AddRefs(output)))) { 189 break; 190 } 191 192 DXGI_OUTPUT_DESC desc; 193 if (FAILED(output->GetDesc(&desc))) { 194 continue; 195 } 196 197 if (desc.Monitor == monitor) { 198 *aOutOutput = output; 199 return true; 200 } 201 } 202 return false; 203 } 204 205 void DeviceManagerDx::PostUpdateMonitorInfo() { 206 MOZ_ASSERT(XRE_IsGPUProcess()); 207 MOZ_ASSERT(NS_IsMainThread()); 208 209 MutexAutoLock lock(mDeviceLock); 210 // Reduce frequency of UpdateMonitorInfo() call. 211 if (mUpdateMonitorInfoRunnable) { 212 return; 213 } 214 215 auto* holder = CompositorThreadHolder::GetSingleton(); 216 if (!holder) { 217 return; 218 } 219 220 mUpdateMonitorInfoRunnable = NS_NewRunnableFunction( 221 "DeviceManagerDx::PostUpdateMonitorInfo::Runnable", []() -> void { 222 auto* dm = gfx::DeviceManagerDx::Get(); 223 if (dm) { 224 dm->UpdateMonitorInfo(); 225 } 226 }); 227 228 const uint32_t kDelayMS = 100; 229 RefPtr<Runnable> runnable = mUpdateMonitorInfoRunnable; 230 holder->GetCompositorThread()->DelayedDispatch(runnable.forget(), kDelayMS); 231 } 232 233 static bool ColorSpaceIsHDR(const DXGI_OUTPUT_DESC1& aDesc) { 234 // Set isHDR to true if the output has a BT2020 colorspace with EOTF2084 235 // gamma curve, this indicates the system is sending an HDR format to 236 // this monitor. The colorspace returned by DXGI is very vague - we only 237 // see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR and 238 // DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the 239 // monitor is using something like YCbCr444 according to Settings 240 // (System -> Display Settings -> Advanced Display). To get more specific 241 // info we would need to query the DISPLAYCONFIG values in WinGDI. 242 // 243 // Note that we don't check bit depth here, since as of Windows 11 22H2, 244 // HDR is supported with 8bpc for lower bandwidth, where DWM converts to 245 // dithered RGB8 rather than RGB10, which doesn't really matter here. 246 // 247 // Since RefreshScreens(), the caller of this function, is triggered 248 // by WM_DISPLAYCHANGE, this will pick up changes to the monitors in 249 // all the important cases (resolution/color changes by the user). 250 // 251 // Further reading: 252 // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range 253 // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level 254 bool isHDR = (aDesc.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020); 255 256 return isHDR; 257 } 258 259 void DeviceManagerDx::UpdateMonitorInfo() { 260 bool systemHdrEnabled = false; 261 std::set<HMONITOR> hdrMonitors; 262 263 for (const auto desc : EnumerateOutputs()) { 264 if (ColorSpaceIsHDR(desc)) { 265 systemHdrEnabled = true; 266 hdrMonitors.emplace(desc.Monitor); 267 } 268 } 269 270 { 271 MutexAutoLock lock(mDeviceLock); 272 mSystemHdrEnabled = Some(systemHdrEnabled); 273 mHdrMonitors.swap(hdrMonitors); 274 mUpdateMonitorInfoRunnable = nullptr; 275 } 276 } 277 278 bool DeviceManagerDx::SystemHDREnabled() { 279 { 280 MutexAutoLock lock(mDeviceLock); 281 if (mSystemHdrEnabled.isSome()) { 282 return mSystemHdrEnabled.ref(); 283 } 284 } 285 286 UpdateMonitorInfo(); 287 288 MutexAutoLock lock(mDeviceLock); 289 return mSystemHdrEnabled.ref(); 290 } 291 292 bool DeviceManagerDx::WindowHDREnabled(HWND aWindow) { 293 MOZ_ASSERT(aWindow); 294 295 HMONITOR monitor = ::MonitorFromWindow(aWindow, MONITOR_DEFAULTTONEAREST); 296 return MonitorHDREnabled(monitor); 297 } 298 299 bool DeviceManagerDx::MonitorHDREnabled(HMONITOR aMonitor) { 300 if (!aMonitor) { 301 return false; 302 } 303 304 bool needInit = false; 305 306 { 307 MutexAutoLock lock(mDeviceLock); 308 if (mSystemHdrEnabled.isNothing()) { 309 needInit = true; 310 } 311 } 312 313 if (needInit) { 314 UpdateMonitorInfo(); 315 } 316 317 MutexAutoLock lock(mDeviceLock); 318 MOZ_ASSERT(mSystemHdrEnabled.isSome()); 319 320 auto it = mHdrMonitors.find(aMonitor); 321 if (it == mHdrMonitors.end()) { 322 return false; 323 } 324 325 return true; 326 } 327 328 void DeviceManagerDx::CheckHardwareStretchingSupport(HwStretchingSupport& aRv) { 329 RefPtr<IDXGIAdapter> adapter = GetDXGIAdapter(); 330 331 if (!adapter) { 332 NS_WARNING( 333 "Failed to acquire a DXGI adapter for checking hardware stretching " 334 "support."); 335 ++aRv.mError; 336 return; 337 } 338 339 for (UINT i = 0;; ++i) { 340 RefPtr<IDXGIOutput> output = nullptr; 341 HRESULT result = adapter->EnumOutputs(i, getter_AddRefs(output)); 342 if (result == DXGI_ERROR_NOT_FOUND) { 343 // No more outputs to check. 344 break; 345 } 346 347 if (FAILED(result)) { 348 ++aRv.mError; 349 break; 350 } 351 352 RefPtr<IDXGIOutput6> output6 = nullptr; 353 if (FAILED(output->QueryInterface(__uuidof(IDXGIOutput6), 354 getter_AddRefs(output6)))) { 355 ++aRv.mError; 356 continue; 357 } 358 359 UINT flags = 0; 360 if (FAILED(output6->CheckHardwareCompositionSupport(&flags))) { 361 ++aRv.mError; 362 continue; 363 } 364 365 bool fullScreen = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_FULLSCREEN; 366 bool window = flags & DXGI_HARDWARE_COMPOSITION_SUPPORT_FLAG_WINDOWED; 367 if (fullScreen && window) { 368 ++aRv.mBoth; 369 } else if (fullScreen) { 370 ++aRv.mFullScreenOnly; 371 } else if (window) { 372 ++aRv.mWindowOnly; 373 } else { 374 ++aRv.mNone; 375 } 376 } 377 } 378 379 #ifdef DEBUG 380 static inline bool ProcessOwnsCompositor() { 381 return XRE_GetProcessType() == GeckoProcessType_GPU || 382 XRE_GetProcessType() == GeckoProcessType_VR || 383 (XRE_IsParentProcess() && !gfxConfig::IsEnabled(Feature::GPU_PROCESS)); 384 } 385 #endif 386 387 bool DeviceManagerDx::CreateCompositorDevices() { 388 MutexAutoLock lock(mDeviceLock); 389 return CreateCompositorDevicesLocked(); 390 } 391 392 bool DeviceManagerDx::CreateCompositorDevicesLocked() { 393 MOZ_ASSERT(ProcessOwnsCompositor()); 394 395 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); 396 MOZ_ASSERT(d3d11.IsEnabled()); 397 398 if (int32_t sleepSec = 399 StaticPrefs::gfx_direct3d11_sleep_on_create_device_AtStartup()) { 400 printf_stderr("Attach to PID: %lu\n", GetCurrentProcessId()); 401 Sleep(sleepSec * 1000); 402 } 403 404 if (!LoadD3D11()) { 405 return false; 406 } 407 408 CreateCompositorDevice(d3d11); 409 410 if (!d3d11.IsEnabled()) { 411 MOZ_ASSERT(!mCompositorDevice); 412 ReleaseD3D11(); 413 414 return false; 415 } 416 417 // We leak these everywhere and we need them our entire runtime anyway, let's 418 // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around 419 // as well for D2D1 and device resets. 420 mD3D11Module.disown(); 421 422 MOZ_ASSERT(mCompositorDevice); 423 if (!d3d11.IsEnabled()) { 424 return false; 425 } 426 427 // When WR is used, do not preload attachments for D3D11 Non-WR compositor. 428 // 429 // Fallback from WR to D3D11 Non-WR compositor without re-creating gpu process 430 // could happen when WR causes error. In this case, the attachments are loaded 431 // synchronously. 432 if (gfx::gfxVars::UseSoftwareWebRender()) { 433 PreloadAttachmentsOnCompositorThread(); 434 } 435 436 return true; 437 } 438 439 bool DeviceManagerDx::CreateVRDevice() { 440 MOZ_ASSERT(ProcessOwnsCompositor()); 441 442 if (mVRDevice) { 443 return true; 444 } 445 446 if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) { 447 NS_WARNING("Direct3D11 Compositing required for VR"); 448 return false; 449 } 450 451 if (!LoadD3D11()) { 452 return false; 453 } 454 455 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked(); 456 if (!adapter) { 457 NS_WARNING("Failed to acquire a DXGI adapter for VR"); 458 return false; 459 } 460 461 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 462 463 HRESULT hr; 464 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, mVRDevice)) { 465 gfxCriticalError() << "Crash during D3D11 device creation for VR"; 466 return false; 467 } 468 469 if (FAILED(hr) || !mVRDevice) { 470 NS_WARNING("Failed to acquire a D3D11 device for VR"); 471 return false; 472 } 473 474 return true; 475 } 476 477 bool DeviceManagerDx::CreateCanvasDevice() { 478 MutexAutoLock lock(mDeviceLock); 479 return CreateCanvasDeviceLocked(); 480 } 481 482 bool DeviceManagerDx::CreateCanvasDeviceLocked() { 483 MOZ_ASSERT(ProcessOwnsCompositor()); 484 485 if (mCanvasDevice) { 486 return true; 487 } 488 489 if (!LoadD3D11()) { 490 return false; 491 } 492 493 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked(); 494 if (!adapter) { 495 NS_WARNING("Failed to acquire a DXGI adapter for Canvas"); 496 return false; 497 } 498 499 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 500 501 HRESULT hr; 502 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, 503 mCanvasDevice)) { 504 gfxCriticalError() << "Crash during D3D11 device creation for Canvas"; 505 return false; 506 } 507 508 if (FAILED(hr) || !mCanvasDevice) { 509 NS_WARNING("Failed to acquire a D3D11 device for Canvas"); 510 return false; 511 } 512 513 if (!D3D11Checks::DoesTextureSharingWork(mCanvasDevice)) { 514 mCanvasDevice = nullptr; 515 return false; 516 } 517 518 if (XRE_IsGPUProcess()) { 519 Factory::SetDirect3D11Device(mCanvasDevice); 520 } 521 522 return true; 523 } 524 525 void DeviceManagerDx::CreateDirectCompositionDevice() { 526 MutexAutoLock lock(mDeviceLock); 527 CreateDirectCompositionDeviceLocked(); 528 } 529 530 void DeviceManagerDx::CreateDirectCompositionDeviceLocked() { 531 if (!gfxVars::UseWebRenderDCompWin()) { 532 return; 533 } 534 535 if (!mCompositorDevice) { 536 return; 537 } 538 539 if (!LoadDcomp()) { 540 return; 541 } 542 543 RefPtr<IDXGIDevice> dxgiDevice; 544 if (mCompositorDevice->QueryInterface( 545 IID_PPV_ARGS((IDXGIDevice**)getter_AddRefs(dxgiDevice))) != S_OK) { 546 return; 547 } 548 549 HRESULT hr; 550 RefPtr<IDCompositionDesktopDevice> desktopDevice; 551 MOZ_SEH_TRY { 552 hr = sDcompCreateDevice3Fn( 553 dxgiDevice.get(), 554 IID_PPV_ARGS( 555 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice))); 556 if (!desktopDevice) { 557 hr = sDcompCreateDevice2Fn( 558 dxgiDevice.get(), 559 IID_PPV_ARGS( 560 (IDCompositionDesktopDevice**)getter_AddRefs(desktopDevice))); 561 } 562 } 563 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return; } 564 565 if (!SUCCEEDED(hr)) { 566 return; 567 } 568 569 RefPtr<IDCompositionDevice2> compositionDevice; 570 if (desktopDevice->QueryInterface(IID_PPV_ARGS( 571 (IDCompositionDevice2**)getter_AddRefs(compositionDevice))) != S_OK) { 572 return; 573 } 574 575 // Check if DCompositionTexture is supported 576 RefPtr<ID3D11Device> device = mCompositorDevice; 577 const bool supported = [device, compositionDevice] { 578 HRESULT hr; 579 RefPtr<IDCompositionDevice4> dcomp4; 580 hr = compositionDevice->QueryInterface( 581 (IDCompositionDevice4**)getter_AddRefs(dcomp4)); 582 if (FAILED(hr)) { 583 return false; 584 } 585 586 BOOL supportCompositionTexture = FALSE; 587 hr = dcomp4->CheckCompositionTextureSupport(device, 588 &supportCompositionTexture); 589 if (FAILED(hr)) { 590 return false; 591 } 592 593 if (supportCompositionTexture == FALSE) { 594 return false; 595 } 596 597 return true; 598 }(); 599 600 mSupportsDCompositionTexture = supported; 601 mDirectCompositionDevice = compositionDevice; 602 } 603 604 /* static */ 605 HANDLE DeviceManagerDx::CreateDCompSurfaceHandle() { 606 if (!sDcompCreateSurfaceHandleFn) { 607 return 0; 608 } 609 610 HANDLE handle = 0; 611 HRESULT hr = sDcompCreateSurfaceHandleFn(COMPOSITIONOBJECT_ALL_ACCESS, 612 nullptr, &handle); 613 if (FAILED(hr)) { 614 return 0; 615 } 616 617 return handle; 618 } 619 620 void DeviceManagerDx::ImportDeviceInfo(const D3D11DeviceStatus& aDeviceStatus) { 621 MOZ_ASSERT(!ProcessOwnsCompositor()); 622 623 MutexAutoLock lock(mDeviceLock); 624 mDeviceStatus = Some(aDeviceStatus); 625 } 626 627 bool DeviceManagerDx::ExportDeviceInfo(D3D11DeviceStatus* aOut) { 628 MutexAutoLock lock(mDeviceLock); 629 if (mDeviceStatus) { 630 *aOut = mDeviceStatus.value(); 631 return true; 632 } 633 634 return false; 635 } 636 637 void DeviceManagerDx::CreateContentDevices() { 638 MutexAutoLock lock(mDeviceLock); 639 CreateContentDevicesLocked(); 640 } 641 642 void DeviceManagerDx::CreateContentDevicesLocked() { 643 MOZ_ASSERT(gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)); 644 645 if (!LoadD3D11()) { 646 return; 647 } 648 649 // We should have been assigned a DeviceStatus from the parent process, 650 // GPU process, or the same process if using in-process compositing. 651 MOZ_RELEASE_ASSERT(mDeviceStatus); 652 653 if (CreateContentDevice() == FeatureStatus::CrashedInHandler) { 654 DisableD3D11AfterCrash(); 655 } 656 } 657 658 already_AddRefed<IDXGIAdapter1> DeviceManagerDx::GetDXGIAdapter() { 659 MutexAutoLock lock(mDeviceLock); 660 return do_AddRef(GetDXGIAdapterLocked()); 661 } 662 663 IDXGIAdapter1* DeviceManagerDx::GetDXGIAdapterLocked() { 664 if (mAdapter && mFactory && mFactory->IsCurrent()) { 665 return mAdapter; 666 } 667 mAdapter = nullptr; 668 mFactory = nullptr; 669 670 nsModuleHandle dxgiModule(LoadLibrarySystem32(L"dxgi.dll")); 671 decltype(CreateDXGIFactory1)* createDXGIFactory1 = 672 (decltype(CreateDXGIFactory1)*)GetProcAddress(dxgiModule, 673 "CreateDXGIFactory1"); 674 if (!createDXGIFactory1) { 675 return nullptr; 676 } 677 static const auto fCreateDXGIFactory2 = 678 (decltype(CreateDXGIFactory2)*)GetProcAddress(dxgiModule, 679 "CreateDXGIFactory2"); 680 681 // Try to use a DXGI 1.1 adapter in order to share resources 682 // across processes. 683 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup()) { 684 if (fCreateDXGIFactory2) { 685 auto hr = fCreateDXGIFactory2(DXGI_CREATE_FACTORY_DEBUG, 686 __uuidof(IDXGIFactory2), 687 getter_AddRefs(mFactory)); 688 MOZ_ALWAYS_TRUE(!FAILED(hr)); 689 } else { 690 NS_WARNING( 691 "fCreateDXGIFactory2 not loaded, cannot create debug IDXGIFactory2."); 692 } 693 } 694 if (!mFactory) { 695 HRESULT hr = 696 createDXGIFactory1(__uuidof(IDXGIFactory1), getter_AddRefs(mFactory)); 697 if (FAILED(hr) || !mFactory) { 698 // This seems to happen with some people running the iZ3D driver. 699 // They won't get acceleration. 700 return nullptr; 701 } 702 } 703 704 if (mDeviceStatus) { 705 // Match the adapter to our mDeviceStatus, if possible. 706 for (UINT index = 0;; index++) { 707 RefPtr<IDXGIAdapter1> adapter; 708 if (FAILED(mFactory->EnumAdapters1(index, getter_AddRefs(adapter)))) { 709 break; 710 } 711 712 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter(); 713 714 DXGI_ADAPTER_DESC desc; 715 if (SUCCEEDED(adapter->GetDesc(&desc)) && 716 desc.AdapterLuid.HighPart == preferred.AdapterLuid.HighPart && 717 desc.AdapterLuid.LowPart == preferred.AdapterLuid.LowPart && 718 desc.VendorId == preferred.VendorId && 719 desc.DeviceId == preferred.DeviceId) { 720 mAdapter = adapter.forget(); 721 break; 722 } 723 } 724 } 725 726 if (!mAdapter) { 727 mDeviceStatus.reset(); 728 // Pick the first adapter available. 729 mFactory->EnumAdapters1(0, getter_AddRefs(mAdapter)); 730 } 731 732 // We leak this module everywhere, we might as well do so here as well. 733 dxgiModule.disown(); 734 return mAdapter; 735 } 736 737 bool DeviceManagerDx::CreateCompositorDeviceHelper( 738 FeatureState& aD3d11, IDXGIAdapter1* aAdapter, bool aAttemptVideoSupport, 739 RefPtr<ID3D11Device>& aOutDevice) { 740 // Check if a failure was injected for testing. 741 if (StaticPrefs::gfx_testing_device_fail()) { 742 aD3d11.SetFailed(FeatureStatus::Failed, 743 "Direct3D11 device failure simulated by preference", 744 "FEATURE_FAILURE_D3D11_SIM"_ns); 745 return false; 746 } 747 748 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 749 750 DXGI_ADAPTER_DESC desc; 751 aAdapter->GetDesc(&desc); 752 if (desc.VendorId != 0x1414) { 753 // 0x1414 is Microsoft (e.g. WARP) 754 // When not using WARP, use 755 // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS to prevent 756 // bug 1092260. IE 11 also uses this flag. 757 flags |= D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS; 758 } 759 760 if (aAttemptVideoSupport) { 761 flags |= D3D11_CREATE_DEVICE_VIDEO_SUPPORT; 762 } 763 764 HRESULT hr; 765 RefPtr<ID3D11Device> device; 766 if (!CreateDevice(aAdapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) { 767 if (!aAttemptVideoSupport) { 768 gfxCriticalError() << "Crash during D3D11 device creation"; 769 aD3d11.SetFailed(FeatureStatus::CrashedInHandler, 770 "Crashed trying to acquire a D3D11 device", 771 "FEATURE_FAILURE_D3D11_DEVICE1"_ns); 772 } 773 return false; 774 } 775 776 if (FAILED(hr) || !device) { 777 if (!aAttemptVideoSupport) { 778 aD3d11.SetFailed(FeatureStatus::Failed, 779 "Failed to acquire a D3D11 device", 780 "FEATURE_FAILURE_D3D11_DEVICE2"_ns); 781 } 782 return false; 783 } 784 if (!D3D11Checks::DoesDeviceWork()) { 785 if (!aAttemptVideoSupport) { 786 aD3d11.SetFailed(FeatureStatus::Broken, 787 "Direct3D11 device was determined to be broken", 788 "FEATURE_FAILURE_D3D11_BROKEN"_ns); 789 } 790 return false; 791 } 792 793 aOutDevice = device; 794 return true; 795 } 796 797 // Note that it's enough for us to just use a counter for a unique ID, 798 // even though the counter isn't synchronized between processes. If we 799 // start in the GPU process and wind up in the parent process, the 800 // whole graphics stack is blown away anyway. But just in case, we 801 // make gpu process IDs negative and parent process IDs positive. 802 static inline int32_t GetNextDeviceCounter() { 803 static int32_t sDeviceCounter = 0; 804 return XRE_IsGPUProcess() ? --sDeviceCounter : ++sDeviceCounter; 805 } 806 807 void DeviceManagerDx::CreateCompositorDevice(FeatureState& d3d11) { 808 if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) { 809 CreateWARPCompositorDevice(); 810 return; 811 } 812 813 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked(); 814 if (!adapter) { 815 d3d11.SetFailed(FeatureStatus::Unavailable, 816 "Failed to acquire a DXGI adapter", 817 "FEATURE_FAILURE_D3D11_DXGI"_ns); 818 return; 819 } 820 821 if (XRE_IsGPUProcess() && !D3D11Checks::DoesRemotePresentWork(adapter)) { 822 d3d11.SetFailed(FeatureStatus::Unavailable, 823 "DXGI does not support out-of-process presentation", 824 "FEATURE_FAILURE_D3D11_REMOTE_PRESENT"_ns); 825 return; 826 } 827 828 RefPtr<ID3D11Device> device; 829 if (!CreateCompositorDeviceHelper(d3d11, adapter, true, device)) { 830 // Try again without video support and record that it failed. 831 mCompositorDeviceSupportsVideo = false; 832 if (!CreateCompositorDeviceHelper(d3d11, adapter, false, device)) { 833 return; 834 } 835 } else { 836 mCompositorDeviceSupportsVideo = true; 837 } 838 839 // Only test this when not using WARP since it can fail and cause 840 // GetDeviceRemovedReason to return weird values. 841 bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device); 842 843 DXGI_ADAPTER_DESC desc; 844 PodZero(&desc); 845 adapter->GetDesc(&desc); 846 847 if (!textureSharingWorks) { 848 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken, 849 "Texture sharing doesn't work", 850 "FEATURE_FAILURE_HW_ANGLE_NEEDS_TEXTURE_SHARING"_ns); 851 } 852 if (D3D11Checks::DoesRenderTargetViewNeedRecreating(device)) { 853 gfxConfig::SetFailed(Feature::D3D11_HW_ANGLE, FeatureStatus::Broken, 854 "RenderTargetViews need recreating", 855 "FEATURE_FAILURE_HW_ANGLE_NEEDS_RTV_RECREATION"_ns); 856 } 857 if (XRE_IsParentProcess()) { 858 // It seems like this may only happen when we're using the NVIDIA gpu 859 D3D11Checks::WarnOnAdapterMismatch(device); 860 } 861 862 RefPtr<ID3D10Multithread> multi; 863 HRESULT hr = device->QueryInterface(__uuidof(ID3D10Multithread), 864 getter_AddRefs(multi)); 865 if (SUCCEEDED(hr) && multi) { 866 multi->SetMultithreadProtected(TRUE); 867 } 868 869 uint32_t featureLevel = device->GetFeatureLevel(); 870 auto formatOptions = D3D11Checks::FormatOptions(device); 871 mCompositorDevice = device; 872 873 int32_t sequenceNumber = GetNextDeviceCounter(); 874 mDeviceStatus = Some(D3D11DeviceStatus( 875 false, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc), 876 sequenceNumber, formatOptions)); 877 mCompositorDevice->SetExceptionMode(0); 878 } 879 880 bool DeviceManagerDx::CreateDevice(IDXGIAdapter* aAdapter, 881 D3D_DRIVER_TYPE aDriverType, UINT aFlags, 882 HRESULT& aResOut, 883 RefPtr<ID3D11Device>& aOutDevice) { 884 if (StaticPrefs::gfx_direct3d11_enable_debug_layer_AtStartup() || 885 StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) { 886 aFlags |= D3D11_CREATE_DEVICE_DEBUG; 887 } 888 889 MOZ_SEH_TRY { 890 aResOut = sD3D11CreateDeviceFn( 891 aAdapter, aDriverType, nullptr, aFlags, mFeatureLevels.Elements(), 892 mFeatureLevels.Length(), D3D11_SDK_VERSION, getter_AddRefs(aOutDevice), 893 nullptr, nullptr); 894 } 895 MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return false; } 896 897 if (StaticPrefs::gfx_direct3d11_break_on_error_AtStartup()) { 898 do { 899 if (!aOutDevice) break; 900 901 RefPtr<ID3D11Debug> debug; 902 if (!SUCCEEDED(aOutDevice->QueryInterface(__uuidof(ID3D11Debug), 903 getter_AddRefs(debug)))) 904 break; 905 906 RefPtr<ID3D11InfoQueue> infoQueue; 907 if (!SUCCEEDED(debug->QueryInterface(__uuidof(ID3D11InfoQueue), 908 getter_AddRefs(infoQueue)))) 909 break; 910 911 D3D11_INFO_QUEUE_FILTER filter; 912 PodZero(&filter); 913 914 // Disable warnings caused by Advanced Layers that are known and not 915 // problematic. 916 D3D11_MESSAGE_ID blockIDs[] = { 917 D3D11_MESSAGE_ID_DEVICE_DRAW_CONSTANT_BUFFER_TOO_SMALL}; 918 filter.DenyList.NumIDs = std::size(blockIDs); 919 filter.DenyList.pIDList = blockIDs; 920 infoQueue->PushStorageFilter(&filter); 921 922 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); 923 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); 924 infoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_WARNING, true); 925 } while (false); 926 } 927 928 return true; 929 } 930 931 void DeviceManagerDx::CreateWARPCompositorDevice() { 932 ScopedGfxFeatureReporter reporterWARP( 933 "D3D11-WARP", StaticPrefs::layers_d3d11_force_warp_AtStartup()); 934 FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING); 935 936 HRESULT hr; 937 RefPtr<ID3D11Device> device; 938 939 // Use D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS 940 // to prevent bug 1092260. IE 11 also uses this flag. 941 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 942 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, flags, hr, device)) { 943 gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!"; 944 d3d11.SetFailed(FeatureStatus::CrashedInHandler, 945 "Crashed creating a D3D11 WARP device", 946 "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns); 947 } 948 949 if (FAILED(hr) || !device) { 950 // This should always succeed... in theory. 951 gfxCriticalError() << "Failed to initialize WARP D3D11 device! " 952 << hexa(hr); 953 d3d11.SetFailed(FeatureStatus::Failed, 954 "Failed to create a D3D11 WARP device", 955 "FEATURE_FAILURE_D3D11_WARP_DEVICE2"_ns); 956 return; 957 } 958 959 bool textureSharingWorks = D3D11Checks::DoesTextureSharingWork(device); 960 961 RefPtr<ID3D10Multithread> multi; 962 hr = device->QueryInterface(__uuidof(ID3D10Multithread), 963 getter_AddRefs(multi)); 964 if (SUCCEEDED(hr) && multi) { 965 multi->SetMultithreadProtected(TRUE); 966 } 967 968 DXGI_ADAPTER_DESC desc; 969 D3D11Checks::GetDxgiDesc(device, &desc); 970 971 int featureLevel = device->GetFeatureLevel(); 972 973 auto formatOptions = D3D11Checks::FormatOptions(device); 974 mCompositorDevice = device; 975 976 int32_t sequenceNumber = GetNextDeviceCounter(); 977 mDeviceStatus = Some(D3D11DeviceStatus( 978 true, textureSharingWorks, featureLevel, DxgiAdapterDesc::From(desc), 979 sequenceNumber, formatOptions)); 980 mCompositorDevice->SetExceptionMode(0); 981 982 reporterWARP.SetSuccessful(); 983 } 984 985 FeatureStatus DeviceManagerDx::CreateContentDevice() { 986 RefPtr<IDXGIAdapter1> adapter; 987 if (!IsWARPLocked()) { 988 adapter = GetDXGIAdapterLocked(); 989 if (!adapter) { 990 gfxCriticalNote << "Could not get a DXGI adapter"; 991 return FeatureStatus::Unavailable; 992 } 993 } 994 995 HRESULT hr; 996 RefPtr<ID3D11Device> device; 997 998 UINT flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; 999 D3D_DRIVER_TYPE type = 1000 IsWARPLocked() ? D3D_DRIVER_TYPE_WARP : D3D_DRIVER_TYPE_UNKNOWN; 1001 if (!CreateDevice(adapter, type, flags, hr, device)) { 1002 gfxCriticalNote 1003 << "Recovered from crash while creating a D3D11 content device"; 1004 gfxWindowsPlatform::RecordContentDeviceFailure( 1005 TelemetryDeviceCode::Content); 1006 return FeatureStatus::CrashedInHandler; 1007 } 1008 1009 if (FAILED(hr) || !device) { 1010 gfxCriticalNote << "Failed to create a D3D11 content device: " << hexa(hr); 1011 gfxWindowsPlatform::RecordContentDeviceFailure( 1012 TelemetryDeviceCode::Content); 1013 return FeatureStatus::Failed; 1014 } 1015 1016 // InitializeD2D() will abort early if the compositor device did not support 1017 // texture sharing. If we're in the content process, we can't rely on the 1018 // parent device alone: some systems have dual GPUs that are capable of 1019 // binding the parent and child processes to different GPUs. As a safety net, 1020 // we re-check texture sharing against the newly created D3D11 content device. 1021 // If it fails, we won't use Direct2D. 1022 if (XRE_IsContentProcess()) { 1023 if (!D3D11Checks::DoesTextureSharingWork(device)) { 1024 return FeatureStatus::Failed; 1025 } 1026 1027 DebugOnly<bool> ok = ContentAdapterIsParentAdapter(device); 1028 MOZ_ASSERT(ok); 1029 } 1030 1031 mContentDevice = device; 1032 mContentDevice->SetExceptionMode(0); 1033 1034 RefPtr<ID3D10Multithread> multi; 1035 hr = mContentDevice->QueryInterface(__uuidof(ID3D10Multithread), 1036 getter_AddRefs(multi)); 1037 if (SUCCEEDED(hr) && multi) { 1038 multi->SetMultithreadProtected(TRUE); 1039 } 1040 return FeatureStatus::Available; 1041 } 1042 1043 RefPtr<ID3D11Device> DeviceManagerDx::CreateDecoderDevice( 1044 DeviceFlagSet aFlags) { 1045 MutexAutoLock lock(mDeviceLock); 1046 1047 if (!mDeviceStatus) { 1048 return nullptr; 1049 } 1050 1051 bool isAMD = mDeviceStatus->adapter().VendorId == 0x1002; 1052 bool reuseDevice = false; 1053 if (gfxVars::ReuseDecoderDevice()) { 1054 reuseDevice = true; 1055 } else if (isAMD) { 1056 reuseDevice = true; 1057 gfxCriticalNoteOnce << "Always have to reuse decoder device on AMD"; 1058 } 1059 1060 if (reuseDevice) { 1061 // Use mCompositorDevice for decoder device only for hardware WebRender. 1062 if (aFlags.contains(DeviceFlag::isHardwareWebRenderInUse) && 1063 mCompositorDevice && mCompositorDeviceSupportsVideo && 1064 !mDecoderDevice) { 1065 mDecoderDevice = mCompositorDevice; 1066 1067 RefPtr<ID3D10Multithread> multi; 1068 mDecoderDevice->QueryInterface(__uuidof(ID3D10Multithread), 1069 getter_AddRefs(multi)); 1070 if (multi) { 1071 MOZ_ASSERT(multi->GetMultithreadProtected()); 1072 } 1073 } 1074 1075 if (mDecoderDevice) { 1076 RefPtr<ID3D11Device> dev = mDecoderDevice; 1077 return dev.forget(); 1078 } 1079 } 1080 1081 if (!sD3D11CreateDeviceFn) { 1082 // We should just be on Windows Vista or XP in this case. 1083 return nullptr; 1084 } 1085 1086 RefPtr<IDXGIAdapter1> adapter = GetDXGIAdapterLocked(); 1087 if (!adapter) { 1088 return nullptr; 1089 } 1090 1091 HRESULT hr; 1092 RefPtr<ID3D11Device> device; 1093 1094 UINT flags = D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS | 1095 D3D11_CREATE_DEVICE_VIDEO_SUPPORT; 1096 if (!CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, flags, hr, device)) { 1097 return nullptr; 1098 } 1099 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) { 1100 return nullptr; 1101 } 1102 1103 RefPtr<ID3D10Multithread> multi; 1104 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi)); 1105 if (multi) { 1106 multi->SetMultithreadProtected(TRUE); 1107 } 1108 if (reuseDevice) { 1109 mDecoderDevice = device; 1110 } 1111 return device; 1112 } 1113 1114 // ID3D11DeviceChild, IDXGIObject and ID3D11Device implement SetPrivateData with 1115 // the exact same parameters. 1116 template <typename T> 1117 static HRESULT SetDebugName(T* d3d11Object, const char* debugString) { 1118 return d3d11Object->SetPrivateData(WKPDID_D3DDebugObjectName, 1119 strlen(debugString), debugString); 1120 } 1121 1122 RefPtr<ID3D11Device> DeviceManagerDx::CreateMediaEngineDevice() { 1123 MutexAutoLock lock(mDeviceLock); 1124 if (!LoadD3D11()) { 1125 return nullptr; 1126 } 1127 1128 HRESULT hr; 1129 RefPtr<ID3D11Device> device; 1130 UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT | 1131 D3D11_CREATE_DEVICE_BGRA_SUPPORT | 1132 D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS; 1133 if (!CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, flags, hr, device)) { 1134 return nullptr; 1135 } 1136 if (FAILED(hr) || !device || !D3D11Checks::DoesDeviceWork()) { 1137 return nullptr; 1138 } 1139 (void)SetDebugName(device.get(), "MFMediaEngineDevice"); 1140 1141 RefPtr<ID3D10Multithread> multi; 1142 device->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi)); 1143 if (multi) { 1144 multi->SetMultithreadProtected(TRUE); 1145 } 1146 return device; 1147 } 1148 1149 void DeviceManagerDx::ResetDevices() { 1150 MutexAutoLock lock(mDeviceLock); 1151 ResetDevicesLocked(); 1152 } 1153 1154 void DeviceManagerDx::ResetDevicesLocked() { 1155 mAdapter = nullptr; 1156 mCompositorAttachments = nullptr; 1157 mCompositorDevice = nullptr; 1158 mContentDevice = nullptr; 1159 mCanvasDevice = nullptr; 1160 mImageDevice = nullptr; 1161 mVRDevice = nullptr; 1162 mDecoderDevice = nullptr; 1163 mDirectCompositionDevice = nullptr; 1164 mDeviceStatus = Nothing(); 1165 mDeviceResetReason = Nothing(); 1166 Factory::SetDirect3D11Device(nullptr); 1167 } 1168 1169 bool DeviceManagerDx::MaybeResetAndReacquireDevices() { 1170 MutexAutoLock lock(mDeviceLock); 1171 1172 DeviceResetReason resetReason; 1173 if (!HasDeviceResetLocked(&resetReason)) { 1174 return false; 1175 } 1176 1177 GPUProcessManager::RecordDeviceReset(resetReason); 1178 1179 bool createCompositorDevice = !!mCompositorDevice; 1180 bool createContentDevice = !!mContentDevice; 1181 bool createCanvasDevice = !!mCanvasDevice; 1182 bool createDirectCompositionDevice = !!mDirectCompositionDevice; 1183 1184 ResetDevicesLocked(); 1185 1186 if (createCompositorDevice && !CreateCompositorDevicesLocked()) { 1187 // Just stop, don't try anything more 1188 return true; 1189 } 1190 if (createContentDevice) { 1191 CreateContentDevicesLocked(); 1192 } 1193 if (createCanvasDevice) { 1194 CreateCanvasDeviceLocked(); 1195 } 1196 if (createDirectCompositionDevice) { 1197 CreateDirectCompositionDeviceLocked(); 1198 } 1199 1200 return true; 1201 } 1202 1203 bool DeviceManagerDx::ContentAdapterIsParentAdapter(ID3D11Device* device) { 1204 DXGI_ADAPTER_DESC desc; 1205 if (!D3D11Checks::GetDxgiDesc(device, &desc)) { 1206 gfxCriticalNote << "Could not query device DXGI adapter info"; 1207 return false; 1208 } 1209 1210 if (!mDeviceStatus) { 1211 return false; 1212 } 1213 1214 const DxgiAdapterDesc& preferred = mDeviceStatus->adapter(); 1215 1216 if (desc.VendorId != preferred.VendorId || 1217 desc.DeviceId != preferred.DeviceId || 1218 desc.SubSysId != preferred.SubSysId || 1219 desc.AdapterLuid.HighPart != preferred.AdapterLuid.HighPart || 1220 desc.AdapterLuid.LowPart != preferred.AdapterLuid.LowPart) { 1221 gfxCriticalNote << "VendorIDMismatch P " << hexa(preferred.VendorId) << " " 1222 << hexa(desc.VendorId); 1223 return false; 1224 } 1225 1226 return true; 1227 } 1228 1229 static DeviceResetReason HResultToResetReason(HRESULT hr) { 1230 switch (hr) { 1231 case DXGI_ERROR_DEVICE_HUNG: 1232 return DeviceResetReason::HUNG; 1233 case DXGI_ERROR_DEVICE_REMOVED: 1234 return DeviceResetReason::REMOVED; 1235 case DXGI_ERROR_DEVICE_RESET: 1236 return DeviceResetReason::RESET; 1237 case DXGI_ERROR_DRIVER_INTERNAL_ERROR: 1238 return DeviceResetReason::DRIVER_ERROR; 1239 case DXGI_ERROR_INVALID_CALL: 1240 return DeviceResetReason::INVALID_CALL; 1241 case E_OUTOFMEMORY: 1242 return DeviceResetReason::OUT_OF_MEMORY; 1243 default: 1244 MOZ_ASSERT(false); 1245 } 1246 return DeviceResetReason::OTHER; 1247 } 1248 1249 bool DeviceManagerDx::HasDeviceReset(DeviceResetReason* aOutReason) { 1250 MutexAutoLock lock(mDeviceLock); 1251 return HasDeviceResetLocked(aOutReason); 1252 } 1253 1254 bool DeviceManagerDx::HasDeviceResetLocked(DeviceResetReason* aOutReason) { 1255 if (mDeviceResetReason) { 1256 if (aOutReason) { 1257 *aOutReason = mDeviceResetReason.value(); 1258 } 1259 return true; 1260 } 1261 1262 DeviceResetReason reason; 1263 if (GetAnyDeviceRemovedReason(&reason)) { 1264 mDeviceResetReason = Some(reason); 1265 if (aOutReason) { 1266 *aOutReason = reason; 1267 } 1268 return true; 1269 } 1270 1271 return false; 1272 } 1273 1274 static inline bool DidDeviceReset(const RefPtr<ID3D11Device>& aDevice, 1275 DeviceResetReason* aOutReason) { 1276 if (!aDevice) { 1277 return false; 1278 } 1279 HRESULT hr = aDevice->GetDeviceRemovedReason(); 1280 if (hr == S_OK) { 1281 return false; 1282 } 1283 1284 *aOutReason = HResultToResetReason(hr); 1285 return true; 1286 } 1287 1288 bool DeviceManagerDx::GetAnyDeviceRemovedReason(DeviceResetReason* aOutReason) { 1289 if (DidDeviceReset(mCompositorDevice, aOutReason) || 1290 DidDeviceReset(mContentDevice, aOutReason) || 1291 DidDeviceReset(mCanvasDevice, aOutReason)) { 1292 return true; 1293 } 1294 1295 if (XRE_IsParentProcess() && NS_IsMainThread() && 1296 StaticPrefs::gfx_testing_device_reset()) { 1297 Preferences::SetInt("gfx.testing.device-reset", 0); 1298 *aOutReason = DeviceResetReason::FORCED_RESET; 1299 return true; 1300 } 1301 1302 return false; 1303 } 1304 1305 void DeviceManagerDx::ForceDeviceReset(ForcedDeviceResetReason aReason) { 1306 glean::gfx::forced_device_reset_reason.AccumulateSingleSample( 1307 uint32_t(aReason)); 1308 { 1309 MutexAutoLock lock(mDeviceLock); 1310 if (!mDeviceResetReason) { 1311 mDeviceResetReason = Some(DeviceResetReason::FORCED_RESET); 1312 } 1313 } 1314 } 1315 1316 void DeviceManagerDx::DisableD3D11AfterCrash() { 1317 gfxConfig::Disable(Feature::D3D11_COMPOSITING, 1318 FeatureStatus::CrashedInHandler, 1319 "Crashed while acquiring a Direct3D11 device", 1320 "FEATURE_FAILURE_D3D11_CRASH"_ns); 1321 ResetDevices(); 1322 } 1323 1324 RefPtr<ID3D11Device> DeviceManagerDx::GetCompositorDevice() { 1325 /// ID3D11Device is thread-safe. We need the lock to read the 1326 /// mDeviceLockPointer, but manipulating the pointee outside of the lock is 1327 /// safe. See 1328 /// https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-render-multi-thread-intro 1329 MutexAutoLock lock(mDeviceLock); 1330 return mCompositorDevice; 1331 } 1332 1333 RefPtr<ID3D11Device> DeviceManagerDx::GetContentDevice() { 1334 MOZ_ASSERT(XRE_IsGPUProcess() || 1335 gfxPlatform::GetPlatform()->DevicesInitialized()); 1336 1337 MutexAutoLock lock(mDeviceLock); 1338 return mContentDevice; 1339 } 1340 1341 RefPtr<ID3D11Device> DeviceManagerDx::GetImageDevice() { 1342 MutexAutoLock lock(mDeviceLock); 1343 if (mImageDevice) { 1344 return mImageDevice; 1345 } 1346 1347 RefPtr<ID3D11Device> device = mContentDevice; 1348 if (!device) { 1349 device = mCompositorDevice; 1350 } 1351 1352 if (!device) { 1353 return nullptr; 1354 } 1355 1356 RefPtr<ID3D10Multithread> multi; 1357 HRESULT hr = 1358 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(multi)); 1359 if (FAILED(hr) || !multi) { 1360 gfxWarning() << "Multithread safety interface not supported. " << hr; 1361 return nullptr; 1362 } else { 1363 MOZ_ASSERT(multi->GetMultithreadProtected()); 1364 } 1365 1366 mImageDevice = device; 1367 1368 return mImageDevice; 1369 } 1370 1371 RefPtr<ID3D11Device> DeviceManagerDx::GetVRDevice() { 1372 MutexAutoLock lock(mDeviceLock); 1373 if (!mVRDevice) { 1374 CreateVRDevice(); 1375 } 1376 return mVRDevice; 1377 } 1378 1379 RefPtr<ID3D11Device> DeviceManagerDx::GetCanvasDevice() { 1380 MutexAutoLock lock(mDeviceLock); 1381 return mCanvasDevice; 1382 } 1383 1384 RefPtr<IDCompositionDevice2> DeviceManagerDx::GetDirectCompositionDevice() { 1385 MutexAutoLock lock(mDeviceLock); 1386 return mDirectCompositionDevice; 1387 } 1388 1389 unsigned DeviceManagerDx::GetCompositorFeatureLevel() const { 1390 MutexAutoLock lock(mDeviceLock); 1391 if (!mDeviceStatus) { 1392 return 0; 1393 } 1394 return mDeviceStatus->featureLevel(); 1395 } 1396 1397 bool DeviceManagerDx::TextureSharingWorks() { 1398 MutexAutoLock lock(mDeviceLock); 1399 if (!mDeviceStatus) { 1400 return false; 1401 } 1402 return mDeviceStatus->textureSharingWorks(); 1403 } 1404 1405 bool DeviceManagerDx::CanInitializeKeyedMutexTextures() { 1406 MutexAutoLock lock(mDeviceLock); 1407 return mDeviceStatus && StaticPrefs::gfx_direct3d11_allow_keyed_mutex() && 1408 gfxVars::AllowD3D11KeyedMutex(); 1409 } 1410 1411 bool DeviceManagerDx::IsWARP() { 1412 MutexAutoLock lock(mDeviceLock); 1413 return IsWARPLocked(); 1414 } 1415 1416 bool DeviceManagerDx::IsWARPLocked() { 1417 if (!mDeviceStatus) { 1418 return false; 1419 } 1420 return mDeviceStatus->isWARP(); 1421 } 1422 1423 bool DeviceManagerDx::CanUseNV12() { 1424 MutexAutoLock lock(mDeviceLock); 1425 if (!mDeviceStatus) { 1426 return false; 1427 } 1428 return mDeviceStatus->formatOptions().contains( 1429 D3D11Checks::VideoFormatOption::NV12); 1430 } 1431 1432 bool DeviceManagerDx::CanUseP010() { 1433 MutexAutoLock lock(mDeviceLock); 1434 if (!mDeviceStatus) { 1435 return false; 1436 } 1437 return mDeviceStatus->formatOptions().contains( 1438 D3D11Checks::VideoFormatOption::P010); 1439 } 1440 1441 bool DeviceManagerDx::CanUseP016() { 1442 MutexAutoLock lock(mDeviceLock); 1443 if (!mDeviceStatus) { 1444 return false; 1445 } 1446 return mDeviceStatus->formatOptions().contains( 1447 D3D11Checks::VideoFormatOption::P016); 1448 } 1449 1450 bool DeviceManagerDx::CanUseDComp() { 1451 MutexAutoLock lock(mDeviceLock); 1452 return !!mDirectCompositionDevice; 1453 } 1454 1455 bool DeviceManagerDx::CanUseDCompositionTexture() { 1456 MutexAutoLock lock(mDeviceLock); 1457 return mDirectCompositionDevice && mSupportsDCompositionTexture; 1458 } 1459 1460 void DeviceManagerDx::GetCompositorDevices( 1461 RefPtr<ID3D11Device>* aOutDevice, 1462 RefPtr<layers::DeviceAttachmentsD3D11>* aOutAttachments) { 1463 RefPtr<ID3D11Device> device; 1464 { 1465 MutexAutoLock lock(mDeviceLock); 1466 if (!mCompositorDevice) { 1467 return; 1468 } 1469 if (mCompositorAttachments) { 1470 *aOutDevice = mCompositorDevice; 1471 *aOutAttachments = mCompositorAttachments; 1472 return; 1473 } 1474 1475 // Otherwise, we'll try to create attachments outside the lock. 1476 device = mCompositorDevice; 1477 } 1478 1479 // We save the attachments object even if it fails to initialize, so the 1480 // compositor can grab the failure ID. 1481 RefPtr<layers::DeviceAttachmentsD3D11> attachments = 1482 layers::DeviceAttachmentsD3D11::Create(device); 1483 { 1484 MutexAutoLock lock(mDeviceLock); 1485 if (device != mCompositorDevice) { 1486 return; 1487 } 1488 mCompositorAttachments = attachments; 1489 } 1490 1491 *aOutDevice = device; 1492 *aOutAttachments = attachments; 1493 } 1494 1495 /* static */ 1496 void DeviceManagerDx::PreloadAttachmentsOnCompositorThread() { 1497 if (!CompositorThread()) { 1498 return; 1499 } 1500 1501 RefPtr<Runnable> task = NS_NewRunnableFunction( 1502 "DeviceManagerDx::PreloadAttachmentsOnCompositorThread", []() -> void { 1503 if (DeviceManagerDx* dm = DeviceManagerDx::Get()) { 1504 RefPtr<ID3D11Device> device; 1505 RefPtr<layers::DeviceAttachmentsD3D11> attachments; 1506 dm->GetCompositorDevices(&device, &attachments); 1507 } 1508 }); 1509 CompositorThread()->Dispatch(task.forget()); 1510 } 1511 1512 } // namespace gfx 1513 } // namespace mozilla