Commit 111548d2 authored by Christopher Cameron's avatar Christopher Cameron Committed by Commit Bot

Add support for HDR displays on macOS 10.15

Detect HDR support using the -[NSScreen
maximumPotentialExtendedDynamicRangeColorComponentValue] API introduced
in 10.15. Use the hard-coded kDefaultBitsPerPixel/Component constants
instead of reading from the NSScreen. Move the constants to a common
location.

We can only promote an IOSurface to an overlay if we can set the
color space on the IOSurface in a way that will make CoreAnimation
draw it the same way that GLRenderer would.

Merge the various checks for color space compatibility into an
IOSurfaceCanSetColorSpace function, and call this from the SDR
and HDR paths.

Update IOSurfaceSetColorSpace to use the new constants
kCGColorSpaceITUR_2020_PQ_EOTF and kCGColorSpaceITUR_2020_HLG
introduced in 10.15.

Note that this will not trigger HDR mode. Doing so requires making
visible a CAMetalLayer with wantsExtendedDynamicRangeContent set.
The next patch in this sequence will do that.

Bug: 976426
Change-Id: Ic93302aa895f182713658f1eaea89c0e91953857
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1863449
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarMiguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707125}
parent 28856894
......@@ -363,7 +363,15 @@ typedef NSString* NSAppearanceName;
BASE_EXPORT extern NSAppearanceName const NSAppearanceNameDarkAqua;
#endif
#endif // MAC_OS_X_VERSION_10_14
#if !defined(MAC_OS_X_VERSION_10_15) || \
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15
@interface NSScreen (ForwardDeclare)
@property(readonly)
CGFloat maximumPotentialExtendedDynamicRangeColorComponentValue;
@end
#endif // MAC_OS_X_VERSION_10_15
// ----------------------------------------------------------------------------
// The symbol for kCWSSIDDidChangeNotification is available in the
......
......@@ -38,6 +38,11 @@
#include "ui/gfx/color_space.h"
#include "ui/gl/trace_util.h"
#if defined(OS_MACOSX)
#include "base/mac/mac_util.h"
#include "ui/gfx/mac/io_surface.h"
#endif
namespace media {
// Implementation of a pool of GpuMemoryBuffers used to back VideoFrames.
......@@ -563,14 +568,7 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::CreateHardwareFrame(
bool passthrough = false;
#if defined(OS_MACOSX)
// GPU memory buffers do not support full-range YUV video on mac.
// Fortunately, the hardware decoders never produce full-range video.
// https://crbug/882627
gfx::ColorSpace color_space = video_frame->ColorSpace();
gfx::ColorSpace as_rgb = color_space.GetAsRGB();
gfx::ColorSpace as_full_range_rgb = color_space.GetAsFullRangeRGB();
if (color_space != as_rgb && as_rgb == as_full_range_rgb)
if (!IOSurfaceCanSetColorSpace(video_frame->ColorSpace()))
passthrough = true;
#endif
if (output_format_ == GpuVideoAcceleratorFactories::OutputFormat::UNDEFINED)
......@@ -937,6 +935,9 @@ void GpuMemoryBufferVideoFramePool::PoolImpl::
case GpuVideoAcceleratorFactories::OutputFormat::XB30:
// TODO(mcasas): Enable this for ChromeOS https://crbug.com/776093.
allow_overlay = false;
#if defined(OS_MACOSX)
allow_overlay = IOSurfaceCanSetColorSpace(video_frame->ColorSpace());
#endif
// We've converted the YUV to RGB, fix the color space.
// TODO(hubbe): The libyuv YUV to RGB conversion may not have
// honored the color space conversion 100%. We should either fix
......
......@@ -21,15 +21,6 @@
namespace display {
namespace {
constexpr int kDefaultBitsPerPixel = 24;
constexpr int kDefaultBitsPerComponent = 8;
constexpr int kHDR10BitsPerPixel = 30;
constexpr int kHDR10BitsPerComponent = 10;
constexpr int kSCRGBLinearBitsPerPixel = 48;
constexpr int kSCRGBLinearBitsPerComponent = 16;
// This variable tracks whether the forced device scale factor switch needs to
// be read from the command line, i.e. if it is set to -1 then the command line
// is checked.
......
......@@ -237,6 +237,15 @@ class DISPLAY_EXPORT Display final {
const gfx::ColorSpace& color_space,
float sdr_white_level = gfx::ColorSpace::kDefaultSDRWhiteLevel);
// Default values for color_depth and depth_per_component.
static constexpr int kDefaultBitsPerPixel = 24;
static constexpr int kDefaultBitsPerComponent = 8;
// The following values are abused by media query APIs to detect HDR
// capability.
static constexpr int kHDR10BitsPerPixel = 30;
static constexpr int kHDR10BitsPerComponent = 10;
// The number of bits per pixel. Used by media query APIs.
int color_depth() const { return color_depth_; }
void set_color_depth(int color_depth) {
......@@ -267,6 +276,9 @@ class DISPLAY_EXPORT Display final {
private:
friend struct mojo::StructTraits<mojom::DisplayDataView, Display>;
static constexpr int kSCRGBLinearBitsPerPixel = 48;
static constexpr int kSCRGBLinearBitsPerComponent = 16;
int64_t id_ = kInvalidDisplayId;
gfx::Rect bounds_;
// If non-empty, then should be same size as |bounds_|. Used to avoid rounding
......
......@@ -106,8 +106,16 @@ Display BuildDisplayForScreen(NSScreen* screen) {
display.set_color_space(screen_color_space);
}
display.set_color_depth(NSBitsPerPixelFromDepth([screen depth]));
display.set_depth_per_component(NSBitsPerSampleFromDepth([screen depth]));
display.set_color_depth(Display::kDefaultBitsPerPixel);
display.set_depth_per_component(Display::kDefaultBitsPerComponent);
if ([screen respondsToSelector:@selector
(maximumPotentialExtendedDynamicRangeColorComponentValue)]) {
if ([screen maximumPotentialExtendedDynamicRangeColorComponentValue] >=
2.0) {
display.set_color_depth(Display::kHDR10BitsPerPixel);
display.set_depth_per_component(Display::kHDR10BitsPerComponent);
}
}
display.set_is_monochrome(CGDisplayUsesForceToGray());
if (auto display_link = ui::DisplayLinkMac::GetForDisplay(display_id))
......
......@@ -21,6 +21,13 @@ namespace gfx {
namespace {
#if !defined(MAC_OS_X_VERSION_10_15) || \
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_15
CFStringRef kCGColorSpaceITUR_2020_PQ_EOTF =
CFSTR("kCGColorSpaceITUR_2020_PQ_EOTF");
CFStringRef kCGColorSpaceITUR_2020_HLG = CFSTR("kCGColorSpaceITUR_2020_HLG");
#endif // MAC_OS_X_VERSION_10_15
void AddIntegerValue(CFMutableDictionaryRef dictionary,
const CFStringRef key,
int32_t value) {
......@@ -116,6 +123,71 @@ void IOSurfaceMachPortTraits::Release(mach_port_t port) {
<< "IOSurfaceMachPortTraits::Release mach_port_mod_refs";
}
// Common method used by IOSurfaceSetColorSpace and IOSurfaceCanSetColorSpace.
bool IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
const ColorSpace& color_space) {
// Allow but ignore invalid color spaces.
if (!color_space.IsValid())
return true;
// Prefer using named spaces.
CFStringRef color_space_name = nullptr;
if (__builtin_available(macos 10.12, *)) {
if (color_space == ColorSpace::CreateSRGB()) {
color_space_name = kCGColorSpaceSRGB;
} else if (color_space == ColorSpace::CreateDisplayP3D65()) {
color_space_name = kCGColorSpaceDisplayP3;
} else if (color_space == ColorSpace::CreateExtendedSRGB()) {
color_space_name = kCGColorSpaceExtendedSRGB;
} else if (color_space == ColorSpace::CreateSCRGBLinear()) {
color_space_name = kCGColorSpaceExtendedLinearSRGB;
}
}
if (__builtin_available(macos 10.15, *)) {
if (color_space == ColorSpace(ColorSpace::PrimaryID::BT2020,
ColorSpace::TransferID::SMPTEST2084,
ColorSpace::MatrixID::BT2020_NCL,
ColorSpace::RangeID::LIMITED)) {
color_space_name = kCGColorSpaceITUR_2020_PQ_EOTF;
} else if (color_space == ColorSpace(ColorSpace::PrimaryID::BT2020,
ColorSpace::TransferID::ARIB_STD_B67,
ColorSpace::MatrixID::BT2020_NCL,
ColorSpace::RangeID::LIMITED)) {
color_space_name = kCGColorSpaceITUR_2020_HLG;
}
}
if (color_space_name) {
if (io_surface) {
IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"),
color_space_name);
}
return true;
}
gfx::ColorSpace as_rgb = color_space.GetAsRGB();
gfx::ColorSpace as_full_range_rgb = color_space.GetAsFullRangeRGB();
// IOSurfaces do not support full-range YUV video. Fortunately, the hardware
// decoders never produce full-range video.
// https://crbug.com/882627
if (color_space != as_rgb && as_rgb == as_full_range_rgb)
return false;
// Generate an ICCProfile from the parametric color space.
ICCProfile icc_profile = ICCProfile::FromColorSpace(as_full_range_rgb);
if (!icc_profile.IsValid())
return false;
// Package it as a CFDataRef and send it to the IOSurface.
std::vector<char> icc_profile_data = icc_profile.GetData();
base::ScopedCFTypeRef<CFDataRef> cf_data_icc_profile(CFDataCreate(
nullptr, reinterpret_cast<const UInt8*>(icc_profile_data.data()),
icc_profile_data.size()));
IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"),
cf_data_icc_profile);
return true;
}
} // namespace internal
IOSurfaceRef CreateIOSurface(const gfx::Size& size,
......@@ -185,61 +257,30 @@ IOSurfaceRef CreateIOSurface(const gfx::Size& size,
}
// Ensure that all IOSurfaces start as sRGB.
CGColorSpaceRef color_space = base::mac::GetSRGBColorSpace();
base::ScopedCFTypeRef<CFDataRef> color_space_icc(
CGColorSpaceCopyICCProfile(color_space));
IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), color_space_icc);
if (__builtin_available(macos 10.12, *)) {
IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB);
} else {
CGColorSpaceRef color_space = base::mac::GetSRGBColorSpace();
base::ScopedCFTypeRef<CFDataRef> color_space_icc(
CGColorSpaceCopyICCProfile(color_space));
IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), color_space_icc);
}
UMA_HISTOGRAM_TIMES("GPU.IOSurface.CreateTime",
base::TimeTicks::Now() - start_time);
return surface;
}
bool IOSurfaceCanSetColorSpace(const ColorSpace& color_space) {
return internal::IOSurfaceSetColorSpace(nullptr, color_space);
}
void IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
const ColorSpace& color_space) {
// Special-case sRGB.
if (color_space == ColorSpace::CreateSRGB()) {
base::ScopedCFTypeRef<CFDataRef> srgb_icc(
CGColorSpaceCopyICCProfile(base::mac::GetSRGBColorSpace()));
IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"), srgb_icc);
return;
}
// Special-case BT2020_NCL.
if (__builtin_available(macos 10.12, *)) {
const ColorSpace kBt2020(
ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::SMPTEST2084,
ColorSpace::MatrixID::BT2020_NCL, ColorSpace::RangeID::LIMITED);
if (color_space == kBt2020) {
base::ScopedCFTypeRef<CGColorSpaceRef> cg_color_space(
CGColorSpaceCreateWithName(kCGColorSpaceITUR_2020));
DCHECK(cg_color_space);
base::ScopedCFTypeRef<CFDataRef> cf_data_icc_profile(
CGColorSpaceCopyICCData(cg_color_space));
DCHECK(cf_data_icc_profile);
IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"),
cf_data_icc_profile);
return;
}
}
// Generate an ICCProfile from the parametric color space.
ICCProfile icc_profile =
ICCProfile::FromColorSpace(color_space.GetAsFullRangeRGB());
if (!icc_profile.IsValid()) {
DLOG(ERROR) << "Failed to set color space for IOSurface: no ICC profile: "
if (!internal::IOSurfaceSetColorSpace(io_surface, color_space)) {
DLOG(ERROR) << "Failed to set color space for IOSurface: "
<< color_space.ToString();
return;
}
// Package it as a CFDataRef and send it to the IOSurface.
std::vector<char> icc_profile_data = icc_profile.GetData();
base::ScopedCFTypeRef<CFDataRef> cf_data_icc_profile(CFDataCreate(
nullptr, reinterpret_cast<const UInt8*>(icc_profile_data.data()),
icc_profile_data.size()));
IOSurfaceSetValue(io_surface, CFSTR("IOSurfaceColorSpace"),
cf_data_icc_profile);
}
} // namespace gfx
......@@ -62,8 +62,12 @@ using ScopedRefCountedIOSurfaceMachPort =
using ScopedInUseIOSurface =
base::ScopedTypeRef<IOSurfaceRef, internal::ScopedInUseIOSurfaceTraits>;
// Set color space for given IOSurface. Color space must have an associated ICC
// color profile otherwise this function does nothing.
// Return true if there exists a value for IOSurfaceColorSpace or
// IOSurfaceICCProfile that will make CoreAnimation render using |color_space|.
GFX_EXPORT bool IOSurfaceCanSetColorSpace(const gfx::ColorSpace& color_space);
// Set color space for given IOSurface. IOSurfaceCanSetColorSpace must return
// true for |color_space| otherwise this does nothing.
GFX_EXPORT void IOSurfaceSetColorSpace(IOSurfaceRef io_surface,
const gfx::ColorSpace& color_space);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment