tor-browser

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

gfxWindowsPlatform.cpp (59602B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #define INITGUID  // set before devguid.h
      8 
      9 #include "gfxWindowsPlatform.h"
     10 
     11 #include "cairo.h"
     12 #include "mozilla/layers/CompositorBridgeChild.h"
     13 
     14 #include "gfxBlur.h"
     15 #include "gfxImageSurface.h"
     16 #include "gfxWindowsSurface.h"
     17 
     18 #include "nsUnicharUtils.h"
     19 #include "nsUnicodeProperties.h"
     20 
     21 #include "mozilla/Preferences.h"
     22 #include "mozilla/ProfilerLabels.h"
     23 #include "mozilla/ProfilerMarkers.h"
     24 #include "mozilla/ProfilerThreadSleep.h"
     25 #include "mozilla/Components.h"
     26 #include "mozilla/Sprintf.h"
     27 #include "mozilla/WindowsVersion.h"
     28 #include "nsIGfxInfo.h"
     29 #include "nsServiceManagerUtils.h"
     30 #include "nsTArray.h"
     31 #include "nsThreadUtils.h"
     32 #include "mozilla/glean/GfxMetrics.h"
     33 
     34 #include "plbase64.h"
     35 #include "nsIXULRuntime.h"
     36 #include "imgLoader.h"
     37 
     38 #include "nsIGfxInfo.h"
     39 
     40 #include "gfxCrashReporterUtils.h"
     41 
     42 #include "mozilla/layers/CanvasChild.h"
     43 #include "mozilla/layers/CompositorThread.h"
     44 
     45 #include "gfxDWriteFontList.h"
     46 #include "gfxDWriteFonts.h"
     47 #include "gfxDWriteCommon.h"
     48 #include <dwrite.h>
     49 
     50 #include "gfxTextRun.h"
     51 #include "gfxUserFontSet.h"
     52 #include "nsWindowsHelpers.h"
     53 #include "gfx2DGlue.h"
     54 
     55 #include <d3d10_1.h>
     56 
     57 #include "mozilla/gfx/2D.h"
     58 #include "mozilla/gfx/gfxVars.h"
     59 
     60 #include <dwmapi.h>
     61 #include <d3d11.h>
     62 #include <d2d1_1.h>
     63 
     64 #include "nsIMemoryReporter.h"
     65 #include <winternl.h>
     66 #include "d3dkmtQueryStatistics.h"
     67 
     68 #include "base/thread.h"
     69 #include "mozilla/StaticPrefs_gfx.h"
     70 #ifdef MOZ_WMF_CDM
     71 #  include "mozilla/StaticPrefs_media.h"
     72 #endif
     73 #include "mozilla/StaticPrefs_layers.h"
     74 #include "gfxConfig.h"
     75 #include "VsyncSource.h"
     76 #include "DriverCrashGuard.h"
     77 #include "mozilla/dom/ContentChild.h"
     78 #include "mozilla/gfx/DeviceManagerDx.h"
     79 #include "mozilla/gfx/DisplayConfigWindows.h"
     80 #include "mozilla/gfx/GPUProcessManager.h"
     81 #include "mozilla/layers/DeviceAttachmentsD3D11.h"
     82 #include "mozilla/WindowsProcessMitigations.h"
     83 #include "D3D11Checks.h"
     84 #include "mozilla/ScreenHelperWin.h"
     85 
     86 using namespace mozilla;
     87 using namespace mozilla::gfx;
     88 using namespace mozilla::layers;
     89 using namespace mozilla::widget;
     90 using namespace mozilla::image;
     91 using namespace mozilla::unicode;
     92 
     93 DCForMetrics::DCForMetrics() {
     94  // Get the whole screen DC:
     95  mDC = GetDC(nullptr);
     96  SetGraphicsMode(mDC, GM_ADVANCED);
     97 }
     98 
     99 class GPUAdapterReporter final : public nsIMemoryReporter {
    100  // Callers must Release the DXGIAdapter after use or risk mem-leak
    101  static bool GetDXGIAdapter(IDXGIAdapter** aDXGIAdapter) {
    102    RefPtr<ID3D11Device> d3d11Device;
    103    RefPtr<IDXGIDevice> dxgiDevice;
    104    bool result = false;
    105 
    106    if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
    107      if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice),
    108                                      getter_AddRefs(dxgiDevice)) == S_OK) {
    109        result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
    110      }
    111    }
    112 
    113    return result;
    114  }
    115 
    116  ~GPUAdapterReporter() {}
    117 
    118 public:
    119  NS_DECL_ISUPPORTS
    120 
    121  NS_IMETHOD
    122  CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
    123                 bool aAnonymize) override {
    124    HANDLE ProcessHandle = GetCurrentProcess();
    125 
    126    int64_t dedicatedBytesUsed = 0;
    127    int64_t sharedBytesUsed = 0;
    128    int64_t committedBytesUsed = 0;
    129    IDXGIAdapter* DXGIAdapter;
    130 
    131    HMODULE gdi32Handle;
    132    PFND3DKMTQS queryD3DKMTStatistics = nullptr;
    133 
    134    if ((gdi32Handle = LoadLibrary(TEXT("gdi32.dll"))))
    135      queryD3DKMTStatistics =
    136          (PFND3DKMTQS)GetProcAddress(gdi32Handle, "D3DKMTQueryStatistics");
    137 
    138    if (queryD3DKMTStatistics && GetDXGIAdapter(&DXGIAdapter)) {
    139      // Most of this block is understood thanks to wj32's work on Process
    140      // Hacker
    141 
    142      DXGI_ADAPTER_DESC adapterDesc;
    143      D3DKMTQS queryStatistics;
    144 
    145      DXGIAdapter->GetDesc(&adapterDesc);
    146      DXGIAdapter->Release();
    147 
    148      memset(&queryStatistics, 0, sizeof(D3DKMTQS));
    149      queryStatistics.Type = D3DKMTQS_PROCESS;
    150      queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
    151      queryStatistics.hProcess = ProcessHandle;
    152      if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
    153        committedBytesUsed =
    154            queryStatistics.QueryResult.ProcessInfo.SystemMemory.BytesAllocated;
    155      }
    156 
    157      memset(&queryStatistics, 0, sizeof(D3DKMTQS));
    158      queryStatistics.Type = D3DKMTQS_ADAPTER;
    159      queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
    160      if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
    161        ULONG i;
    162        ULONG segmentCount = queryStatistics.QueryResult.AdapterInfo.NbSegments;
    163 
    164        for (i = 0; i < segmentCount; i++) {
    165          memset(&queryStatistics, 0, sizeof(D3DKMTQS));
    166          queryStatistics.Type = D3DKMTQS_SEGMENT;
    167          queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
    168          queryStatistics.QuerySegment.SegmentId = i;
    169 
    170          if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
    171            bool aperture = queryStatistics.QueryResult.SegmentInfo.Aperture;
    172            memset(&queryStatistics, 0, sizeof(D3DKMTQS));
    173            queryStatistics.Type = D3DKMTQS_PROCESS_SEGMENT;
    174            queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
    175            queryStatistics.hProcess = ProcessHandle;
    176            queryStatistics.QueryProcessSegment.SegmentId = i;
    177            if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
    178              ULONGLONG bytesCommitted =
    179                  queryStatistics.QueryResult.ProcessSegmentInfo.BytesCommitted;
    180              if (aperture)
    181                sharedBytesUsed += bytesCommitted;
    182              else
    183                dedicatedBytesUsed += bytesCommitted;
    184            }
    185          }
    186        }
    187      }
    188    }
    189 
    190    FreeLibrary(gdi32Handle);
    191 
    192    MOZ_COLLECT_REPORT("gpu-committed", KIND_OTHER, UNITS_BYTES,
    193                       committedBytesUsed,
    194                       "Memory committed by the Windows graphics system.");
    195 
    196    MOZ_COLLECT_REPORT(
    197        "gpu-dedicated", KIND_OTHER, UNITS_BYTES, dedicatedBytesUsed,
    198        "Out-of-process memory allocated for this process in a physical "
    199        "GPU adapter's memory.");
    200 
    201    MOZ_COLLECT_REPORT("gpu-shared", KIND_OTHER, UNITS_BYTES, sharedBytesUsed,
    202                       "In-process memory that is shared with the GPU.");
    203 
    204    return NS_OK;
    205  }
    206 };
    207 
    208 NS_IMPL_ISUPPORTS(GPUAdapterReporter, nsIMemoryReporter)
    209 
    210 Atomic<size_t> gfxWindowsPlatform::sD3D11SharedTextures;
    211 Atomic<size_t> gfxWindowsPlatform::sD3D9SharedTextures;
    212 
    213 class D3DSharedTexturesReporter final : public nsIMemoryReporter {
    214  ~D3DSharedTexturesReporter() {}
    215 
    216 public:
    217  NS_DECL_ISUPPORTS
    218 
    219  NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport,
    220                            nsISupports* aData, bool aAnonymize) override {
    221    if (gfxWindowsPlatform::sD3D11SharedTextures > 0) {
    222      MOZ_COLLECT_REPORT("d3d11-shared-textures", KIND_OTHER, UNITS_BYTES,
    223                         gfxWindowsPlatform::sD3D11SharedTextures,
    224                         "D3D11 shared textures.");
    225    }
    226 
    227    if (gfxWindowsPlatform::sD3D9SharedTextures > 0) {
    228      MOZ_COLLECT_REPORT("d3d9-shared-textures", KIND_OTHER, UNITS_BYTES,
    229                         gfxWindowsPlatform::sD3D9SharedTextures,
    230                         "D3D9 shared textures.");
    231    }
    232 
    233    return NS_OK;
    234  }
    235 };
    236 
    237 NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter)
    238 
    239 gfxWindowsPlatform::gfxWindowsPlatform() {
    240  // If win32k is locked down then we can't use COM STA and shouldn't need it.
    241  // Also, we won't be using any GPU memory in this process.
    242  if (!IsWin32kLockedDown()) {
    243    /*
    244     * Initialize COM
    245     */
    246    CoInitialize(nullptr);
    247 
    248    RegisterStrongMemoryReporter(new GPUAdapterReporter());
    249    RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
    250  }
    251 }
    252 
    253 gfxWindowsPlatform::~gfxWindowsPlatform() {
    254  DeviceManagerDx::Shutdown();
    255 
    256  // We don't initialize COM when win32k is locked down.
    257  if (!IsWin32kLockedDown()) {
    258    /*
    259     * Uninitialize COM
    260     */
    261    CoUninitialize();
    262  }
    263 }
    264 
    265 /* static */
    266 void gfxWindowsPlatform::InitMemoryReportersForGPUProcess() {
    267  MOZ_RELEASE_ASSERT(XRE_IsGPUProcess());
    268 
    269  RegisterStrongMemoryReporter(new GPUAdapterReporter());
    270  RegisterStrongMemoryReporter(new D3DSharedTexturesReporter());
    271 }
    272 
    273 /* static */
    274 nsresult gfxWindowsPlatform::GetGpuTimeSinceProcessStartInMs(
    275    uint64_t* aResult) {
    276  // If win32k is locked down then we should not have any GPU processing and
    277  // cannot use these APIs either way.
    278  if (IsWin32kLockedDown()) {
    279    *aResult = 0;
    280    return NS_OK;
    281  }
    282 
    283  nsModuleHandle module(LoadLibrary(L"gdi32.dll"));
    284  if (!module) {
    285    return NS_ERROR_NOT_AVAILABLE;
    286  }
    287 
    288  PFND3DKMTQS queryD3DKMTStatistics =
    289      (PFND3DKMTQS)GetProcAddress(module, "D3DKMTQueryStatistics");
    290  if (!queryD3DKMTStatistics) {
    291    return NS_ERROR_NOT_AVAILABLE;
    292  }
    293 
    294  gfx::DeviceManagerDx* dm = DeviceManagerDx::Get();
    295  if (!dm) {
    296    return NS_ERROR_NOT_AVAILABLE;
    297  }
    298 
    299  D3D11DeviceStatus status;
    300  if (!dm->ExportDeviceInfo(&status)) {
    301    // Assume that we used 0ms of GPU time if the device manager
    302    // doesn't know the device status.
    303    *aResult = 0;
    304    return NS_OK;
    305  }
    306 
    307  const DxgiAdapterDesc& adapterDesc = status.adapter();
    308 
    309  D3DKMTQS queryStatistics;
    310  memset(&queryStatistics, 0, sizeof(D3DKMTQS));
    311  queryStatistics.Type = D3DKMTQS_ADAPTER;
    312  queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
    313  if (!NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
    314    return NS_ERROR_FAILURE;
    315  }
    316 
    317  uint64_t result = 0;
    318  ULONG nodeCount = queryStatistics.QueryResult.AdapterInfo.NodeCount;
    319  for (ULONG i = 0; i < nodeCount; ++i) {
    320    memset(&queryStatistics, 0, sizeof(D3DKMTQS));
    321    queryStatistics.Type = D3DKMTQS_PROCESS_NODE;
    322    queryStatistics.AdapterLuid = adapterDesc.AdapterLuid;
    323    queryStatistics.hProcess = GetCurrentProcess();
    324    queryStatistics.QueryProcessNode.NodeId = i;
    325    if (NT_SUCCESS(queryD3DKMTStatistics(&queryStatistics))) {
    326      result += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime
    327                    .QuadPart *
    328                100 / PR_NSEC_PER_MSEC;
    329    }
    330  }
    331 
    332  *aResult = result;
    333  return NS_OK;
    334 }
    335 
    336 static void UpdateANGLEConfig() {
    337  if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
    338    gfxConfig::Disable(Feature::D3D11_HW_ANGLE, FeatureStatus::Disabled,
    339                       "D3D11 compositing is disabled",
    340                       "FEATURE_FAILURE_HW_ANGLE_D3D11_DISABLED"_ns);
    341  }
    342 }
    343 
    344 void gfxWindowsPlatform::InitAcceleration() {
    345  gfxPlatform::InitAcceleration();
    346 
    347  DeviceManagerDx::Init();
    348 
    349  InitializeConfig();
    350  // Ensure devices initialization. SharedSurfaceANGLE and
    351  // SharedSurfaceD3D11Interop use them. The devices are lazily initialized
    352  // with WebRender to reduce memory usage.
    353  // Initialize them now when running non-e10s.
    354  if (!BrowserTabsRemoteAutostart()) {
    355    EnsureDevicesInitialized();
    356  }
    357  UpdateANGLEConfig();
    358  UpdateRenderMode();
    359 
    360  // If we have Skia and we didn't init dwrite already, do it now.
    361  if (!DWriteEnabled() && GetDefaultContentBackend() == BackendType::SKIA) {
    362    InitDWriteSupport();
    363  }
    364  // We need to listen for font setting changes even if DWrite is not used.
    365  Factory::SetSystemTextQuality(gfxVars::SystemTextQuality());
    366  gfxVars::SetSystemTextQualityListener(
    367      gfxDWriteFont::SystemTextQualityChanged);
    368 
    369  // Our ScreenHelperWin also depends on DeviceManagerDx state.
    370  if (XRE_IsParentProcess() && !gfxPlatform::IsHeadless()) {
    371    ScreenHelperWin::RefreshScreens();
    372  }
    373 
    374  RecordStartupTelemetry();
    375 }
    376 
    377 void gfxWindowsPlatform::InitWebRenderConfig() {
    378  gfxPlatform::InitWebRenderConfig();
    379  UpdateBackendPrefs();
    380 }
    381 
    382 void gfxWindowsPlatform::InitPlatformHardwareVideoConfig() {
    383  FeatureState& featureDec =
    384      gfxConfig::GetFeature(Feature::HARDWARE_VIDEO_DECODING);
    385  FeatureState& featureEnc =
    386      gfxConfig::GetFeature(Feature::HARDWARE_VIDEO_ENCODING);
    387 
    388  DeviceManagerDx* dm = DeviceManagerDx::Get();
    389  if (!dm) {
    390    featureDec.ForceDisable(FeatureStatus::Unavailable,
    391                            "Requires DeviceManagerDx",
    392                            "FEATURE_FAILURE_NO_DEVICE_MANAGER_DX"_ns);
    393    featureEnc.ForceDisable(FeatureStatus::Unavailable,
    394                            "Requires DeviceManagerDx",
    395                            "FEATURE_FAILURE_NO_DEVICE_MANAGER_DX"_ns);
    396  } else if (!dm->TextureSharingWorks()) {
    397    featureDec.ForceDisable(FeatureStatus::Unavailable,
    398                            "Requires texture sharing",
    399                            "FEATURE_FAILURE_BROKEN_TEXTURE_SHARING"_ns);
    400    featureEnc.ForceDisable(FeatureStatus::Unavailable,
    401                            "Requires texture sharing",
    402                            "FEATURE_FAILURE_BROKEN_TEXTURE_SHARING"_ns);
    403  } else if (dm->IsWARP()) {
    404    featureDec.ForceDisable(FeatureStatus::Unavailable, "Cannot use with WARP",
    405                            "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns);
    406    featureEnc.ForceDisable(FeatureStatus::Unavailable, "Cannot use with WARP",
    407                            "FEATURE_FAILURE_D3D11_WARP_DEVICE"_ns);
    408  }
    409 }
    410 
    411 #ifdef MOZ_WMF_CDM
    412 void gfxWindowsPlatform::InitPlatformHardwarDRMConfig() {
    413  nsCString message, failureId;
    414  FeatureState& featureHWDRM = gfxConfig::GetFeature(Feature::WMF_HW_DRM);
    415  featureHWDRM.Reset();
    416  featureHWDRM.EnableByDefault();
    417  if (StaticPrefs::media_wmf_media_engine_enabled() != 1 &&
    418      StaticPrefs::media_wmf_media_engine_enabled() != 2) {
    419    featureHWDRM.UserDisable(
    420        "Force disabled by 'media.wmf.media-engine.enabled'",
    421        "FEATURE_FAILURE_USER_FORCE_DISABLED"_ns);
    422  } else if (StaticPrefs::media_wmf_media_engine_bypass_gfx_blocklist()) {
    423    featureHWDRM.UserForceEnable(
    424        "Force enabled by "
    425        "'media.wmf.media-engine.bypass-gfx-blocklist'");
    426  }
    427  if (!IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_WMF_HW_DRM, &message,
    428                           failureId)) {
    429    featureHWDRM.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
    430  }
    431  if (Preferences::GetBool("media.eme.hwdrm.failed", false)) {
    432    featureHWDRM.ForceDisable(FeatureStatus::Unavailable,
    433                              "Force disabled by failed to find a descryptor",
    434                              "FEATURE_FAILURE_NO_DESCRYPTOR_FAILED"_ns);
    435  }
    436  gfxVars::SetUseWMFHWDWM(featureHWDRM.IsEnabled());
    437 }
    438 #endif
    439 
    440 bool gfxWindowsPlatform::InitDWriteSupport() {
    441  mozilla::ScopedGfxFeatureReporter reporter("DWrite");
    442  if (!gfxDWriteFont::InitDWriteSupport()) {
    443    return false;
    444  }
    445 
    446  reporter.SetSuccessful();
    447  return true;
    448 }
    449 
    450 bool gfxWindowsPlatform::HandleDeviceReset() {
    451  mozilla::gfx::DeviceResetReason resetReason =
    452      mozilla::gfx::DeviceResetReason::OK;
    453  if (!DidRenderingDeviceReset(&resetReason)) {
    454    return false;
    455  }
    456 
    457  if (resetReason != mozilla::gfx::DeviceResetReason::FORCED_RESET) {
    458    glean::gfx::device_reset_reason.AccumulateSingleSample(
    459        uint32_t(resetReason));
    460  }
    461 
    462  // Remove devices and adapters.
    463  DeviceManagerDx::Get()->ResetDevices();
    464 
    465  imgLoader::NormalLoader()->ClearCache(Nothing());
    466  imgLoader::PrivateBrowsingLoader()->ClearCache(Nothing());
    467  gfxGaussianBlur::ShutdownBlurCache();
    468 
    469  gfxConfig::Reset(Feature::D3D11_COMPOSITING);
    470  gfxConfig::Reset(Feature::D3D11_HW_ANGLE);
    471 
    472  InitializeConfig();
    473  // XXX Add InitWebRenderConfig() calling.
    474  if (mInitializedDevices) {
    475    InitializeDevices();
    476  }
    477  UpdateANGLEConfig();
    478  return true;
    479 }
    480 
    481 BackendPrefsData gfxWindowsPlatform::GetBackendPrefs() const {
    482  BackendPrefsData data;
    483 
    484  data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
    485  data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
    486  data.mCanvasDefault = BackendType::SKIA;
    487  data.mContentDefault = BackendType::SKIA;
    488 
    489  return data;
    490 }
    491 
    492 void gfxWindowsPlatform::UpdateBackendPrefs() {
    493  BackendPrefsData data = GetBackendPrefs();
    494  InitBackendPrefs(std::move(data));
    495 }
    496 
    497 void gfxWindowsPlatform::UpdateRenderMode() {
    498  bool didReset = HandleDeviceReset();
    499 
    500  UpdateBackendPrefs();
    501 
    502  if (didReset) {
    503    mScreenReferenceDrawTarget = CreateOffscreenContentDrawTarget(
    504        IntSize(1, 1), SurfaceFormat::B8G8R8A8);
    505    if (!mScreenReferenceDrawTarget) {
    506      gfxCriticalNote
    507          << "Failed to update reference draw target after device reset"
    508          << ", D3D11 device:" << hexa(Factory::GetDirect3D11Device().get())
    509          << ", D3D11 status:"
    510          << FeatureStatusToString(
    511                 gfxConfig::GetValue(Feature::D3D11_COMPOSITING))
    512          << ", content:" << int(GetDefaultContentBackend())
    513          << ", compositor:" << int(GetCompositorBackend());
    514      MOZ_CRASH(
    515          "GFX: Failed to update reference draw target after device reset");
    516    }
    517  }
    518 }
    519 
    520 mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor(
    521    mozilla::layers::LayersBackend aLayers) {
    522  return gfxPlatform::GetDefaultContentBackend();
    523 }
    524 
    525 mozilla::gfx::BackendType gfxWindowsPlatform::GetPreferredCanvasBackend() {
    526  return gfxPlatform::GetPreferredCanvasBackend();
    527 }
    528 
    529 bool gfxWindowsPlatform::CreatePlatformFontList() {
    530  return gfxPlatformFontList::Initialize(new gfxDWriteFontList);
    531 }
    532 
    533 already_AddRefed<gfxASurface> gfxWindowsPlatform::CreateOffscreenSurface(
    534    const IntSize& aSize, gfxImageFormat aFormat) {
    535  if (!Factory::AllowedSurfaceSize(aSize)) {
    536    return nullptr;
    537  }
    538 
    539  RefPtr<gfxASurface> surf = nullptr;
    540 
    541 #ifdef CAIRO_HAS_WIN32_SURFACE
    542  if (!XRE_IsContentProcess()) {
    543    surf = new gfxWindowsSurface(aSize, aFormat);
    544  }
    545 #endif
    546 
    547  if (!surf || surf->CairoStatus()) {
    548    surf = new gfxImageSurface(aSize, aFormat);
    549  }
    550 
    551  return surf.forget();
    552 }
    553 
    554 void gfxWindowsPlatform::GetCommonFallbackFonts(
    555    uint32_t aCh, Script aRunScript, FontPresentation aPresentation,
    556    nsTArray<const char*>& aFontList) {
    557  if (PrefersColor(aPresentation)) {
    558    aFontList.AppendElement("Segoe UI Emoji");
    559    aFontList.AppendElement("Twemoji Mozilla");
    560  }
    561 
    562  switch (aRunScript) {
    563    case Script::INVALID:
    564    case Script::NUM_SCRIPT_CODES:
    565      // Ensure the switch covers all the Script enum values.
    566      MOZ_ASSERT_UNREACHABLE("bad script code");
    567      break;
    568 
    569    case Script::COMMON:
    570    case Script::INHERITED:
    571      // In most cases, COMMON and INHERITED characters will be merged into
    572      // their context, but if they occur without context, we'll just treat
    573      // them like Latin, etc.
    574    case Script::LATIN:
    575    case Script::CYRILLIC:
    576    case Script::GREEK:
    577    case Script::ARMENIAN:
    578    case Script::HEBREW:
    579      // We always append Arial below, so no need to add it here.
    580      // aFontList.AppendElement("Arial");
    581      break;
    582 
    583    case Script::MATHEMATICAL_NOTATION:
    584    case Script::SYMBOLS:
    585    case Script::SYMBOLS_EMOJI:
    586      // Not currently returned by script run resolution (but some symbols may
    587      // be handled below).
    588      break;
    589 
    590      // CJK-related script codes are a bit troublesome because of unification;
    591      // we'll probably just get HAN much of the time, so the choice of which
    592      // language font to try for fallback is rather arbitrary. Usually, though,
    593      // we hope that font prefs will have handled this earlier.
    594    case Script::BOPOMOFO:
    595    case Script::HAN_WITH_BOPOMOFO:
    596    case Script::SIMPLIFIED_HAN:
    597    case Script::HAN:
    598      aFontList.AppendElement("SimSun");
    599      if (aCh > 0xFFFF) {
    600        aFontList.AppendElement("SimSun-ExtB");
    601      }
    602      break;
    603      // Currently, we don't resolve script runs to this value, but we may do so
    604      // in future if we get better at handling things like `lang=zh-Hant`, not
    605      // just resolving based on the Unicode text.
    606    case Script::TRADITIONAL_HAN:
    607    case Script::TRADITIONAL_HAN_WITH_LATIN:
    608      aFontList.AppendElement("MingLiU");
    609      if (aCh > 0xFFFF) {
    610        aFontList.AppendElement("MingLiU-ExtB");
    611      }
    612      break;
    613    case Script::HIRAGANA:
    614    case Script::KATAKANA:
    615    case Script::KATAKANA_OR_HIRAGANA:
    616    case Script::JAPANESE:
    617      aFontList.AppendElement("Yu Gothic");
    618      aFontList.AppendElement("MS PGothic");
    619      break;
    620    case Script::HANGUL:
    621    case Script::JAMO:
    622    case Script::KOREAN:
    623      aFontList.AppendElement("Malgun Gothic");
    624      break;
    625 
    626    case Script::YI:
    627      aFontList.AppendElement("Microsoft Yi Baiti");
    628      break;
    629    case Script::MONGOLIAN:
    630      aFontList.AppendElement("Mongolian Baiti");
    631      break;
    632    case Script::TIBETAN:
    633      aFontList.AppendElement("Microsoft Himalaya");
    634      break;
    635    case Script::PHAGS_PA:
    636      aFontList.AppendElement("Microsoft PhagsPa");
    637      break;
    638 
    639    case Script::ARABIC:
    640      // Default to Arial (added unconditionally below) for Arabic script.
    641      break;
    642    case Script::ARABIC_NASTALIQ:
    643      aFontList.AppendElement("Urdu Typesetting");
    644      break;
    645    case Script::SYRIAC:
    646    case Script::ESTRANGELO_SYRIAC:
    647      aFontList.AppendElement("Estrangelo Edessa");
    648      break;
    649    case Script::THAANA:
    650      aFontList.AppendElement("MV Boli");
    651      break;
    652 
    653    case Script::BENGALI:
    654      aFontList.AppendElement("Vrinda");
    655      aFontList.AppendElement("Nirmala UI");
    656      break;
    657    case Script::DEVANAGARI:
    658      aFontList.AppendElement("Kokila");
    659      aFontList.AppendElement("Nirmala UI");
    660      break;
    661    case Script::GUJARATI:
    662      aFontList.AppendElement("Shruti");
    663      aFontList.AppendElement("Nirmala UI");
    664      break;
    665    case Script::GURMUKHI:
    666      aFontList.AppendElement("Raavi");
    667      aFontList.AppendElement("Nirmala UI");
    668      break;
    669    case Script::KANNADA:
    670      aFontList.AppendElement("Tunga");
    671      aFontList.AppendElement("Nirmala UI");
    672      break;
    673    case Script::MALAYALAM:
    674      aFontList.AppendElement("Kartika");
    675      aFontList.AppendElement("Nirmala UI");
    676      break;
    677    case Script::ORIYA:
    678      aFontList.AppendElement("Kalinga");
    679      aFontList.AppendElement("Nirmala UI");
    680      break;
    681    case Script::TAMIL:
    682      aFontList.AppendElement("Latha");
    683      aFontList.AppendElement("Nirmala UI");
    684      break;
    685    case Script::TELUGU:
    686      aFontList.AppendElement("Gautami");
    687      aFontList.AppendElement("Nirmala UI");
    688      break;
    689    case Script::SINHALA:
    690      aFontList.AppendElement("Iskoola Pota");
    691      aFontList.AppendElement("Nirmala UI");
    692      break;
    693 
    694    case Script::CHAKMA:
    695    case Script::MEETEI_MAYEK:
    696    case Script::OL_CHIKI:
    697    case Script::SORA_SOMPENG:
    698      aFontList.AppendElement("Nirmala UI");
    699      break;
    700 
    701    case Script::MYANMAR:
    702      aFontList.AppendElement("Myanmar Text");
    703      break;
    704    case Script::KHMER:
    705      aFontList.AppendElement("Khmer UI");
    706      break;
    707    case Script::LAO:
    708      aFontList.AppendElement("Lao UI");
    709      break;
    710    case Script::THAI:
    711      aFontList.AppendElement("Tahoma");
    712      aFontList.AppendElement("Leelawadee UI");
    713      break;
    714    case Script::TAI_LE:
    715      aFontList.AppendElement("Microsoft Tai Le");
    716      break;
    717    case Script::BUGINESE:
    718      aFontList.AppendElement("Leelawadee UI");
    719      break;
    720    case Script::NEW_TAI_LUE:
    721      aFontList.AppendElement("Microsoft New Tai Lue");
    722      break;
    723    case Script::JAVANESE:
    724      aFontList.AppendElement("Javanese Text");
    725      break;
    726 
    727    case Script::GEORGIAN:
    728    case Script::KHUTSURI:
    729    case Script::LISU:
    730      aFontList.AppendElement("Segoe UI");
    731      break;
    732 
    733    case Script::ETHIOPIC:
    734      aFontList.AppendElement("Nyala");
    735      aFontList.AppendElement("Ebrima");
    736      break;
    737 
    738    case Script::ADLAM:
    739    case Script::NKO:
    740    case Script::OSMANYA:
    741    case Script::TIFINAGH:
    742    case Script::VAI:
    743      aFontList.AppendElement("Ebrima");
    744      break;
    745 
    746    case Script::CANADIAN_ABORIGINAL:
    747      aFontList.AppendElement("Euphemia");
    748      break;
    749 
    750    case Script::CHEROKEE:
    751    case Script::OSAGE:
    752      aFontList.AppendElement("Gadugi");
    753      break;
    754 
    755    case Script::BRAILLE:
    756    case Script::DESERET:
    757      aFontList.AppendElement("Segoe UI Symbol");
    758      break;
    759 
    760    case Script::BRAHMI:
    761    case Script::CARIAN:
    762    case Script::CUNEIFORM:
    763    case Script::CYPRIOT:
    764    case Script::EGYPTIAN_HIEROGLYPHS:
    765    case Script::GLAGOLITIC:
    766    case Script::GOTHIC:
    767    case Script::IMPERIAL_ARAMAIC:
    768    case Script::INSCRIPTIONAL_PAHLAVI:
    769    case Script::INSCRIPTIONAL_PARTHIAN:
    770    case Script::KHAROSHTHI:
    771    case Script::LYCIAN:
    772    case Script::LYDIAN:
    773    case Script::MEROITIC_CURSIVE:
    774    case Script::OGHAM:
    775    case Script::OLD_ITALIC:
    776    case Script::OLD_PERSIAN:
    777    case Script::OLD_SOUTH_ARABIAN:
    778    case Script::OLD_TURKIC:
    779    case Script::PHOENICIAN:
    780    case Script::RUNIC:
    781    case Script::SHAVIAN:
    782    case Script::UGARITIC:
    783      aFontList.AppendElement("Segoe UI Historic");
    784      break;
    785 
    786      // For some scripts where Windows doesn't supply a font by default,
    787      // there are Noto fonts that users might have installed:
    788    case Script::AHOM:
    789      aFontList.AppendElement("Noto Serif Ahom");
    790      break;
    791    case Script::AVESTAN:
    792      aFontList.AppendElement("Noto Sans Avestan");
    793      break;
    794    case Script::BALINESE:
    795      aFontList.AppendElement("Noto Sans Balinese");
    796      break;
    797    case Script::BAMUM:
    798      aFontList.AppendElement("Noto Sans Bamum");
    799      break;
    800    case Script::BASSA_VAH:
    801      aFontList.AppendElement("Noto Sans Bassa Vah");
    802      break;
    803    case Script::BATAK:
    804      aFontList.AppendElement("Noto Sans Batak");
    805      break;
    806    case Script::BHAIKSUKI:
    807      aFontList.AppendElement("Noto Sans Bhaiksuki");
    808      break;
    809    case Script::BUHID:
    810      aFontList.AppendElement("Noto Sans Buhid");
    811      break;
    812    case Script::CAUCASIAN_ALBANIAN:
    813      aFontList.AppendElement("Noto Sans Caucasian Albanian");
    814      break;
    815    case Script::CHAM:
    816      aFontList.AppendElement("Noto Sans Cham");
    817      break;
    818    case Script::COPTIC:
    819      aFontList.AppendElement("Noto Sans Coptic");
    820      break;
    821    case Script::DUPLOYAN:
    822      aFontList.AppendElement("Noto Sans Duployan");
    823      break;
    824    case Script::ELBASAN:
    825      aFontList.AppendElement("Noto Sans Elbasan");
    826      break;
    827    case Script::GRANTHA:
    828      aFontList.AppendElement("Noto Sans Grantha");
    829      break;
    830    case Script::HANIFI_ROHINGYA:
    831      aFontList.AppendElement("Noto Sans Hanifi Rohingya");
    832      break;
    833    case Script::HANUNOO:
    834      aFontList.AppendElement("Noto Sans Hanunoo");
    835      break;
    836    case Script::HATRAN:
    837      aFontList.AppendElement("Noto Sans Hatran");
    838      break;
    839    case Script::KAITHI:
    840      aFontList.AppendElement("Noto Sans Kaithi");
    841      break;
    842    case Script::KAYAH_LI:
    843      aFontList.AppendElement("Noto Sans Kayah Li");
    844      break;
    845    case Script::KHOJKI:
    846      aFontList.AppendElement("Noto Sans Khojki");
    847      break;
    848    case Script::KHUDAWADI:
    849      aFontList.AppendElement("Noto Sans Khudawadi");
    850      break;
    851    case Script::LEPCHA:
    852      aFontList.AppendElement("Noto Sans Lepcha");
    853      break;
    854    case Script::LIMBU:
    855      aFontList.AppendElement("Noto Sans Limbu");
    856      break;
    857    case Script::LINEAR_A:
    858      aFontList.AppendElement("Noto Sans Linear A");
    859      break;
    860    case Script::LINEAR_B:
    861      aFontList.AppendElement("Noto Sans Linear B");
    862      break;
    863    case Script::MAHAJANI:
    864      aFontList.AppendElement("Noto Sans Mahajani");
    865      break;
    866    case Script::MANDAIC:
    867      aFontList.AppendElement("Noto Sans Mandaic");
    868      break;
    869    case Script::MANICHAEAN:
    870      aFontList.AppendElement("Noto Sans Manichaean");
    871      break;
    872    case Script::MARCHEN:
    873      aFontList.AppendElement("Noto Sans Marchen");
    874      break;
    875    case Script::MENDE_KIKAKUI:
    876      aFontList.AppendElement("Noto Sans Mende Kikakui");
    877      break;
    878    case Script::MEROITIC_HIEROGLYPHS:
    879      aFontList.AppendElement("Noto Sans Meroitic");
    880      break;
    881    case Script::MIAO:
    882      aFontList.AppendElement("Noto Sans Miao");
    883      break;
    884    case Script::MODI:
    885      aFontList.AppendElement("Noto Sans Modi");
    886      break;
    887    case Script::MRO:
    888      aFontList.AppendElement("Noto Sans Mro");
    889      break;
    890    case Script::MULTANI:
    891      aFontList.AppendElement("Noto Sans Multani");
    892      break;
    893    case Script::NABATAEAN:
    894      aFontList.AppendElement("Noto Sans Nabataean");
    895      break;
    896    case Script::NEWA:
    897      aFontList.AppendElement("Noto Sans Newa");
    898      break;
    899    case Script::OLD_HUNGARIAN:
    900      aFontList.AppendElement("Noto Sans Old Hungarian");
    901      break;
    902    case Script::OLD_NORTH_ARABIAN:
    903      aFontList.AppendElement("Noto Sans Old North Arabian");
    904      break;
    905    case Script::OLD_PERMIC:
    906      aFontList.AppendElement("Noto Sans Old Permic");
    907      break;
    908    case Script::PAHAWH_HMONG:
    909      aFontList.AppendElement("Noto Sans Pahawh Hmong");
    910      break;
    911    case Script::PALMYRENE:
    912      aFontList.AppendElement("Noto Sans Palmyrene");
    913      break;
    914    case Script::PAU_CIN_HAU:
    915      aFontList.AppendElement("Noto Sans Pau Cin Hau");
    916      break;
    917    case Script::PSALTER_PAHLAVI:
    918      aFontList.AppendElement("Noto Sans Psalter Pahlavi");
    919      break;
    920    case Script::REJANG:
    921      aFontList.AppendElement("Noto Sans Rejang");
    922      break;
    923    case Script::SAMARITAN:
    924      aFontList.AppendElement("Noto Sans Samaritan");
    925      break;
    926    case Script::SAURASHTRA:
    927      aFontList.AppendElement("Noto Sans Saurashtra");
    928      break;
    929    case Script::SHARADA:
    930      aFontList.AppendElement("Noto Sans Sharada");
    931      break;
    932    case Script::SIDDHAM:
    933      aFontList.AppendElement("Noto Sans Siddham");
    934      break;
    935    case Script::SUNDANESE:
    936      aFontList.AppendElement("Noto Sans Sundanese");
    937      break;
    938    case Script::SYLOTI_NAGRI:
    939      aFontList.AppendElement("Noto Sans Syloti Nagri");
    940      break;
    941    case Script::TAGALOG:
    942      aFontList.AppendElement("Noto Sans Tagalog");
    943      break;
    944    case Script::TAGBANWA:
    945      aFontList.AppendElement("Noto Sans Tagbanwa");
    946      break;
    947    case Script::TAI_THAM:
    948      aFontList.AppendElement("Noto Sans Tai Tham");
    949      break;
    950    case Script::TAI_VIET:
    951      aFontList.AppendElement("Noto Sans Tai Viet");
    952      break;
    953    case Script::TAKRI:
    954      aFontList.AppendElement("Noto Sans Takri");
    955      break;
    956    case Script::TIRHUTA:
    957      aFontList.AppendElement("Noto Sans Tirhuta");
    958      break;
    959    case Script::WANCHO:
    960      aFontList.AppendElement("Noto Sans Wancho");
    961      break;
    962    case Script::WARANG_CITI:
    963      aFontList.AppendElement("Noto Sans Warang Citi");
    964      break;
    965 
    966    case Script::AFAKA:
    967    case Script::ANATOLIAN_HIEROGLYPHS:
    968    case Script::BERIA_ERFE:
    969    case Script::BLISSYMBOLS:
    970    case Script::BOOK_PAHLAVI:
    971    case Script::CHORASMIAN:
    972    case Script::CIRTH:
    973    case Script::CYPRO_MINOAN:
    974    case Script::DEMOTIC_EGYPTIAN:
    975    case Script::DIVES_AKURU:
    976    case Script::DOGRA:
    977    case Script::EASTERN_SYRIAC:
    978    case Script::ELYMAIC:
    979    case Script::GARAY:
    980    case Script::GUNJALA_GONDI:
    981    case Script::GURUNG_KHEMA:
    982    case Script::HARAPPAN_INDUS:
    983    case Script::HIERATIC_EGYPTIAN:
    984    case Script::JURCHEN:
    985    case Script::KAWI:
    986    case Script::KHITAN_SMALL_SCRIPT:
    987    case Script::KIRAT_RAI:
    988    case Script::KPELLE:
    989    case Script::LATIN_FRAKTUR:
    990    case Script::LATIN_GAELIC:
    991    case Script::LOMA:
    992    case Script::MAKASAR:
    993    case Script::MASARAM_GONDI:
    994    case Script::MAYAN_HIEROGLYPHS:
    995    case Script::MEDEFAIDRIN:
    996    case Script::MOON:
    997    case Script::NAG_MUNDARI:
    998    case Script::NAKHI_GEBA:
    999    case Script::NANDINAGARI:
   1000    case Script::NUSHU:
   1001    case Script::NYIAKENG_PUACHUE_HMONG:
   1002    case Script::OL_ONAL:
   1003    case Script::OLD_CHURCH_SLAVONIC_CYRILLIC:
   1004    case Script::OLD_SOGDIAN:
   1005    case Script::OLD_UYGHUR:
   1006    case Script::RONGORONGO:
   1007    case Script::SARATI:
   1008    case Script::SIDETIC:
   1009    case Script::SIGNWRITING:
   1010    case Script::SOGDIAN:
   1011    case Script::SOYOMBO:
   1012    case Script::SUNUWAR:
   1013    case Script::TAI_YO:
   1014    case Script::TANGSA:
   1015    case Script::TANGUT:
   1016    case Script::TENGWAR:
   1017    case Script::TODHRI:
   1018    case Script::TOLONG_SIKI:
   1019    case Script::TOTO:
   1020    case Script::TULU_TIGALARI:
   1021    case Script::UNKNOWN:
   1022    case Script::UNWRITTEN_LANGUAGES:
   1023    case Script::VISIBLE_SPEECH:
   1024    case Script::VITHKUQI:
   1025    case Script::WESTERN_SYRIAC:
   1026    case Script::WOLEAI:
   1027    case Script::YEZIDI:
   1028    case Script::ZANABAZAR_SQUARE:
   1029      break;
   1030  }
   1031 
   1032  // Arial is used as default fallback for system fallback, so always try that.
   1033  aFontList.AppendElement("Arial");
   1034 
   1035  // Symbols/dingbats are generally Script=COMMON but may be resolved to any
   1036  // surrounding script run. So we'll always append a couple of likely fonts
   1037  // for such characters.
   1038  const uint32_t b = aCh >> 8;
   1039  if (aRunScript == Script::COMMON ||  // Stray COMMON chars not resolved
   1040      (b >= 0x20 && b <= 0x2b) || b == 0x2e ||  // BMP symbols/punctuation/etc
   1041      GetGenCategory(aCh) == nsUGenCategory::kSymbol ||
   1042      GetGenCategory(aCh) == nsUGenCategory::kPunctuation) {
   1043    // Segoe UI handles some punctuation/symbols that are missing from many text
   1044    // fonts.
   1045    aFontList.AppendElement("Segoe UI");
   1046    aFontList.AppendElement("Segoe UI Symbol");
   1047    aFontList.AppendElement("Cambria Math");
   1048  }
   1049 
   1050  // Arial Unicode MS also has lots of glyphs for obscure characters; try it as
   1051  // a last resort, if available.
   1052  aFontList.AppendElement("Arial Unicode MS");
   1053 
   1054  // If we didn't begin with the color-emoji fonts, include them here
   1055  // so that they'll be preferred over user-installed (and possibly
   1056  // broken) fonts in the global fallback path.
   1057  if (!PrefersColor(aPresentation)) {
   1058    aFontList.AppendElement("Segoe UI Emoji");
   1059    aFontList.AppendElement("Twemoji Mozilla");
   1060  }
   1061 }
   1062 
   1063 bool gfxWindowsPlatform::DidRenderingDeviceReset(
   1064    mozilla::gfx::DeviceResetReason* aResetReason) {
   1065  DeviceManagerDx* dm = DeviceManagerDx::Get();
   1066  if (!dm) {
   1067    return false;
   1068  }
   1069  return dm->HasDeviceReset(aResetReason);
   1070 }
   1071 
   1072 void gfxWindowsPlatform::CompositorUpdated() {
   1073  DeviceManagerDx::Get()->ForceDeviceReset(
   1074      mozilla::gfx::ForcedDeviceResetReason::COMPOSITOR_UPDATED);
   1075  UpdateRenderMode();
   1076 }
   1077 
   1078 BOOL CALLBACK InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) {
   1079  RedrawWindow(aWnd, nullptr, nullptr,
   1080               RDW_INVALIDATE | RDW_INTERNALPAINT | RDW_FRAME);
   1081  return TRUE;
   1082 }
   1083 
   1084 void gfxWindowsPlatform::SchedulePaintIfDeviceReset() {
   1085  AUTO_PROFILER_LABEL("gfxWindowsPlatform::SchedulePaintIfDeviceReset", OTHER);
   1086 
   1087  mozilla::gfx::DeviceResetReason resetReason =
   1088      mozilla::gfx::DeviceResetReason::OK;
   1089  if (!DidRenderingDeviceReset(&resetReason)) {
   1090    return;
   1091  }
   1092 
   1093  gfxCriticalNote << "(gfxWindowsPlatform) Detected device reset: "
   1094                  << (int)resetReason;
   1095 
   1096  if (XRE_IsParentProcess()) {
   1097    // Trigger an ::OnPaint for each window.
   1098    ::EnumThreadWindows(GetCurrentThreadId(), InvalidateWindowForDeviceReset,
   1099                        0);
   1100  } else {
   1101    NS_DispatchToMainThread(NS_NewRunnableFunction(
   1102        "gfx::gfxWindowsPlatform::SchedulePaintIfDeviceReset", []() -> void {
   1103          gfxWindowsPlatform::GetPlatform()->CheckForContentOnlyDeviceReset();
   1104        }));
   1105  }
   1106 
   1107  gfxCriticalNote << "(gfxWindowsPlatform) scheduled device update.";
   1108 }
   1109 
   1110 void gfxWindowsPlatform::CheckForContentOnlyDeviceReset() {
   1111  if (!DidRenderingDeviceReset()) {
   1112    return;
   1113  }
   1114 
   1115  bool isContentOnlyTDR;
   1116  D3D11DeviceStatus status;
   1117 
   1118  DeviceManagerDx::Get()->ExportDeviceInfo(&status);
   1119  CompositorBridgeChild::Get()->SendCheckContentOnlyTDR(status.sequenceNumber(),
   1120                                                        &isContentOnlyTDR);
   1121 
   1122  // The parent process doesn't know about the reset yet, or the reset is
   1123  // local to our device.
   1124  if (isContentOnlyTDR) {
   1125    gfxCriticalNote << "A content-only TDR is detected.";
   1126    dom::ContentChild* cc = dom::ContentChild::GetSingleton();
   1127    cc->RecvReinitRenderingForDeviceReset();
   1128  }
   1129 }
   1130 
   1131 nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData() {
   1132  if (XRE_IsContentProcess()) {
   1133    auto& cmsOutputProfileData = GetCMSOutputProfileData();
   1134    // We should have set our profile data when we received our initial
   1135    // ContentDeviceData.
   1136    MOZ_ASSERT(cmsOutputProfileData.isSome(),
   1137               "Should have created output profile data when we received "
   1138               "initial content device data.");
   1139 
   1140    // If we have data, it should not be empty.
   1141    MOZ_ASSERT_IF(cmsOutputProfileData.isSome(),
   1142                  !cmsOutputProfileData->IsEmpty());
   1143 
   1144    if (cmsOutputProfileData.isSome()) {
   1145      return cmsOutputProfileData.ref().Clone();
   1146    }
   1147    return nsTArray<uint8_t>();
   1148  }
   1149 
   1150  return GetPlatformCMSOutputProfileData_Impl();
   1151 }
   1152 
   1153 nsTArray<uint8_t> gfxWindowsPlatform::GetPlatformCMSOutputProfileData_Impl() {
   1154  static nsTArray<uint8_t> sCached = [&] {
   1155    // Check override pref first:
   1156    nsTArray<uint8_t> prefProfileData =
   1157        gfxPlatform::GetPrefCMSOutputProfileData();
   1158    if (!prefProfileData.IsEmpty()) {
   1159      return prefProfileData;
   1160    }
   1161 
   1162    // -
   1163    // Otherwise, create a dummy DC and pull from that.
   1164 
   1165    HDC dc = ::GetDC(nullptr);
   1166    if (!dc) {
   1167      return nsTArray<uint8_t>();
   1168    }
   1169 
   1170    WCHAR profilePath[MAX_PATH];
   1171    DWORD profilePathLen = MAX_PATH;
   1172 
   1173    bool getProfileResult = ::GetICMProfileW(dc, &profilePathLen, profilePath);
   1174 
   1175    ::ReleaseDC(nullptr, dc);
   1176 
   1177    if (!getProfileResult) {
   1178      return nsTArray<uint8_t>();
   1179    }
   1180 
   1181    void* mem = nullptr;
   1182    size_t size = 0;
   1183 
   1184    qcms_data_from_unicode_path(profilePath, &mem, &size);
   1185    if (!mem) {
   1186      return nsTArray<uint8_t>();
   1187    }
   1188 
   1189    nsTArray<uint8_t> result;
   1190    result.AppendElements(static_cast<uint8_t*>(mem), size);
   1191 
   1192    free(mem);
   1193 
   1194    return result;
   1195  }();
   1196 
   1197  return sCached.Clone();
   1198 }
   1199 
   1200 void gfxWindowsPlatform::GetDLLVersion(char16ptr_t aDLLPath,
   1201                                       nsAString& aVersion) {
   1202  DWORD versInfoSize, vers[4] = {0};
   1203  // version info not available case
   1204  aVersion.AssignLiteral(u"0.0.0.0");
   1205  versInfoSize = GetFileVersionInfoSizeW(aDLLPath, nullptr);
   1206  AutoTArray<BYTE, 512> versionInfo;
   1207 
   1208  if (versInfoSize == 0) {
   1209    return;
   1210  }
   1211 
   1212  // XXX(Bug 1631371) Check if this should use a fallible operation as it
   1213  // pretended earlier.
   1214  versionInfo.AppendElements(uint32_t(versInfoSize));
   1215 
   1216  if (!GetFileVersionInfoW(aDLLPath, 0, versInfoSize,
   1217                           LPBYTE(versionInfo.Elements()))) {
   1218    return;
   1219  }
   1220 
   1221  UINT len = 0;
   1222  VS_FIXEDFILEINFO* fileInfo = nullptr;
   1223  if (!VerQueryValue(LPBYTE(versionInfo.Elements()), TEXT("\\"),
   1224                     (LPVOID*)&fileInfo, &len) ||
   1225      len == 0 || fileInfo == nullptr) {
   1226    return;
   1227  }
   1228 
   1229  DWORD fileVersMS = fileInfo->dwFileVersionMS;
   1230  DWORD fileVersLS = fileInfo->dwFileVersionLS;
   1231 
   1232  vers[0] = HIWORD(fileVersMS);
   1233  vers[1] = LOWORD(fileVersMS);
   1234  vers[2] = HIWORD(fileVersLS);
   1235  vers[3] = LOWORD(fileVersLS);
   1236 
   1237  char buf[256];
   1238  SprintfLiteral(buf, "%lu.%lu.%lu.%lu", vers[0], vers[1], vers[2], vers[3]);
   1239  aVersion.Assign(NS_ConvertUTF8toUTF16(buf));
   1240 }
   1241 
   1242 static BOOL CALLBACK AppendClearTypeParams(HMONITOR aMonitor, HDC, LPRECT,
   1243                                           LPARAM aContext) {
   1244  MONITORINFOEXW monitorInfo;
   1245  monitorInfo.cbSize = sizeof(MONITORINFOEXW);
   1246  if (!GetMonitorInfoW(aMonitor, &monitorInfo)) {
   1247    return TRUE;
   1248  }
   1249 
   1250  ClearTypeParameterInfo ctinfo;
   1251  ctinfo.displayName.Assign(monitorInfo.szDevice);
   1252 
   1253  RefPtr<IDWriteRenderingParams> renderingParams;
   1254  HRESULT hr = Factory::GetDWriteFactory()->CreateMonitorRenderingParams(
   1255      aMonitor, getter_AddRefs(renderingParams));
   1256  if (FAILED(hr)) {
   1257    return TRUE;
   1258  }
   1259 
   1260  ctinfo.gamma = renderingParams->GetGamma() * 1000;
   1261  ctinfo.pixelStructure = renderingParams->GetPixelGeometry();
   1262  ctinfo.clearTypeLevel = renderingParams->GetClearTypeLevel() * 100;
   1263  ctinfo.enhancedContrast = renderingParams->GetEnhancedContrast() * 100;
   1264 
   1265  auto* params = reinterpret_cast<nsTArray<ClearTypeParameterInfo>*>(aContext);
   1266  params->AppendElement(ctinfo);
   1267  return TRUE;
   1268 }
   1269 
   1270 void gfxWindowsPlatform::GetCleartypeParams(
   1271    nsTArray<ClearTypeParameterInfo>& aParams) {
   1272  aParams.Clear();
   1273  if (!DWriteEnabled()) {
   1274    return;
   1275  }
   1276  EnumDisplayMonitors(nullptr, nullptr, AppendClearTypeParams,
   1277                      reinterpret_cast<LPARAM>(&aParams));
   1278 }
   1279 
   1280 void gfxWindowsPlatform::FontsPrefsChanged(const char* aPref) {
   1281  bool clearTextFontCaches = true;
   1282 
   1283  gfxPlatform::FontsPrefsChanged(aPref);
   1284 
   1285  if (aPref &&
   1286      !strncmp(GFX_CLEARTYPE_PARAMS, aPref, strlen(GFX_CLEARTYPE_PARAMS))) {
   1287    gfxDWriteFont::UpdateClearTypeVars();
   1288  } else {
   1289    clearTextFontCaches = false;
   1290  }
   1291 
   1292  if (clearTextFontCaches) {
   1293    gfxFontCache* fc = gfxFontCache::GetCache();
   1294    if (fc) {
   1295      fc->Flush();
   1296    }
   1297  }
   1298 }
   1299 
   1300 bool gfxWindowsPlatform::IsOptimus() {
   1301  static int knowIsOptimus = -1;
   1302  if (knowIsOptimus == -1) {
   1303    // other potential optimus -- nvd3d9wrapx.dll & nvdxgiwrap.dll
   1304    if (GetModuleHandleA("nvumdshim.dll") ||
   1305        GetModuleHandleA("nvumdshimx.dll")) {
   1306      knowIsOptimus = 1;
   1307    } else {
   1308      knowIsOptimus = 0;
   1309    }
   1310  }
   1311  return knowIsOptimus;
   1312 }
   1313 
   1314 static void InitializeANGLEConfig() {
   1315  FeatureState& d3d11ANGLE = gfxConfig::GetFeature(Feature::D3D11_HW_ANGLE);
   1316 
   1317  if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
   1318    d3d11ANGLE.DisableByDefault(FeatureStatus::Unavailable,
   1319                                "D3D11 compositing is disabled",
   1320                                "FEATURE_FAILURE_HW_ANGLE_D3D11_DISABLED"_ns);
   1321    return;
   1322  }
   1323 
   1324  d3d11ANGLE.EnableByDefault();
   1325 
   1326  nsCString message;
   1327  nsCString failureId;
   1328  if (!gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_ANGLE,
   1329                                        &message, failureId)) {
   1330    d3d11ANGLE.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   1331  }
   1332 }
   1333 
   1334 void gfxWindowsPlatform::InitializeDirectDrawConfig() {
   1335  MOZ_ASSERT(XRE_IsParentProcess());
   1336 
   1337  FeatureState& ddraw = gfxConfig::GetFeature(Feature::DIRECT_DRAW);
   1338  ddraw.EnableByDefault();
   1339 }
   1340 
   1341 void gfxWindowsPlatform::InitializeConfig() {
   1342  if (XRE_IsParentProcess()) {
   1343    // The parent process first determines which features can be attempted.
   1344    // This information is relayed to content processes and the GPU process.
   1345    InitializeD3D11Config();
   1346    InitializeANGLEConfig();
   1347  } else {
   1348    ImportCachedContentDeviceData();
   1349    InitializeANGLEConfig();
   1350  }
   1351 }
   1352 
   1353 void gfxWindowsPlatform::InitializeD3D11Config() {
   1354  MOZ_ASSERT(XRE_IsParentProcess());
   1355 
   1356  FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
   1357 
   1358  if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
   1359    d3d11.DisableByDefault(FeatureStatus::Unavailable,
   1360                           "Hardware compositing is disabled",
   1361                           "FEATURE_FAILURE_D3D11_NEED_HWCOMP"_ns);
   1362    return;
   1363  }
   1364 
   1365  d3d11.EnableByDefault();
   1366 
   1367  // Check if the user really, really wants WARP.
   1368  if (StaticPrefs::layers_d3d11_force_warp_AtStartup()) {
   1369    // Force D3D11 on even if we disabled it.
   1370    d3d11.UserForceEnable("User force-enabled WARP");
   1371  }
   1372 
   1373  nsCString message;
   1374  nsCString failureId;
   1375  if (StaticPrefs::layers_d3d11_enable_blacklist_AtStartup() &&
   1376      !gfxPlatform::IsGfxInfoStatusOkay(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS,
   1377                                        &message, failureId)) {
   1378    d3d11.Disable(FeatureStatus::Blocklisted, message.get(), failureId);
   1379  }
   1380 }
   1381 
   1382 /* static */
   1383 void gfxWindowsPlatform::RecordContentDeviceFailure(
   1384    TelemetryDeviceCode aDevice) {
   1385  // If the parent process fails to acquire a device, we record this
   1386  // normally as part of the environment. The exceptional case we're
   1387  // looking for here is when the parent process successfully acquires
   1388  // a device, but the content process fails to acquire the same device.
   1389  // This would not normally be displayed in about:support.
   1390  if (!XRE_IsContentProcess()) {
   1391    return;
   1392  }
   1393  glean::gfx::content_failed_to_acquire_device.AccumulateSingleSample(
   1394      uint32_t(aDevice));
   1395 }
   1396 
   1397 void gfxWindowsPlatform::RecordStartupTelemetry() {
   1398  if (!XRE_IsParentProcess()) {
   1399    return;
   1400  }
   1401 
   1402  DeviceManagerDx* dx = DeviceManagerDx::Get();
   1403  nsTArray<DXGI_OUTPUT_DESC1> outputs = dx->EnumerateOutputs();
   1404 
   1405  uint32_t allSupportedColorSpaces = 0;
   1406  for (auto& output : outputs) {
   1407    uint32_t colorSpace = 1 << output.ColorSpace;
   1408    allSupportedColorSpaces |= colorSpace;
   1409  }
   1410 
   1411  glean::gfx_hdr::windows_display_colorspace_bitfield.Set(
   1412      allSupportedColorSpaces);
   1413 }
   1414 
   1415 // Supports lazy device initialization on Windows, so that WebRender can avoid
   1416 // initializing GPU state and allocating swap chains for most non-GPU processes.
   1417 void gfxWindowsPlatform::EnsureDevicesInitialized() {
   1418  MOZ_DIAGNOSTIC_ASSERT(!IsWin32kLockedDown());
   1419 
   1420  if (!mInitializedDevices) {
   1421    mInitializedDevices = true;
   1422    InitializeDevices();
   1423    UpdateBackendPrefs();
   1424  }
   1425 }
   1426 
   1427 bool gfxWindowsPlatform::DevicesInitialized() { return mInitializedDevices; }
   1428 
   1429 void gfxWindowsPlatform::InitializeDevices() {
   1430  MOZ_ASSERT(NS_IsMainThread());
   1431 
   1432  if (XRE_IsParentProcess()) {
   1433    // If we're the UI process, and the GPU process is enabled, then we don't
   1434    // initialize any DirectX devices. We do leave them enabled in gfxConfig
   1435    // though. If the GPU process fails to create these devices it will send
   1436    // a message back and we'll update their status.
   1437    if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
   1438      return;
   1439    }
   1440 
   1441    // No GPU process, continue initializing devices as normal.
   1442  }
   1443 
   1444  // If acceleration is disabled, we refuse to initialize anything.
   1445  if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
   1446    return;
   1447  }
   1448 
   1449  // If we previously crashed initializing devices, bail out now.
   1450  D3D11LayersCrashGuard detectCrashes;
   1451  if (detectCrashes.Crashed()) {
   1452    gfxConfig::SetFailed(Feature::HW_COMPOSITING,
   1453                         FeatureStatus::CrashedOnStartup,
   1454                         "Crashed during startup in a previous session");
   1455    gfxConfig::SetFailed(
   1456        Feature::D3D11_COMPOSITING, FeatureStatus::CrashedOnStartup,
   1457        "Harware acceleration crashed during startup in a previous session");
   1458    return;
   1459  }
   1460 
   1461  // First, initialize D3D11.
   1462  InitializeD3D11();
   1463 }
   1464 
   1465 void gfxWindowsPlatform::InitializeD3D11() {
   1466  // This function attempts to initialize our D3D11 devices, if the hardware
   1467  // is not blocklisted for D3D11 layers. This first attempt will try to create
   1468  // a hardware accelerated device. If this creation fails or the hardware is
   1469  // blocklisted, then this function will abort if WARP is disabled, causing us
   1470  // to fallback to Basic layers. If WARP is not disabled it will use a WARP
   1471  // device which should always be available on Windows 7 and higher.
   1472  if (!gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
   1473    return;
   1474  }
   1475 
   1476  DeviceManagerDx* dm = DeviceManagerDx::Get();
   1477  if (XRE_IsParentProcess()) {
   1478    if (!dm->CreateCompositorDevices()) {
   1479      return;
   1480    }
   1481  }
   1482 
   1483  dm->CreateContentDevices();
   1484 
   1485  // Content process failed to create the d3d11 device while parent process
   1486  // succeed.
   1487  if (XRE_IsContentProcess() &&
   1488      !gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
   1489    gfxCriticalError()
   1490        << "[D3D11] Failed to create the D3D11 device in content \
   1491                           process.";
   1492  }
   1493 }
   1494 
   1495 class D3DVsyncSource final : public VsyncSource {
   1496 public:
   1497  D3DVsyncSource()
   1498      : mPrevVsync(TimeStamp::Now()),
   1499        mVsyncEnabled(false),
   1500        mWaitVBlankMonitor(NULL) {
   1501    mVsyncThread = new base::Thread("WindowsVsyncThread");
   1502    MOZ_RELEASE_ASSERT(mVsyncThread->Start(),
   1503                       "GFX: Could not start Windows vsync thread");
   1504    SetVsyncRate();
   1505  }
   1506 
   1507  void SetVsyncRate() {
   1508    DWM_TIMING_INFO vblankTime;
   1509    // Make sure to init the cbSize, otherwise GetCompositionTiming will fail
   1510    vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
   1511    HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime);
   1512    if (SUCCEEDED(hr)) {
   1513      UNSIGNED_RATIO refreshRate = vblankTime.rateRefresh;
   1514      // We get the rate in hertz / time, but we want the rate in ms.
   1515      float rate =
   1516          ((float)refreshRate.uiDenominator / (float)refreshRate.uiNumerator) *
   1517          1000;
   1518      mVsyncRate = TimeDuration::FromMilliseconds(rate);
   1519    } else {
   1520      mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
   1521    }
   1522  }
   1523 
   1524  virtual void Shutdown() override {
   1525    MOZ_ASSERT(NS_IsMainThread());
   1526    DisableVsync();
   1527    mVsyncThread->Stop();
   1528    delete mVsyncThread;
   1529  }
   1530 
   1531  virtual void EnableVsync() override {
   1532    MOZ_ASSERT(NS_IsMainThread());
   1533    MOZ_ASSERT(mVsyncThread->IsRunning());
   1534    {  // scope lock
   1535      if (mVsyncEnabled) {
   1536        return;
   1537      }
   1538      mVsyncEnabled = true;
   1539    }
   1540 
   1541    mVsyncThread->message_loop()->PostTask(NewRunnableMethod(
   1542        "D3DVsyncSource::VBlankLoop", this, &D3DVsyncSource::VBlankLoop));
   1543  }
   1544 
   1545  virtual void DisableVsync() override {
   1546    MOZ_ASSERT(NS_IsMainThread());
   1547    MOZ_ASSERT(mVsyncThread->IsRunning());
   1548    if (!mVsyncEnabled) {
   1549      return;
   1550    }
   1551    mVsyncEnabled = false;
   1552  }
   1553 
   1554  virtual bool IsVsyncEnabled() override {
   1555    MOZ_ASSERT(NS_IsMainThread());
   1556    return mVsyncEnabled;
   1557  }
   1558 
   1559  virtual TimeDuration GetVsyncRate() override { return mVsyncRate; }
   1560 
   1561  void ScheduleSoftwareVsync(TimeStamp aVsyncTimestamp) {
   1562    MOZ_ASSERT(IsInVsyncThread());
   1563    NS_WARNING(
   1564        "DwmComposition dynamically disabled, falling back to software "
   1565        "timers");
   1566 
   1567    TimeStamp nextVsync = aVsyncTimestamp + mVsyncRate;
   1568    TimeDuration delay = nextVsync - TimeStamp::Now();
   1569    if (delay.ToMilliseconds() < 0) {
   1570      delay = mozilla::TimeDuration::FromMilliseconds(0);
   1571    }
   1572 
   1573    mVsyncThread->message_loop()->PostDelayedTask(
   1574        NewRunnableMethod("D3DVsyncSource::VBlankLoop", this,
   1575                          &D3DVsyncSource::VBlankLoop),
   1576        delay.ToMilliseconds());
   1577  }
   1578 
   1579  // Returns the timestamp for the just happened vsync
   1580  TimeStamp GetVBlankTime() {
   1581    TimeStamp vsync = TimeStamp::Now();
   1582    TimeStamp now = vsync;
   1583 
   1584    DWM_TIMING_INFO vblankTime;
   1585    // Make sure to init the cbSize, otherwise
   1586    // GetCompositionTiming will fail
   1587    vblankTime.cbSize = sizeof(DWM_TIMING_INFO);
   1588    HRESULT hr = DwmGetCompositionTimingInfo(0, &vblankTime);
   1589    if (!SUCCEEDED(hr)) {
   1590      return vsync;
   1591    }
   1592 
   1593    LARGE_INTEGER frequency;
   1594    QueryPerformanceFrequency(&frequency);
   1595 
   1596    LARGE_INTEGER qpcNow;
   1597    QueryPerformanceCounter(&qpcNow);
   1598 
   1599    const int microseconds = 1000000;
   1600    int64_t adjust = qpcNow.QuadPart - vblankTime.qpcVBlank;
   1601    int64_t usAdjust = (adjust * microseconds) / frequency.QuadPart;
   1602    vsync -= TimeDuration::FromMicroseconds((double)usAdjust);
   1603 
   1604    // On Windows 10 and on, DWMGetCompositionTimingInfo, mostly
   1605    // reports the upcoming vsync time, which is in the future.
   1606    // It can also sometimes report a vblank time in the past.
   1607    // Since large parts of Gecko assume TimeStamps can't be in future,
   1608    // use the previous vsync.
   1609 
   1610    // Windows 10 and Intel HD vsync timestamps are messy and
   1611    // all over the place once in a while. Most of the time,
   1612    // it reports the upcoming vsync. Sometimes, that upcoming
   1613    // vsync is in the past. Sometimes that upcoming vsync is before
   1614    // the previously seen vsync.
   1615    // In these error cases, normalize to Now();
   1616    if (vsync >= now) {
   1617      vsync = vsync - mVsyncRate;
   1618    }
   1619 
   1620    // On Windows 7 and 8, DwmFlush wakes up AFTER qpcVBlankTime
   1621    // from DWMGetCompositionTimingInfo. We can return the adjusted vsync.
   1622    if (vsync >= now) {
   1623      vsync = now;
   1624    }
   1625 
   1626    // Our vsync time is some time very far in the past, adjust to Now.
   1627    // 4 ms is arbitrary, so feel free to pick something else if this isn't
   1628    // working. See the comment above.
   1629    if ((now - vsync).ToMilliseconds() > 4.0) {
   1630      vsync = now;
   1631    }
   1632 
   1633    return vsync;
   1634  }
   1635 
   1636  void VBlankLoop() {
   1637    MOZ_ASSERT(IsInVsyncThread());
   1638    MOZ_ASSERT(sizeof(int64_t) == sizeof(QPC_TIME));
   1639 
   1640    TimeStamp vsync = TimeStamp::Now();
   1641    mPrevVsync = TimeStamp();
   1642    TimeStamp flushTime = TimeStamp::Now();
   1643    TimeDuration longVBlank = mVsyncRate * 2;
   1644 
   1645    for (;;) {
   1646      {  // scope lock
   1647        if (!mVsyncEnabled) return;
   1648      }
   1649 
   1650      // Large parts of gecko assume that the refresh driver timestamp
   1651      // must be <= Now() and cannot be in the future.
   1652      MOZ_ASSERT(vsync <= TimeStamp::Now());
   1653      NotifyVsync(vsync, vsync + mVsyncRate);
   1654 
   1655      HRESULT hr = E_FAIL;
   1656      if (!StaticPrefs::gfx_vsync_force_disable_waitforvblank()) {
   1657        UpdateVBlankOutput();
   1658        if (mWaitVBlankOutput) {
   1659          const TimeStamp vblank_begin_wait = TimeStamp::Now();
   1660          {
   1661            AUTO_PROFILER_THREAD_SLEEP;
   1662            AUTO_PROFILER_MARKER_UNTYPED("WaitForVBlank", GRAPHICS_VSync, {});
   1663            hr = mWaitVBlankOutput->WaitForVBlank();
   1664          }
   1665          if (SUCCEEDED(hr)) {
   1666            // vblank might return instantly when running headless,
   1667            // monitor powering off, etc.  Since we're on a dedicated
   1668            // thread, instant-return should not happen in the normal
   1669            // case, so catch any odd behavior with a time cutoff:
   1670            TimeDuration vblank_wait = TimeStamp::Now() - vblank_begin_wait;
   1671            if (vblank_wait.ToMilliseconds() < 1.0) {
   1672              hr = E_FAIL;  // fall back on old behavior
   1673            }
   1674          }
   1675        }
   1676      } else {
   1677        // To mitigate bug 1924932 we only want to use DwmFlush if WaitForVBlank
   1678        // is disabled, WaitForVBlank is the standard since Vista so we should
   1679        // probably remove this option entirely.
   1680        AUTO_PROFILER_MARKER_UNTYPED("DwmFlush", GRAPHICS_VSync, {});
   1681        hr = DwmFlush();
   1682      }
   1683      if (!SUCCEEDED(hr)) {
   1684        // DWMFlush isn't working, fallback to software vsync.
   1685        AUTO_PROFILER_MARKER_UNTYPED("SoftwareVsync", GRAPHICS_VSync, {});
   1686        ScheduleSoftwareVsync(TimeStamp::Now());
   1687        return;
   1688      }
   1689 
   1690      TimeStamp now = TimeStamp::Now();
   1691      TimeDuration flushDiff = now - flushTime;
   1692      flushTime = now;
   1693      if ((flushDiff > longVBlank) || mPrevVsync.IsNull()) {
   1694        // Our vblank took longer than 2 intervals, readjust our timestamps
   1695        PROFILER_MARKER_UNTYPED("LongVBlank", GRAPHICS_VSync);
   1696        vsync = GetVBlankTime();
   1697        mPrevVsync = vsync;
   1698      } else {
   1699        // Instead of giving the actual vsync time, a constant interval
   1700        // between vblanks instead of the noise generated via hardware
   1701        // is actually what we want. Most apps just care about the diff
   1702        // between vblanks to animate, so a clean constant interval is
   1703        // smoother.
   1704        vsync = mPrevVsync + mVsyncRate;
   1705        if (vsync > now) {
   1706          // DWMFlush woke up very early, so readjust our times again
   1707          PROFILER_MARKER_UNTYPED("EarlyWake", GRAPHICS_VSync);
   1708          vsync = GetVBlankTime();
   1709        }
   1710 
   1711        if (vsync <= mPrevVsync) {
   1712          PROFILER_MARKER_UNTYPED("TimeSteppedBack", GRAPHICS_VSync);
   1713          vsync = TimeStamp::Now();
   1714        }
   1715 
   1716        if ((now - vsync).ToMilliseconds() > 2.0) {
   1717          // Account for time drift here where vsync never quite catches up to
   1718          // Now and we'd fall ever so slightly further behind Now().
   1719          PROFILER_MARKER_UNTYPED("TimeFellBehind2ms", GRAPHICS_VSync);
   1720          vsync = GetVBlankTime();
   1721        }
   1722 
   1723        mPrevVsync = vsync;
   1724      }
   1725    }  // end for
   1726  }
   1727  virtual ~D3DVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); }
   1728 
   1729 private:
   1730  bool IsInVsyncThread() {
   1731    return mVsyncThread->thread_id() == PlatformThread::CurrentId();
   1732  }
   1733 
   1734  void UpdateVBlankOutput() {
   1735    HMONITOR primary_monitor =
   1736        MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);
   1737    if (primary_monitor == mWaitVBlankMonitor && mWaitVBlankOutput) {
   1738      return;
   1739    }
   1740 
   1741    mWaitVBlankMonitor = primary_monitor;
   1742 
   1743    RefPtr<IDXGIOutput> output = nullptr;
   1744    if (DeviceManagerDx* dx = DeviceManagerDx::Get()) {
   1745      if (dx->GetOutputFromMonitor(mWaitVBlankMonitor, &output)) {
   1746        mWaitVBlankOutput = output;
   1747        return;
   1748      }
   1749    }
   1750 
   1751    // failed to convert a monitor to an output so keep trying
   1752    mWaitVBlankOutput = nullptr;
   1753  }
   1754 
   1755  TimeStamp mPrevVsync;
   1756  base::Thread* mVsyncThread;
   1757  TimeDuration mVsyncRate;
   1758  Atomic<bool> mVsyncEnabled;
   1759 
   1760  HMONITOR mWaitVBlankMonitor;
   1761  RefPtr<IDXGIOutput> mWaitVBlankOutput;
   1762 };  // D3DVsyncSource
   1763 
   1764 already_AddRefed<mozilla::gfx::VsyncSource>
   1765 gfxWindowsPlatform::CreateGlobalHardwareVsyncSource() {
   1766  MOZ_RELEASE_ASSERT(NS_IsMainThread(), "GFX: Not in main thread.");
   1767 
   1768  RefPtr<VsyncSource> d3dVsyncSource = new D3DVsyncSource();
   1769  return d3dVsyncSource.forget();
   1770 }
   1771 
   1772 void gfxWindowsPlatform::ImportGPUDeviceData(
   1773    const mozilla::gfx::GPUDeviceData& aData) {
   1774  MOZ_ASSERT(XRE_IsParentProcess());
   1775 
   1776  gfxPlatform::ImportGPUDeviceData(aData);
   1777 
   1778  gfxConfig::ImportChange(Feature::D3D11_COMPOSITING, aData.d3d11Compositing());
   1779 
   1780  DeviceManagerDx* dm = DeviceManagerDx::Get();
   1781  if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
   1782    dm->ImportDeviceInfo(aData.gpuDevice().ref());
   1783  } else {
   1784    // There should be no devices, so this just takes away the device status.
   1785    dm->ResetDevices();
   1786  }
   1787 
   1788  // Hardware video decoding depends on d3d11 state, so update the cache.
   1789  InitHardwareVideoConfig();
   1790 
   1791  // For completeness (and messaging in about:support). Content recomputes this
   1792  // on its own, and we won't use ANGLE in the UI process if we're using a GPU
   1793  // process.
   1794  UpdateANGLEConfig();
   1795 }
   1796 
   1797 void gfxWindowsPlatform::ImportContentDeviceData(
   1798    const mozilla::gfx::ContentDeviceData& aData) {
   1799  MOZ_ASSERT(XRE_IsContentProcess());
   1800 
   1801  gfxPlatform::ImportContentDeviceData(aData);
   1802 
   1803  const DevicePrefs& prefs = aData.prefs();
   1804  gfxConfig::Inherit(Feature::D3D11_COMPOSITING, prefs.d3d11Compositing());
   1805 
   1806  if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
   1807    DeviceManagerDx* dm = DeviceManagerDx::Get();
   1808    dm->ImportDeviceInfo(aData.d3d11());
   1809  }
   1810 }
   1811 
   1812 void gfxWindowsPlatform::BuildContentDeviceData(ContentDeviceData* aOut) {
   1813 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
   1814  // D3D11_COMPOSITING may be updated by the GPU process in DeviceManagerDx.
   1815  if (auto* gpm = GPUProcessManager::Get()) {
   1816    MOZ_DIAGNOSTIC_ASSERT(gpm->IsGPUReady());
   1817  }
   1818 #endif
   1819 
   1820  // Check for device resets before giving back new graphics information.
   1821  UpdateRenderMode();
   1822 
   1823  gfxPlatform::BuildContentDeviceData(aOut);
   1824 
   1825  const FeatureState& d3d11 = gfxConfig::GetFeature(Feature::D3D11_COMPOSITING);
   1826  aOut->prefs().d3d11Compositing() = d3d11.GetValue();
   1827 
   1828  if (d3d11.IsEnabled()) {
   1829    DeviceManagerDx* dm = DeviceManagerDx::Get();
   1830    dm->ExportDeviceInfo(&aOut->d3d11());
   1831  }
   1832 
   1833  aOut->cmsOutputProfileData() =
   1834      gfxPlatform::GetPlatform()->GetPlatformCMSOutputProfileData();
   1835 }
   1836 
   1837 bool gfxWindowsPlatform::CheckVariationFontSupport() {
   1838  // Variation font support is only available on Fall Creators Update or later.
   1839  return IsWin10FallCreatorsUpdateOrLater();
   1840 }
   1841 
   1842 void gfxWindowsPlatform::GetPlatformDisplayInfo(
   1843    mozilla::widget::InfoObject& aObj) {
   1844  HwStretchingSupport stretch;
   1845  DeviceManagerDx::Get()->CheckHardwareStretchingSupport(stretch);
   1846 
   1847  nsPrintfCString stretchValue(
   1848      "both=%u window-only=%u full-screen-only=%u none=%u error=%u",
   1849      stretch.mBoth, stretch.mWindowOnly, stretch.mFullScreenOnly,
   1850      stretch.mNone, stretch.mError);
   1851  aObj.DefineProperty("HardwareStretching", stretchValue.get());
   1852 
   1853  ScaledResolutionSet scaled;
   1854  GetScaledResolutions(scaled);
   1855  if (scaled.IsEmpty()) {
   1856    return;
   1857  }
   1858 
   1859  aObj.DefineProperty("ScaledResolutionCount", scaled.Length());
   1860  for (size_t i = 0; i < scaled.Length(); ++i) {
   1861    auto& s = scaled[i];
   1862    nsPrintfCString name("ScaledResolution%zu", i);
   1863    nsPrintfCString value("source %dx%d, target %dx%d", s.first.width,
   1864                          s.first.height, s.second.width, s.second.height);
   1865    aObj.DefineProperty(name.get(), value.get());
   1866  }
   1867 }