forked from mirrors/gecko-dev
Bug 1764201 Part 1: Make widget::Screen track if the screen is HDR capable. r=geckoview-reviewers,ahale,m_kato
This duplicates existing HDR checks in gfxPlatformMac and gfxWindowsPlatform. A later part of this patch series will remove that redundant code, as it replaces calls to gfxPlatform functions with calls to ScreenManager functions. Differential Revision: https://phabricator.services.mozilla.com/D203670
This commit is contained in:
parent
72c98c7f24
commit
2f4d447f5f
11 changed files with 101 additions and 29 deletions
|
|
@ -114,6 +114,7 @@ struct ScreenDetails {
|
|||
ScreenOrientation orientation;
|
||||
uint16_t orientationAngle;
|
||||
bool isPseudoDisplay;
|
||||
bool isHDR;
|
||||
};
|
||||
|
||||
struct DimensionInfo
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@
|
|||
#include "mozilla/layers/DeviceAttachmentsD3D11.h"
|
||||
#include "mozilla/WindowsProcessMitigations.h"
|
||||
#include "D3D11Checks.h"
|
||||
#include "mozilla/ScreenHelperWin.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
|
@ -402,6 +403,11 @@ void gfxWindowsPlatform::InitAcceleration() {
|
|||
UpdateCanUseHardwareVideoDecoding();
|
||||
UpdateSupportsHDR();
|
||||
|
||||
// Our ScreenHelperWin also depends on DeviceManagerDx state.
|
||||
if (XRE_IsParentProcess() && !gfxPlatform::IsHeadless()) {
|
||||
ScreenHelperWin::RefreshScreens();
|
||||
}
|
||||
|
||||
RecordStartupTelemetry();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
|
|||
uint32_t aPixelDepth, uint32_t aColorDepth,
|
||||
uint32_t aRefreshRate, DesktopToLayoutDeviceScale aContentsScale,
|
||||
CSSToLayoutDeviceScale aDefaultCssScale, float aDPI,
|
||||
IsPseudoDisplay aIsPseudoDisplay,
|
||||
IsPseudoDisplay aIsPseudoDisplay, IsHDR aIsHDR,
|
||||
hal::ScreenOrientation aOrientation,
|
||||
OrientationAngle aOrientationAngle)
|
||||
: mRect(aRect),
|
||||
|
|
@ -45,7 +45,8 @@ Screen::Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
|
|||
mDPI(aDPI),
|
||||
mScreenOrientation(EffectiveOrientation(aOrientation, aRect)),
|
||||
mOrientationAngle(aOrientationAngle),
|
||||
mIsPseudoDisplay(aIsPseudoDisplay == IsPseudoDisplay::Yes) {}
|
||||
mIsPseudoDisplay(aIsPseudoDisplay == IsPseudoDisplay::Yes),
|
||||
mIsHDR(aIsHDR == IsHDR::Yes) {}
|
||||
|
||||
Screen::Screen(const dom::ScreenDetails& aScreen)
|
||||
: mRect(aScreen.rect()),
|
||||
|
|
@ -60,7 +61,8 @@ Screen::Screen(const dom::ScreenDetails& aScreen)
|
|||
mDPI(aScreen.dpi()),
|
||||
mScreenOrientation(aScreen.orientation()),
|
||||
mOrientationAngle(aScreen.orientationAngle()),
|
||||
mIsPseudoDisplay(aScreen.isPseudoDisplay()) {}
|
||||
mIsPseudoDisplay(aScreen.isPseudoDisplay()),
|
||||
mIsHDR(aScreen.isHDR()) {}
|
||||
|
||||
Screen::Screen(const Screen& aOther)
|
||||
: mRect(aOther.mRect),
|
||||
|
|
@ -75,13 +77,14 @@ Screen::Screen(const Screen& aOther)
|
|||
mDPI(aOther.mDPI),
|
||||
mScreenOrientation(aOther.mScreenOrientation),
|
||||
mOrientationAngle(aOther.mOrientationAngle),
|
||||
mIsPseudoDisplay(aOther.mIsPseudoDisplay) {}
|
||||
mIsPseudoDisplay(aOther.mIsPseudoDisplay),
|
||||
mIsHDR(aOther.mIsHDR) {}
|
||||
|
||||
dom::ScreenDetails Screen::ToScreenDetails() const {
|
||||
return dom::ScreenDetails(
|
||||
mRect, mRectDisplayPix, mAvailRect, mAvailRectDisplayPix, mPixelDepth,
|
||||
mColorDepth, mRefreshRate, mContentsScale, mDefaultCssScale, mDPI,
|
||||
mScreenOrientation, mOrientationAngle, mIsPseudoDisplay);
|
||||
mScreenOrientation, mOrientationAngle, mIsPseudoDisplay, mIsHDR);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
|||
|
|
@ -26,12 +26,13 @@ class Screen final : public nsIScreen {
|
|||
|
||||
using OrientationAngle = uint16_t;
|
||||
enum class IsPseudoDisplay : bool { No, Yes };
|
||||
enum class IsHDR : bool { No, Yes };
|
||||
|
||||
Screen(LayoutDeviceIntRect aRect, LayoutDeviceIntRect aAvailRect,
|
||||
uint32_t aPixelDepth, uint32_t aColorDepth, uint32_t aRefreshRate,
|
||||
DesktopToLayoutDeviceScale aContentsScale,
|
||||
CSSToLayoutDeviceScale aDefaultCssScale, float aDpi, IsPseudoDisplay,
|
||||
hal::ScreenOrientation = hal::ScreenOrientation::None,
|
||||
IsHDR, hal::ScreenOrientation = hal::ScreenOrientation::None,
|
||||
OrientationAngle = 0);
|
||||
explicit Screen(const dom::ScreenDetails& aScreenDetails);
|
||||
Screen(const Screen& aOther);
|
||||
|
|
@ -60,6 +61,8 @@ class Screen final : public nsIScreen {
|
|||
enum class IncludeOSZoom : bool { No, Yes };
|
||||
CSSToLayoutDeviceScale GetCSSToLayoutDeviceScale(IncludeOSZoom) const;
|
||||
|
||||
bool GetIsHDR() const { return mIsHDR; }
|
||||
|
||||
private:
|
||||
virtual ~Screen() = default;
|
||||
|
||||
|
|
@ -76,6 +79,7 @@ class Screen final : public nsIScreen {
|
|||
const hal::ScreenOrientation mScreenOrientation;
|
||||
const OrientationAngle mOrientationAngle;
|
||||
const bool mIsPseudoDisplay;
|
||||
const bool mIsHDR;
|
||||
};
|
||||
|
||||
} // namespace widget
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ already_AddRefed<Screen> ScreenManager::ScreenForRect(
|
|||
auto screen = MakeRefPtr<Screen>(
|
||||
LayoutDeviceIntRect(), LayoutDeviceIntRect(), 0, 0, 0,
|
||||
DesktopToLayoutDeviceScale(), CSSToLayoutDeviceScale(), 96 /* dpi */,
|
||||
Screen::IsPseudoDisplay::No, hal::ScreenOrientation::None, 0);
|
||||
Screen::IsPseudoDisplay::No, Screen::IsHDR::No,
|
||||
hal::ScreenOrientation::None, 0);
|
||||
return screen.forget();
|
||||
}
|
||||
|
||||
|
|
@ -219,10 +220,11 @@ already_AddRefed<Screen> ScreenManager::GetPrimaryScreen() {
|
|||
if (mScreenList.IsEmpty()) {
|
||||
MOZ_LOG(sScreenLog, LogLevel::Warning,
|
||||
("No screen available. This can happen in xpcshell."));
|
||||
return MakeAndAddRef<Screen>(
|
||||
LayoutDeviceIntRect(), LayoutDeviceIntRect(), 0, 0, 0,
|
||||
DesktopToLayoutDeviceScale(), CSSToLayoutDeviceScale(), 96 /* dpi */,
|
||||
Screen::IsPseudoDisplay::No, hal::ScreenOrientation::None, 0);
|
||||
return MakeAndAddRef<Screen>(LayoutDeviceIntRect(), LayoutDeviceIntRect(),
|
||||
0, 0, 0, DesktopToLayoutDeviceScale(),
|
||||
CSSToLayoutDeviceScale(), 96 /* dpi */,
|
||||
Screen::IsPseudoDisplay::No, Screen::IsHDR::No,
|
||||
hal::ScreenOrientation::None, 0);
|
||||
}
|
||||
|
||||
return do_AddRef(mScreenList[0]);
|
||||
|
|
|
|||
|
|
@ -38,14 +38,15 @@ static already_AddRefed<Screen> MakePrimaryScreen() {
|
|||
uint32_t depth = java::GeckoAppShell::GetScreenDepth();
|
||||
float density = java::GeckoAppShell::GetDensity();
|
||||
float dpi = java::GeckoAppShell::GetDpi();
|
||||
bool isHDR = false; // Bug 1884960: report this accurately
|
||||
auto orientation =
|
||||
hal::ScreenOrientation(java::GeckoAppShell::GetScreenOrientation());
|
||||
uint16_t angle = java::GeckoAppShell::GetScreenAngle();
|
||||
float refreshRate = java::GeckoAppShell::GetScreenRefreshRate();
|
||||
return MakeAndAddRef<Screen>(bounds, bounds, depth, depth, refreshRate,
|
||||
DesktopToLayoutDeviceScale(density),
|
||||
CSSToLayoutDeviceScale(1.0f), dpi,
|
||||
Screen::IsPseudoDisplay::No, orientation, angle);
|
||||
return MakeAndAddRef<Screen>(
|
||||
bounds, bounds, depth, depth, refreshRate,
|
||||
DesktopToLayoutDeviceScale(density), CSSToLayoutDeviceScale(1.0f), dpi,
|
||||
Screen::IsPseudoDisplay::No, Screen::IsHDR(isHDR), orientation, angle);
|
||||
}
|
||||
|
||||
ScreenHelperAndroid::ScreenHelperAndroid() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "nsCocoaUtils.h"
|
||||
#include "nsObjCExceptions.h"
|
||||
|
||||
|
|
@ -108,6 +109,13 @@ static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
|
|||
if (pixelDepth > MAX_REPORTED_PIXEL_DEPTH) {
|
||||
pixelDepth = MAX_REPORTED_PIXEL_DEPTH;
|
||||
}
|
||||
// Should we treat this as HDR? Based on spec at
|
||||
// https://drafts.csswg.org/mediaqueries-5/#dynamic-range, we'll consider it
|
||||
// HDR if it has pixel depth greater than 24.
|
||||
bool isHDR = pixelDepth > 24;
|
||||
|
||||
// Double-check HDR against the platform capabilities.
|
||||
isHDR &= nsCocoaFeatures::OnBigSurOrLater();
|
||||
|
||||
float dpi = 96.0f;
|
||||
CGDirectDisplayID displayID =
|
||||
|
|
@ -125,9 +133,10 @@ static already_AddRefed<Screen> MakeScreen(NSScreen* aScreen) {
|
|||
// Getting the refresh rate is a little hard on OS X. We could use
|
||||
// CVDisplayLinkGetNominalOutputVideoRefreshPeriod, but that's a little
|
||||
// involved. Ideally we could query it from vsync. For now, we leave it out.
|
||||
RefPtr<Screen> screen = new Screen(rect, availRect, pixelDepth, pixelDepth, 0,
|
||||
contentsScaleFactor, defaultCssScaleFactor,
|
||||
dpi, Screen::IsPseudoDisplay::No);
|
||||
RefPtr<Screen> screen =
|
||||
new Screen(rect, availRect, pixelDepth, pixelDepth, 0,
|
||||
contentsScaleFactor, defaultCssScaleFactor, dpi,
|
||||
Screen::IsPseudoDisplay::No, Screen::IsHDR(isHDR));
|
||||
return screen.forget();
|
||||
|
||||
NS_OBJC_END_TRY_BLOCK_RETURN(nullptr);
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ static already_AddRefed<Screen> MakeScreenGtk(GdkScreen* aScreen,
|
|||
contentsScale.scale, defaultCssScale.scale, dpi, refreshRate);
|
||||
return MakeAndAddRef<Screen>(rect, availRect, pixelDepth, pixelDepth,
|
||||
refreshRate, contentsScale, defaultCssScale, dpi,
|
||||
Screen::IsPseudoDisplay::No);
|
||||
Screen::IsPseudoDisplay::No, Screen::IsHDR::No);
|
||||
}
|
||||
|
||||
void ScreenGetterGtk::RefreshScreens() {
|
||||
|
|
|
|||
|
|
@ -32,9 +32,10 @@ LayoutDeviceIntRect HeadlessScreenHelper::GetScreenRect() {
|
|||
HeadlessScreenHelper::HeadlessScreenHelper() {
|
||||
AutoTArray<RefPtr<Screen>, 1> screenList;
|
||||
LayoutDeviceIntRect rect = GetScreenRect();
|
||||
auto ret = MakeRefPtr<Screen>(
|
||||
rect, rect, 24, 24, 0, DesktopToLayoutDeviceScale(),
|
||||
CSSToLayoutDeviceScale(), 96.0f, Screen::IsPseudoDisplay::No);
|
||||
auto ret =
|
||||
MakeRefPtr<Screen>(rect, rect, 24, 24, 0, DesktopToLayoutDeviceScale(),
|
||||
CSSToLayoutDeviceScale(), 96.0f,
|
||||
Screen::IsPseudoDisplay::No, Screen::IsHDR::No);
|
||||
screenList.AppendElement(ret.forget());
|
||||
ScreenManager::Refresh(std::move(screenList));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,12 @@
|
|||
#include "ScreenHelperWin.h"
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#include "nsTArray.h"
|
||||
#include "WinUtils.h"
|
||||
|
||||
#include <dxgi.h>
|
||||
|
||||
static mozilla::LazyLogModule sScreenLog("WidgetScreen");
|
||||
|
||||
namespace mozilla {
|
||||
|
|
@ -74,8 +77,14 @@ static void GetDisplayInfo(const char16ptr_t aName,
|
|||
}
|
||||
}
|
||||
|
||||
struct CollectMonitorsParam {
|
||||
nsTArray<RefPtr<Screen>> screens;
|
||||
nsTArray<DXGI_OUTPUT_DESC1> outputs;
|
||||
};
|
||||
|
||||
BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
|
||||
auto screens = reinterpret_cast<nsTArray<RefPtr<Screen>>*>(ioParam);
|
||||
CollectMonitorsParam* cmParam =
|
||||
reinterpret_cast<CollectMonitorsParam*>(ioParam);
|
||||
BOOL success = FALSE;
|
||||
MONITORINFOEX info;
|
||||
info.cbSize = sizeof(MONITORINFOEX);
|
||||
|
|
@ -123,6 +132,37 @@ BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
|
|||
GetDisplayInfo(info.szDevice, orientation, angle, isPseudoDisplay,
|
||||
refreshRate);
|
||||
|
||||
// Is this an HDR screen? Determine this by enumerating the DeviceManager
|
||||
// outputs (adapters) and correlating the monitor associated with the
|
||||
// the output with aMon, the monitor we are considering here.
|
||||
bool isHDR = false;
|
||||
for (auto& output : cmParam->outputs) {
|
||||
if (output.Monitor == aMon) {
|
||||
// Set isHDR to true if the output has a BT2020 colorspace with EOTF2084
|
||||
// gamma curve, this indicates the system is sending an HDR format to
|
||||
// this 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 we don't check bit depth here, since 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.
|
||||
//
|
||||
// Since RefreshScreens(), the caller of this function, is triggered
|
||||
// by WM_DISPLAYCHANGE, this will pick up changes to the monitors in
|
||||
// all the important cases (resolution/color changes by the user).
|
||||
//
|
||||
// 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
|
||||
isHDR = (output.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug,
|
||||
("New screen [%s (%s) %d %u %f %f %f %d %d %d]",
|
||||
ToString(rect).c_str(), ToString(availRect).c_str(), pixelDepth,
|
||||
|
|
@ -131,12 +171,12 @@ BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
|
|||
auto screen = MakeRefPtr<Screen>(
|
||||
rect, availRect, pixelDepth, pixelDepth, refreshRate, contentsScaleFactor,
|
||||
defaultCssScaleFactor, dpi, Screen::IsPseudoDisplay(isPseudoDisplay),
|
||||
orientation, angle);
|
||||
Screen::IsHDR(isHDR), orientation, angle);
|
||||
if (info.dwFlags & MONITORINFOF_PRIMARY) {
|
||||
// The primary monitor must be the first element of the screen list.
|
||||
screens->InsertElementAt(0, std::move(screen));
|
||||
cmParam->screens.InsertElementAt(0, std::move(screen));
|
||||
} else {
|
||||
screens->AppendElement(std::move(screen));
|
||||
cmParam->screens.AppendElement(std::move(screen));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -144,13 +184,17 @@ BOOL CALLBACK CollectMonitors(HMONITOR aMon, HDC, LPRECT, LPARAM ioParam) {
|
|||
void ScreenHelperWin::RefreshScreens() {
|
||||
MOZ_LOG(sScreenLog, LogLevel::Debug, ("Refreshing screens"));
|
||||
|
||||
AutoTArray<RefPtr<Screen>, 4> screens;
|
||||
CollectMonitorsParam cmParam;
|
||||
if (auto* dx = gfx::DeviceManagerDx::Get()) {
|
||||
// Get the adapters to pass as an arg to our monitor enumeration callback.
|
||||
cmParam.outputs = dx->EnumerateOutputs();
|
||||
}
|
||||
BOOL result = ::EnumDisplayMonitors(
|
||||
nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&screens);
|
||||
nullptr, nullptr, (MONITORENUMPROC)CollectMonitors, (LPARAM)&cmParam);
|
||||
if (!result) {
|
||||
NS_WARNING("Unable to EnumDisplayMonitors");
|
||||
}
|
||||
ScreenManager::Refresh(std::move(screens));
|
||||
ScreenManager::Refresh(std::move(cmParam.screens));
|
||||
}
|
||||
|
||||
} // namespace widget
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
"ScreenHelperWin.h",
|
||||
"ShellHeaderOnlyUtils.h",
|
||||
"ToastNotificationHeaderOnlyUtils.h",
|
||||
"UrlmonHeaderOnlyUtils.h",
|
||||
|
|
|
|||
Loading…
Reference in a new issue