Commit 07199ff1 authored by Miguel Casas's avatar Miguel Casas Committed by Commit Bot

ui: fill in SDR/HDR DisplayColorSpaces, CrOS

This CL adds code for populating the necessary gfx::DisplayColorSpaces
in CreateManagedDisplayInfo for supporting SDR and HDR target color
spaces (depending on the monitor capabilities and the big hdr flag).

It needs a sibling CL to allow AR/B30 FBs on CrOs crrev.com/c/2078655,
Tested with that CL and by playing an HDR video: the primary
framebuffer format in /sys/kernel/debug/dri/0//state correctly changes
to XB30, whereas when there are not HDR quads in the BufferQueue, it's
XR24.

Bug: 958166
Change-Id: I94638436c079b03ef9f6200b77697b1d3da9337e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2072621Reviewed-by: default avatarccameron <ccameron@chromium.org>
Commit-Queue: Miguel Casas <mcasas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#745461}
parent e3593e12
...@@ -440,16 +440,6 @@ void Compositor::SetDisplayColorSpaces( ...@@ -440,16 +440,6 @@ void Compositor::SetDisplayColorSpaces(
if (display_color_spaces_ == display_color_spaces) if (display_color_spaces_ == display_color_spaces)
return; return;
display_color_spaces_ = display_color_spaces; display_color_spaces_ = display_color_spaces;
// TODO(crbug.com/1012846): Remove this flag and provision when HDR is fully
// supported on ChromeOS.
#if defined(OS_CHROMEOS)
if (display_color_spaces_.SupportsHDR() &&
!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableUseHDRTransferFunction)) {
display_color_spaces_ =
gfx::DisplayColorSpaces(gfx::ColorSpace::CreateSRGB());
}
#endif
host_->SetRasterColorSpace(display_color_spaces_.GetRasterColorSpace()); host_->SetRasterColorSpace(display_color_spaces_.GetRasterColorSpace());
// Always force the ui::Compositor to re-draw all layers, because damage // Always force the ui::Compositor to re-draw all layers, because damage
......
...@@ -163,7 +163,8 @@ std::unique_ptr<FakeDisplaySnapshot> Builder::Build() { ...@@ -163,7 +163,8 @@ std::unique_ptr<FakeDisplaySnapshot> Builder::Build() {
id_, origin_, physical_size, type_, is_aspect_preserving_scaling_, id_, origin_, physical_size, type_, is_aspect_preserving_scaling_,
has_overscan_, privacy_screen_state_, has_color_correction_matrix_, has_overscan_, privacy_screen_state_, has_color_correction_matrix_,
color_correction_in_linear_space_, name_, std::move(modes_), color_correction_in_linear_space_, name_, std::move(modes_),
current_mode_, native_mode_, product_code_, maximum_cursor_size_); current_mode_, native_mode_, product_code_, maximum_cursor_size_,
color_space_, bits_per_channel_);
} }
Builder& Builder::SetId(int64_t id) { Builder& Builder::SetId(int64_t id) {
...@@ -264,6 +265,16 @@ Builder& Builder::SetPrivacyScreen(PrivacyScreenState state) { ...@@ -264,6 +265,16 @@ Builder& Builder::SetPrivacyScreen(PrivacyScreenState state) {
return *this; return *this;
} }
Builder& Builder::SetColorSpace(const gfx::ColorSpace& color_space) {
color_space_ = color_space;
return *this;
}
Builder& Builder::SetBitsPerChannel(uint32_t bits_per_channel) {
bits_per_channel_ = bits_per_channel;
return *this;
}
const DisplayMode* Builder::AddOrFindDisplayMode(const gfx::Size& size) { const DisplayMode* Builder::AddOrFindDisplayMode(const gfx::Size& size) {
for (auto& mode : modes_) { for (auto& mode : modes_) {
if (mode->size() == size) if (mode->size() == size)
...@@ -305,7 +316,9 @@ FakeDisplaySnapshot::FakeDisplaySnapshot( ...@@ -305,7 +316,9 @@ FakeDisplaySnapshot::FakeDisplaySnapshot(
const DisplayMode* current_mode, const DisplayMode* current_mode,
const DisplayMode* native_mode, const DisplayMode* native_mode,
int64_t product_code, int64_t product_code,
const gfx::Size& maximum_cursor_size) const gfx::Size& maximum_cursor_size,
const gfx::ColorSpace& color_space,
uint32_t bits_per_channel)
: DisplaySnapshot(display_id, : DisplaySnapshot(display_id,
origin, origin,
physical_size, physical_size,
...@@ -315,8 +328,8 @@ FakeDisplaySnapshot::FakeDisplaySnapshot( ...@@ -315,8 +328,8 @@ FakeDisplaySnapshot::FakeDisplaySnapshot(
privacy_screen_state, privacy_screen_state,
has_color_correction_matrix, has_color_correction_matrix,
color_correction_in_linear_space, color_correction_in_linear_space,
gfx::ColorSpace(), color_space,
8u /* bits_per_channel */, bits_per_channel,
display_name, display_name,
base::FilePath(), base::FilePath(),
std::move(modes), std::move(modes),
......
...@@ -70,6 +70,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot { ...@@ -70,6 +70,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
// Sets physical_size for high DPI display. // Sets physical_size for high DPI display.
Builder& SetHighDPI(); Builder& SetHighDPI();
Builder& SetPrivacyScreen(PrivacyScreenState state); Builder& SetPrivacyScreen(PrivacyScreenState state);
Builder& SetColorSpace(const gfx::ColorSpace& color_space);
Builder& SetBitsPerChannel(uint32_t bits_per_channel);
private: private:
// Returns a display mode with |size|. If there is no existing mode, insert // Returns a display mode with |size|. If there is no existing mode, insert
...@@ -94,6 +96,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot { ...@@ -94,6 +96,8 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
DisplayModeList modes_; DisplayModeList modes_;
const DisplayMode* current_mode_ = nullptr; const DisplayMode* current_mode_ = nullptr;
const DisplayMode* native_mode_ = nullptr; const DisplayMode* native_mode_ = nullptr;
gfx::ColorSpace color_space_;
uint32_t bits_per_channel_ = 8u;
DISALLOW_COPY_AND_ASSIGN(Builder); DISALLOW_COPY_AND_ASSIGN(Builder);
}; };
...@@ -112,7 +116,9 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot { ...@@ -112,7 +116,9 @@ class FAKE_DISPLAY_EXPORT FakeDisplaySnapshot : public DisplaySnapshot {
const DisplayMode* current_mode, const DisplayMode* current_mode,
const DisplayMode* native_mode, const DisplayMode* native_mode,
int64_t product_code, int64_t product_code,
const gfx::Size& maximum_cursor_size); const gfx::Size& maximum_cursor_size,
const gfx::ColorSpace& color_space,
uint32_t bits_per_channel);
~FakeDisplaySnapshot() override; ~FakeDisplaySnapshot() override;
// Creates a display snapshot from the provided |spec| string. Returns null if // Creates a display snapshot from the provided |spec| string. Returns null if
......
...@@ -77,6 +77,55 @@ ManagedDisplayInfo::ManagedDisplayModeList GetModeListWithAllRefreshRates( ...@@ -77,6 +77,55 @@ ManagedDisplayInfo::ManagedDisplayModeList GetModeListWithAllRefreshRates(
return display_mode_list; return display_mode_list;
} }
// Constructs the raster DisplayColorSpaces out of |snapshot_color_space|,
// including the HDR ones if present and |allow_high_bit_depth| is set.
gfx::DisplayColorSpaces FillDisplayColorSpaces(
const gfx::ColorSpace& snapshot_color_space,
bool allow_high_bit_depth) {
// ChromeOS VMs (e.g. amd64-generic or betty) have INVALID Primaries; just
// pass the color space along.
if (!snapshot_color_space.IsValid()) {
return gfx::DisplayColorSpaces(snapshot_color_space,
DisplaySnapshot::PrimaryFormat());
}
constexpr auto kSDRTransferId = gfx::ColorSpace::TransferID::IEC61966_2_1;
const auto primary_id = snapshot_color_space.GetPrimaryID();
gfx::ColorSpace sdr_color_space;
if (primary_id == gfx::ColorSpace::PrimaryID::CUSTOM) {
skcms_Matrix3x3 primary_matrix{};
snapshot_color_space.GetPrimaryMatrix(&primary_matrix);
sdr_color_space =
gfx::ColorSpace::CreateCustom(primary_matrix, kSDRTransferId);
} else {
sdr_color_space = gfx::ColorSpace(primary_id, kSDRTransferId);
}
gfx::DisplayColorSpaces display_color_spaces(
sdr_color_space, DisplaySnapshot::PrimaryFormat());
if (allow_high_bit_depth) {
gfx::ColorSpace hdr_color_space;
if (primary_id == gfx::ColorSpace::PrimaryID::CUSTOM) {
skcms_Matrix3x3 primary_matrix{};
snapshot_color_space.GetPrimaryMatrix(&primary_matrix);
hdr_color_space = gfx::ColorSpace::CreatePiecewiseHDR(
primary_id, 0.99, 2.0, &primary_matrix);
} else {
hdr_color_space =
gfx::ColorSpace::CreatePiecewiseHDR(primary_id, 0.99, 2.0);
}
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, false /* needs_alpha */, hdr_color_space,
gfx::BufferFormat::RGBA_1010102);
display_color_spaces.SetOutputColorSpaceAndBufferFormat(
gfx::ContentColorUsage::kHDR, true /* needs_alpha */, hdr_color_space,
gfx::BufferFormat::RGBA_1010102);
}
return display_color_spaces;
}
} // namespace } // namespace
// static // static
...@@ -336,21 +385,23 @@ ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo( ...@@ -336,21 +385,23 @@ ManagedDisplayInfo DisplayChangeObserver::CreateManagedDisplayInfo(
if (dpi) if (dpi)
new_info.set_device_dpi(dpi); new_info.set_device_dpi(dpi);
#if !defined(OS_CHROMEOS)
// TODO(crbug.com/1012846): This should configure the HDR color spaces. // TODO(crbug.com/1012846): This should configure the HDR color spaces.
gfx::DisplayColorSpaces display_color_spaces( gfx::DisplayColorSpaces display_color_spaces(
snapshot->color_space(), DisplaySnapshot::PrimaryFormat()); snapshot->color_space(), DisplaySnapshot::PrimaryFormat());
new_info.set_display_color_spaces(display_color_spaces); new_info.set_display_color_spaces(display_color_spaces);
new_info.set_bits_per_channel(snapshot->bits_per_channel()); new_info.set_bits_per_channel(snapshot->bits_per_channel());
#else
// TODO(crbug.com/1012846): Remove this flag and provision when HDR is fully // TODO(crbug.com/1012846): Remove kEnableUseHDRTransferFunction usage when
// supported on ChromeOS. // HDR is fully supported on ChromeOS.
#if defined(OS_CHROMEOS) const bool allow_high_bit_depth =
base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableUseHDRTransferFunction);
new_info.set_display_color_spaces(
FillDisplayColorSpaces(snapshot->color_space(), allow_high_bit_depth));
constexpr int32_t kNormalBitDepth = 8; constexpr int32_t kNormalBitDepth = 8;
if (new_info.bits_per_channel() > kNormalBitDepth && new_info.set_bits_per_channel(
!base::CommandLine::ForCurrentProcess()->HasSwitch( allow_high_bit_depth ? snapshot->bits_per_channel() : kNormalBitDepth);
switches::kEnableUseHDRTransferFunction)) {
new_info.set_bits_per_channel(kNormalBitDepth);
}
#endif #endif
new_info.set_refresh_rate(mode_info->refresh_rate()); new_info.set_refresh_rate(mode_info->refresh_rate());
......
...@@ -60,6 +60,8 @@ class DISPLAY_MANAGER_EXPORT DisplayChangeObserver ...@@ -60,6 +60,8 @@ class DISPLAY_MANAGER_EXPORT DisplayChangeObserver
DISPLAY_EXPORT static float FindDeviceScaleFactor(float dpi); DISPLAY_EXPORT static float FindDeviceScaleFactor(float dpi);
private: private:
friend class DisplayChangeObserverTest;
void UpdateInternalDisplay( void UpdateInternalDisplay(
const DisplayConfigurator::DisplayStateList& display_states); const DisplayConfigurator::DisplayStateList& display_states);
......
...@@ -12,8 +12,11 @@ ...@@ -12,8 +12,11 @@
#include "ui/display/display_switches.h" #include "ui/display/display_switches.h"
#include "ui/display/fake/fake_display_snapshot.h" #include "ui/display/fake/fake_display_snapshot.h"
#include "ui/display/manager/display_configurator.h" #include "ui/display/manager/display_configurator.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/manager/managed_display_info.h" #include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h"
#include "ui/display/types/display_mode.h" #include "ui/display/types/display_mode.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
...@@ -58,6 +61,13 @@ class DisplayChangeObserverTest : public testing::Test, ...@@ -58,6 +61,13 @@ class DisplayChangeObserverTest : public testing::Test,
Test::SetUp(); Test::SetUp();
} }
// Pass through method to be called by individual test cases.
ManagedDisplayInfo CreateManagedDisplayInfo(DisplayChangeObserver* observer,
const DisplaySnapshot* snapshot,
const DisplayMode* mode_info) {
return observer->CreateManagedDisplayInfo(snapshot, mode_info);
}
private: private:
base::test::ScopedFeatureList scoped_feature_list_; base::test::ScopedFeatureList scoped_feature_list_;
...@@ -173,7 +183,8 @@ TEST_P(DisplayChangeObserverTest, GetEmptyExternalManagedDisplayModeList) { ...@@ -173,7 +183,8 @@ TEST_P(DisplayChangeObserverTest, GetEmptyExternalManagedDisplayModeList) {
FakeDisplaySnapshot display_snapshot( FakeDisplaySnapshot display_snapshot(
123, gfx::Point(), gfx::Size(), DISPLAY_CONNECTION_TYPE_UNKNOWN, false, 123, gfx::Point(), gfx::Size(), DISPLAY_CONNECTION_TYPE_UNKNOWN, false,
false, PrivacyScreenState::kNotSupported, false, false, std::string(), {}, false, PrivacyScreenState::kNotSupported, false, false, std::string(), {},
nullptr, nullptr, 0, gfx::Size()); nullptr, nullptr, 0, gfx::Size(), gfx::ColorSpace(),
/*bits_per_channel=*/8u);
ManagedDisplayInfo::ManagedDisplayModeList display_modes = ManagedDisplayInfo::ManagedDisplayModeList display_modes =
DisplayChangeObserver::GetExternalManagedDisplayModeList( DisplayChangeObserver::GetExternalManagedDisplayModeList(
...@@ -267,6 +278,127 @@ TEST_P(DisplayChangeObserverTest, ...@@ -267,6 +278,127 @@ TEST_P(DisplayChangeObserverTest,
} }
} }
TEST_P(DisplayChangeObserverTest, InvalidDisplayColorSpaces) {
const std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
.SetName("AmazingFakeDisplay")
.SetNativeMode(MakeDisplayMode(1920, 1080, true, 60))
.SetColorSpace(gfx::ColorSpace())
.Build();
ui::DeviceDataManager::CreateInstance();
DisplayManager manager(nullptr);
const auto display_mode = MakeDisplayMode(1920, 1080, true, 60);
DisplayChangeObserver observer(&manager);
const ManagedDisplayInfo display_info = CreateManagedDisplayInfo(
&observer, display_snapshot.get(), display_mode.get());
EXPECT_EQ(display_info.bits_per_channel(), 8u);
const auto display_color_spaces = display_info.display_color_spaces();
EXPECT_FALSE(display_color_spaces.SupportsHDR());
EXPECT_EQ(
DisplaySnapshot::PrimaryFormat(),
display_color_spaces.GetOutputBufferFormat(gfx::ContentColorUsage::kSRGB,
/*needs_alpha=*/true));
const auto color_space = display_color_spaces.GetRasterColorSpace();
// DisplayColorSpaces will fix an invalid ColorSpace to return sRGB.
EXPECT_TRUE(color_space.IsValid());
EXPECT_EQ(color_space, gfx::ColorSpace::CreateSRGB());
}
TEST_P(DisplayChangeObserverTest, SDRDisplayColorSpaces) {
const std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
.SetName("AmazingFakeDisplay")
.SetNativeMode(MakeDisplayMode(1920, 1080, true, 60))
.SetColorSpace(gfx::ColorSpace::CreateSRGB())
.Build();
ui::DeviceDataManager::CreateInstance();
DisplayManager manager(nullptr);
const auto display_mode = MakeDisplayMode(1920, 1080, true, 60);
DisplayChangeObserver observer(&manager);
const ManagedDisplayInfo display_info = CreateManagedDisplayInfo(
&observer, display_snapshot.get(), display_mode.get());
EXPECT_EQ(display_info.bits_per_channel(), 8u);
const auto display_color_spaces = display_info.display_color_spaces();
EXPECT_FALSE(display_color_spaces.SupportsHDR());
EXPECT_EQ(
DisplaySnapshot::PrimaryFormat(),
display_color_spaces.GetOutputBufferFormat(gfx::ContentColorUsage::kSRGB,
/*needs_alpha=*/true));
const auto color_space = display_color_spaces.GetRasterColorSpace();
EXPECT_TRUE(color_space.IsValid());
EXPECT_EQ(color_space.GetPrimaryID(), gfx::ColorSpace::PrimaryID::BT709);
EXPECT_EQ(color_space.GetTransferID(),
gfx::ColorSpace::TransferID::IEC61966_2_1);
}
#if defined(OS_CHROMEOS)
TEST_P(DisplayChangeObserverTest, HDRDisplayColorSpaces) {
// TODO(crbug.com/1012846): Remove this flag and provision when HDR is fully
// supported on ChromeOS.
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableUseHDRTransferFunction);
const std::unique_ptr<DisplaySnapshot> display_snapshot =
FakeDisplaySnapshot::Builder()
.SetId(123)
.SetName("AmazingFakeDisplay")
.SetNativeMode(MakeDisplayMode(1920, 1080, true, 60))
.SetColorSpace(gfx::ColorSpace::CreateHDR10(100.0f))
.SetBitsPerChannel(10u)
.Build();
ui::DeviceDataManager::CreateInstance();
DisplayManager manager(nullptr);
const auto display_mode = MakeDisplayMode(1920, 1080, true, 60);
DisplayChangeObserver observer(&manager);
const ManagedDisplayInfo display_info = CreateManagedDisplayInfo(
&observer, display_snapshot.get(), display_mode.get());
EXPECT_EQ(display_info.bits_per_channel(), 10u);
const auto display_color_spaces = display_info.display_color_spaces();
EXPECT_TRUE(display_color_spaces.SupportsHDR());
// |display_color_spaces| still supports SDR rendering.
EXPECT_EQ(
DisplaySnapshot::PrimaryFormat(),
display_color_spaces.GetOutputBufferFormat(gfx::ContentColorUsage::kSRGB,
/*needs_alpha=*/true));
const auto sdr_color_space =
display_color_spaces.GetOutputColorSpace(gfx::ContentColorUsage::kSRGB,
/*needs_alpha=*/true);
EXPECT_TRUE(sdr_color_space.IsValid());
EXPECT_EQ(sdr_color_space.GetPrimaryID(), gfx::ColorSpace::PrimaryID::BT2020);
EXPECT_EQ(sdr_color_space.GetTransferID(),
gfx::ColorSpace::TransferID::IEC61966_2_1);
EXPECT_EQ(
display_color_spaces.GetOutputBufferFormat(gfx::ContentColorUsage::kHDR,
/*needs_alpha=*/true),
gfx::BufferFormat::RGBA_1010102);
const auto hdr_color_space =
display_color_spaces.GetOutputColorSpace(gfx::ContentColorUsage::kHDR,
/*needs_alpha=*/true);
EXPECT_TRUE(hdr_color_space.IsValid());
EXPECT_EQ(hdr_color_space.GetPrimaryID(), gfx::ColorSpace::PrimaryID::BT2020);
EXPECT_EQ(hdr_color_space.GetTransferID(),
gfx::ColorSpace::TransferID::PIECEWISE_HDR);
}
#endif
INSTANTIATE_TEST_SUITE_P(All, INSTANTIATE_TEST_SUITE_P(All,
DisplayChangeObserverTest, DisplayChangeObserverTest,
::testing::Values(false, true)); ::testing::Values(false, true));
......
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