tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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