From 8f132a9e95e9a09f3b4184dfd34f5230b7e4eb91 Mon Sep 17 00:00:00 2001 From: Brad Werth Date: Fri, 22 Mar 2024 00:55:47 +0000 Subject: [PATCH] Bug 1764201 Part 2: Make Gecko_MediaFeatures_VideoDynamicRange check per-screen HDR. r=emilio This makes all platforms report video-dynamic-range:high if the screen most closely associated with the document (according to the logic of nsDeviceContext::FindScreen) is HDR capable. This removes the LookAndFeel id for VideoDynamicRange, since it is only used by Gecko_MediaFeatures_VideoDynamicRange, which is being modified here to use the nsDeviceContext instead. It also removes gfxPlatform::supportsHDR and its implementations, as it is no longer used. Differential Revision: https://phabricator.services.mozilla.com/D203329 --- gfx/src/nsDeviceContext.cpp | 10 ++++ gfx/src/nsDeviceContext.h | 5 ++ gfx/thebes/gfxPlatform.cpp | 11 ++-- gfx/thebes/gfxPlatform.h | 2 - gfx/thebes/gfxPlatformMac.cpp | 21 -------- gfx/thebes/gfxPlatformMac.h | 2 - gfx/thebes/gfxWindowsPlatform.cpp | 51 +------------------ gfx/thebes/gfxWindowsPlatform.h | 6 --- layout/style/nsMediaFeatures.cpp | 12 +++-- modules/libpref/init/StaticPrefList.yaml | 10 ++++ .../nsUserCharacteristics.cpp | 4 +- widget/LookAndFeel.h | 1 - widget/cocoa/nsLookAndFeel.mm | 8 --- widget/nsXPLookAndFeel.cpp | 1 - 14 files changed, 42 insertions(+), 102 deletions(-) diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index 28b2c34652f1..2bb53010a8e9 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -208,6 +208,16 @@ uint16_t nsDeviceContext::GetScreenOrientationAngle() { return screen->GetOrientationAngle(); } +bool nsDeviceContext::GetScreenIsHDR() { + RefPtr screen = FindScreen(); + if (!screen) { + auto& screenManager = ScreenManager::GetSingleton(); + screen = screenManager.GetPrimaryScreen(); + MOZ_ASSERT(screen); + } + return screen->GetIsHDR(); +} + nsresult nsDeviceContext::GetDeviceSurfaceDimensions(nscoord& aWidth, nscoord& aHeight) { if (IsPrinterContext()) { diff --git a/gfx/src/nsDeviceContext.h b/gfx/src/nsDeviceContext.h index 5238c1f71da8..7bf7a6aee260 100644 --- a/gfx/src/nsDeviceContext.h +++ b/gfx/src/nsDeviceContext.h @@ -149,6 +149,11 @@ class nsDeviceContext final { */ uint16_t GetScreenOrientationAngle(); + /** + * Get the status of HDR support of the associated screen. + */ + bool GetScreenIsHDR(); + /** * Get the size of the displayable area of the output device * in app units. diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index c57564b0547b..da367c92aae1 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -1064,6 +1064,13 @@ void gfxPlatform::ReportTelemetry() { mozilla::glean::gfx_display::count.Set(screenCount); mozilla::glean::gfx_display::primary_height.Set(rect.Height()); mozilla::glean::gfx_display::primary_width.Set(rect.Width()); + + // Check if any screen known by screenManager supports HDR. + bool supportsHDR = false; + for (const auto& screen : screenManager.CurrentScreenList()) { + supportsHDR |= screen->GetIsHDR(); + } + Telemetry::ScalarSet(Telemetry::ScalarID::GFX_SUPPORTS_HDR, supportsHDR); } nsString adapterDesc; @@ -1120,10 +1127,6 @@ void gfxPlatform::ReportTelemetry() { NS_ConvertUTF16toUTF8(adapterDriverDate)); mozilla::glean::gfx_status::headless.Set(IsHeadless()); - - MOZ_ASSERT(gPlatform, "Need gPlatform to generate some telemetry."); - Telemetry::ScalarSet(Telemetry::ScalarID::GFX_SUPPORTS_HDR, - gPlatform->SupportsHDR()); } static bool IsFeatureSupported(long aFeature, bool aDefault) { diff --git a/gfx/thebes/gfxPlatform.h b/gfx/thebes/gfxPlatform.h index 5af6d77345a0..e882ca074584 100644 --- a/gfx/thebes/gfxPlatform.h +++ b/gfx/thebes/gfxPlatform.h @@ -811,8 +811,6 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener { static bool UseDesktopZoomingScrollbars(); - virtual bool SupportsHDR() { return false; } - protected: gfxPlatform(); virtual ~gfxPlatform(); diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index 091b0dff2891..5c99d389c8bb 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -965,27 +965,6 @@ gfxPlatformMac::CreateGlobalHardwareVsyncSource() { #endif } -bool gfxPlatformMac::SupportsHDR() { - // HDR has 3 requirements: - // 1) high peak brightness - // 2) high contrast ratio - // 3) color depth > 24 - if (GetScreenDepth() <= 24) { - return false; - } - -#ifdef MOZ_WIDGET_UIKIT - return false; -#elif defined(EARLY_BETA_OR_EARLIER) - // Screen is capable. Is the OS capable? - // More-or-less supported in Catalina. - return true; -#else - // Definitely supported in Big Sur. - return nsCocoaFeatures::OnBigSurOrLater(); -#endif -} - nsTArray gfxPlatformMac::GetPlatformCMSOutputProfileData() { nsTArray prefProfileData = GetPrefCMSOutputProfileData(); if (!prefProfileData.IsEmpty()) { diff --git a/gfx/thebes/gfxPlatformMac.h b/gfx/thebes/gfxPlatformMac.h index 29bbd7e877f7..00ab2c1ca864 100644 --- a/gfx/thebes/gfxPlatformMac.h +++ b/gfx/thebes/gfxPlatformMac.h @@ -76,8 +76,6 @@ class gfxPlatformMac : public gfxPlatform { static bool CheckVariationFontSupport(); - bool SupportsHDR() override; - protected: bool AccelerateLayersByDefault() override; diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 1e343f95845b..4554d487f4d7 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -259,8 +259,7 @@ class D3DSharedTexturesReporter final : public nsIMemoryReporter { NS_IMPL_ISUPPORTS(D3DSharedTexturesReporter, nsIMemoryReporter) -gfxWindowsPlatform::gfxWindowsPlatform() - : mRenderMode(RENDER_GDI), mSupportsHDR(false) { +gfxWindowsPlatform::gfxWindowsPlatform() : mRenderMode(RENDER_GDI) { // If win32k is locked down then we can't use COM STA and shouldn't need it. // Also, we won't be using any GPU memory in this process. if (!IsWin32kLockedDown()) { @@ -401,7 +400,6 @@ void gfxWindowsPlatform::InitAcceleration() { // CanUseHardwareVideoDecoding depends on DeviceManagerDx state, // so update the cached value now. UpdateCanUseHardwareVideoDecoding(); - UpdateSupportsHDR(); // Our ScreenHelperWin also depends on DeviceManagerDx state. if (XRE_IsParentProcess() && !gfxPlatform::IsHeadless()) { @@ -537,53 +535,6 @@ void gfxWindowsPlatform::UpdateRenderMode() { } } -void gfxWindowsPlatform::UpdateSupportsHDR() { - // TODO: This function crashes content processes, for reasons that are not - // obvious from the crash reports. For now, this function can only be executed - // by the parent process. Therefore SupportsHDR() will always return false for - // content processes, as noted in the header. - if (!XRE_IsParentProcess()) { - return; - } - - // Set mSupportsHDR to true if any of the DeviceManager outputs have a BT2020 - // colorspace with EOTF2084 gamma curve, this indicates the system is sending - // an HDR format to at least one monitor. The colorspace returned by DXGI is - // very vague - we only see DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020 for HDR - // and DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709 for SDR modes, even if the - // monitor is using something like YCbCr444 according to Settings - // (System -> Display Settings -> Advanced Display). To get more specific - // info we would need to query the DISPLAYCONFIG values in WinGDI. - // - // Note that the bit depth used to be checked here, but as of Windows 11 22H2, - // HDR is supported with 8bpc for lower bandwidth, where DWM converts to - // dithered RGB8 rather than RGB10, which doesn't really matter here. - // - // This only returns true if there is an HDR display connected at app start, - // if the user switches to HDR to watch a video, we won't know that here, and - // if no displays are connected we return false (e.g. if Windows Update - // restarted a laptop with its lid closed and no external displays, we will - // see zero outputs here when the app is restarted automatically). - // - // It would be better to track if HDR is ever used and report that telemetry - // so we know if HDR matters, not just when it is detected at app start. - // - // Further reading: - // https://learn.microsoft.com/en-us/windows/win32/direct3darticles/high-dynamic-range - // https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-displayconfig_sdr_white_level - DeviceManagerDx* dx = DeviceManagerDx::Get(); - nsTArray outputs = dx->EnumerateOutputs(); - - for (auto& output : outputs) { - if (output.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) { - mSupportsHDR = true; - return; - } - } - - mSupportsHDR = false; -} - mozilla::gfx::BackendType gfxWindowsPlatform::GetContentBackendFor( mozilla::layers::LayersBackend aLayers) { mozilla::gfx::BackendType defaultBackend = diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 0956a384b01f..12efaefc403b 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -193,9 +193,6 @@ class gfxWindowsPlatform final : public gfxPlatform { static bool CheckVariationFontSupport(); - // Always false for content processes. - bool SupportsHDR() override { return mSupportsHDR; } - protected: bool AccelerateLayersByDefault() override { return true; } @@ -214,10 +211,7 @@ class gfxWindowsPlatform final : public gfxPlatform { BackendPrefsData GetBackendPrefs() const override; - void UpdateSupportsHDR(); - RenderMode mRenderMode; - bool mSupportsHDR; private: void Init(); diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp index f888c127d442..fbdde4102dd7 100644 --- a/layout/style/nsMediaFeatures.cpp +++ b/layout/style/nsMediaFeatures.cpp @@ -336,18 +336,20 @@ StyleDynamicRange Gecko_MediaFeatures_DynamicRange(const Document* aDocument) { StyleDynamicRange Gecko_MediaFeatures_VideoDynamicRange( const Document* aDocument) { - if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSVideoDynamicRange)) { + if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSVideoDynamicRange) || + !StaticPrefs::layout_css_video_dynamic_range_allows_high()) { return StyleDynamicRange::Standard; } // video-dynamic-range: high has 3 requirements: // 1) high peak brightness // 2) high contrast ratio // 3) color depth > 24 - // We check the color depth requirement before asking the LookAndFeel - // if it is HDR capable. + + // As a proxy for those requirements, return 'High' if the screen associated + // with the device context claims to be HDR capable. if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) { - if (dx->GetDepth() > 24 && - LookAndFeel::GetInt(LookAndFeel::IntID::VideoDynamicRange)) { + if (dx->GetScreenIsHDR()) { + // bjw return StyleDynamicRange::High; } } diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 08387d9e7efb..40b8c7a373c4 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -9396,6 +9396,16 @@ mirror: always rust: true +# Is matching video-dynamic-range: high allowed? +- name: layout.css.video-dynamic-range.allows-high + type: RelaxedAtomicBool +#if defined(XP_MACOSX) || defined(NIGHTLY_BUILD) + value: true +#else + value: false +#endif + mirror: always + # Whether frame visibility tracking is enabled globally. - name: layout.framevisibility.enabled type: bool diff --git a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp index 8f69e9137779..e1ee97fc1105 100644 --- a/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp +++ b/toolkit/components/resistfingerprinting/nsUserCharacteristics.cpp @@ -57,8 +57,6 @@ int MaxTouchPoints() { // ================================================================== void PopulateCSSProperties() { - glean::characteristics::video_dynamic_range.Set( - LookAndFeel::GetInt(LookAndFeel::IntID::VideoDynamicRange)); glean::characteristics::prefers_reduced_transparency.Set( LookAndFeel::GetInt(LookAndFeel::IntID::PrefersReducedTransparency)); glean::characteristics::prefers_reduced_motion.Set( @@ -110,6 +108,8 @@ void PopulateScreenProperties() { const LayoutDeviceIntRect rect = screen->GetRect(); glean::characteristics::screen_height.Set(rect.Height()); glean::characteristics::screen_width.Set(rect.Width()); + + glean::characteristics::video_dynamic_range.Set(screen->GetIsHDR()); } void PopulateMissingFonts() { diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h index c9581f90af22..160575556c3e 100644 --- a/widget/LookAndFeel.h +++ b/widget/LookAndFeel.h @@ -300,7 +300,6 @@ class LookAndFeel { * 1: High */ DynamicRange, - VideoDynamicRange, /** Whether XUL panel animations are enabled. */ PanelAnimations, diff --git a/widget/cocoa/nsLookAndFeel.mm b/widget/cocoa/nsLookAndFeel.mm index 5675198ff2ef..957f898030cb 100644 --- a/widget/cocoa/nsLookAndFeel.mm +++ b/widget/cocoa/nsLookAndFeel.mm @@ -469,14 +469,6 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { aResult = NSWorkspace.sharedWorkspace .accessibilityDisplayShouldIncreaseContrast; break; - case IntID::VideoDynamicRange: { - // If the platform says it supports HDR, then we claim to support - // video-dynamic-range. - gfxPlatform* platform = gfxPlatform::GetPlatform(); - MOZ_ASSERT(platform); - aResult = platform->SupportsHDR(); - break; - } case IntID::PanelAnimations: aResult = 1; break; diff --git a/widget/nsXPLookAndFeel.cpp b/widget/nsXPLookAndFeel.cpp index e4739ca8deec..aea4d0902100 100644 --- a/widget/nsXPLookAndFeel.cpp +++ b/widget/nsXPLookAndFeel.cpp @@ -187,7 +187,6 @@ static const char sIntPrefs[][45] = { "ui.titlebarRadius", "ui.titlebarButtonSpacing", "ui.dynamicRange", - "ui.videoDynamicRange", "ui.panelAnimations", "ui.hideCursorWhileTyping", "ui.gtkThemeFamily",