Skip to content

Commit

Permalink
SkColorSpacePrimaries: Consolidate more functionality
Browse files Browse the repository at this point in the history
Add several helper functions for SkColorSpacePrimaries.
- Add the ability to produce a D65 SkColorSpacePrimaries from an
  skcms_Matrix3x3. This is needed to produce primaries from an ICC
  profile, which only provides a skcms_Matrix3x3
- Add a function to print primaries
- Add constants for well-known primaries
- And unit tests!

Change gfx::ColorSpace to use these functions
- Rename gfx::ColorSpace::GetColorSpacePrimaries to just GetPrimaries
- Change GetPrimaries to call GetD65PrimariesFromToXYZD50Matrix
  instead of doing its own calculation. The math in this function
  is different (the previous version was missing chromatic
  adaptation).
- Use SkColorSpacePrimariesToString when dumping to a string.

Update chrome://gpu to display SkColorSpacePrimaries information

This creates a single consolidated place where primary constants
are stored (as opposed to repeating them in tests). This potentially
increases binary size.

Binary-Size: See commit description
Fuchsia-Binary-Size: See commit description.

Bug: 1274220
Change-Id: I04fa1b6d5b274422210170112ec0d90812e2e9e7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3878588
Reviewed-by: Zhenyao Mo <zmo@chromium.org>
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Jim Shargo <jshargo@chromium.org>
Commit-Queue: ccameron chromium <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1045604}
  • Loading branch information
ccameron-chromium authored and Chromium LUCI CQ committed Sep 11, 2022
1 parent 2714675 commit 102eed6
Show file tree
Hide file tree
Showing 11 changed files with 231 additions and 103 deletions.
6 changes: 2 additions & 4 deletions components/exo/wayland/zcr_color_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class ColorManagerColorSpace {
explicit ColorManagerColorSpace(gfx::ColorSpace color_space)
: color_space(color_space),
eotf(ui::wayland::ToColorManagerEOTF(color_space.GetTransferID())),
primaries(color_space.GetColorSpacePrimaries()) {}
primaries(color_space.GetPrimaries()) {}

ColorManagerColorSpace(gfx::ColorSpace color_space,
zcr_color_manager_v1_eotf_names eotf,
Expand Down Expand Up @@ -89,9 +89,7 @@ class NameBasedColorSpace final : public ColorManagerColorSpace {
zcr_color_manager_v1_chromaticity_names chromaticity,
zcr_color_manager_v1_eotf_names eotf,
zcr_color_manager_v1_whitepoint_names whitepoint)
: ColorManagerColorSpace(color_space,
eotf,
color_space.GetColorSpacePrimaries()),
: ColorManagerColorSpace(color_space, eotf, color_space.GetPrimaries()),
chromaticity(ui::wayland::ToColorManagerChromaticity(
color_space.GetPrimaryID())),
whitepoint(whitepoint) {}
Expand Down
3 changes: 3 additions & 0 deletions content/browser/gpu/gpu_internals_ui.cc
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,9 @@ base::Value::List GetDisplayInfo() {
gfx::BufferFormatToString(buffer_formats[i])));
}
}
display_info.Append(display::BuildGpuInfoEntry(
"Color volume", skia::SkColorSpacePrimariesToString(
display.color_spaces().GetPrimaries())));
display_info.Append(display::BuildGpuInfoEntry(
"SDR white level in nits",
base::NumberToString(display.color_spaces().GetSDRMaxLuminanceNits())));
Expand Down
10 changes: 5 additions & 5 deletions skia/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,7 @@ source_set("skcms") {

public = [ "//third_party/skia/modules/skcms/skcms.h" ]
include_dirs = [ "//third_party/skia/modules/skcms" ]
sources =
rebase_path(skcms_sources, ".", "//third_party/skia/modules/skcms")
sources = rebase_path(skcms_sources, ".", "//third_party/skia/modules/skcms")
}

component("skia") {
Expand Down Expand Up @@ -243,6 +242,8 @@ component("skia") {
"ext/recursive_gaussian_convolution.h",
"ext/rgba_to_yuva.cc",
"ext/rgba_to_yuva.h",
"ext/skcolorspace_primaries.cc",
"ext/skcolorspace_primaries.h",
"ext/skia_histogram.cc",
"ext/skia_histogram.h",
"ext/skia_memory_dump_provider.cc",
Expand Down Expand Up @@ -423,9 +424,7 @@ component("skia") {
"//third_party/skia/src/ports/SkTypeface_win_dw.cpp",
]
} else {
sources += [
"//third_party/skia/src/ports/SkOSFile_posix.cpp",
]
sources += [ "//third_party/skia/src/ports/SkOSFile_posix.cpp" ]
}

if (is_apple) {
Expand Down Expand Up @@ -930,6 +929,7 @@ test("skia_unittests") {
"ext/image_operations_unittest.cc",
"ext/platform_canvas_unittest.cc",
"ext/recursive_gaussian_convolution_unittest.cc",
"ext/skcolorspace_primaries_unittest.cc",
"ext/skia_memory_dump_provider_unittest.cc",
"ext/skia_utils_base_unittest.cc",
]
Expand Down
93 changes: 93 additions & 0 deletions skia/ext/skcolorspace_primaries.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "skia/ext/skcolorspace_primaries.h"

#include <iomanip>
#include <sstream>

bool operator==(const SkColorSpacePrimaries& a,
const SkColorSpacePrimaries& b) {
return a.fRX == b.fRX && a.fRY == b.fRY && a.fGX == b.fGX && a.fGY == b.fGY &&
a.fBX == b.fBX && a.fBY == b.fBY && a.fWX == b.fWX && a.fWY == b.fWY;
}

bool operator!=(const SkColorSpacePrimaries& a,
const SkColorSpacePrimaries& b) {
return !(a == b);
}

namespace skia {

std::string SkColorSpacePrimariesToString(
const SkColorSpacePrimaries& primaries) {
if (primaries == kSkColorSpacePrimariesZero)
return "invalid";

std::stringstream ss;
ss << std::fixed << std::setprecision(4);
ss << "{";
if (primaries == kSkColorSpacePrimariesSRGB)
ss << "name:'srgb', ";
else if (primaries == kSkColorSpacePrimariesP3)
ss << "name:'p3', ";
else if (primaries == kSkColorSpacePrimariesRec2020)
ss << "name:'rec2020', ";
ss << "r:[" << primaries.fRX << ", " << primaries.fRY << "], ";
ss << "g:[" << primaries.fGX << ", " << primaries.fGY << "], ";
ss << "b:[" << primaries.fBX << ", " << primaries.fRY << "], ";
ss << "w:[" << primaries.fWX << ", " << primaries.fWY << "]";
ss << "}";
return ss.str();
}

SkColorSpacePrimaries GetD65PrimariesFromToXYZD50Matrix(
const skcms_Matrix3x3& m_d50) {
constexpr float kD65_X = 0.3127f;
constexpr float kD65_Y = 0.3290f;
skcms_Matrix3x3 adapt_d65_to_d50;
skcms_AdaptToXYZD50(kD65_X, kD65_Y, &adapt_d65_to_d50);

skcms_Matrix3x3 adapt_d50_to_d65;
skcms_Matrix3x3_invert(&adapt_d65_to_d50, &adapt_d50_to_d65);

const skcms_Matrix3x3 m = skcms_Matrix3x3_concat(&adapt_d50_to_d65, &m_d50);
const float sum_R = m.vals[0][0] + m.vals[1][0] + m.vals[2][0];
const float sum_G = m.vals[0][1] + m.vals[1][1] + m.vals[2][1];
const float sum_B = m.vals[0][2] + m.vals[1][2] + m.vals[2][2];
SkColorSpacePrimaries primaries;
primaries.fRX = m.vals[0][0] / sum_R;
primaries.fRY = m.vals[1][0] / sum_R;
primaries.fGX = m.vals[0][1] / sum_G;
primaries.fGY = m.vals[1][1] / sum_G;
primaries.fBX = m.vals[0][2] / sum_B;
primaries.fBY = m.vals[1][2] / sum_B;
primaries.fWX = kD65_X;
primaries.fWY = kD65_Y;
return primaries;
}

SkColorSpacePrimaries kSkColorSpacePrimariesZero = {0};

SkColorSpacePrimaries kSkColorSpacePrimariesSRGB = {
0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f, 0.3127f, 0.3290f,
};

SkColorSpacePrimaries kSkColorSpacePrimariesP3 = {
0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.3127f, 0.3290f,
};

SkColorSpacePrimaries kSkColorSpacePrimariesRec2020 = {
0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f, 0.3127f, 0.3290f,
};

SkColorSpacePrimaries kSkColorSpacePrimariesProPhotoD50 = {
0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f, 0.34567f, 0.35850f,
};

SkColorSpacePrimaries kSkColorSpacePrimariesWideGamutColorSpin = {
0.01f, 0.98f, 0.01f, 0.01f, 0.98f, 0.01f, 0.3127f, 0.3290f,
};

} // namespace skia
51 changes: 51 additions & 0 deletions skia/ext/skcolorspace_primaries.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef SKIA_EXT_SKCOLORSPACE_PRIMARIES_H_
#define SKIA_EXT_SKCOLORSPACE_PRIMARIES_H_

#include "third_party/skia/include/core/SkColorSpace.h"

#include <string>

// TODO(https://crbug.com/skia/13721): Add these operators to Skia source.
SK_API bool operator==(const SkColorSpacePrimaries& a,
const SkColorSpacePrimaries& b);

SK_API bool operator!=(const SkColorSpacePrimaries& a,
const SkColorSpacePrimaries& b);

namespace skia {

// Display SkColorSpacePrimaries as a string.
SK_API std::string SkColorSpacePrimariesToString(
const SkColorSpacePrimaries& primaries);

// Given a matrix that transforms to XYZD50, compute the primaries with a D65
// white point that would produce this matrix.
SK_API SkColorSpacePrimaries
GetD65PrimariesFromToXYZD50Matrix(const skcms_Matrix3x3& m);

// Primaries initialized to zero (an invalid value).
extern SK_API SkColorSpacePrimaries kSkColorSpacePrimariesZero;

// The sRGB or BT709 primaries.
extern SK_API SkColorSpacePrimaries kSkColorSpacePrimariesSRGB;

// P3 primaries.
extern SK_API SkColorSpacePrimaries kSkColorSpacePrimariesP3;

// Rec2020 primaries.
extern SK_API SkColorSpacePrimaries kSkColorSpacePrimariesRec2020;

// ProPhoto primaries (this has a D50 white point).
extern SK_API SkColorSpacePrimaries kSkColorSpacePrimariesProPhotoD50;

// Primaries where the colors are rotated and the gamut is huge. Good for
// testing.
extern SK_API SkColorSpacePrimaries kSkColorSpacePrimariesWideGamutColorSpin;

} // namespace skia

#endif // SKIA_EXT_SKCOLORSPACE_PRIMARIES_H_
59 changes: 59 additions & 0 deletions skia/ext/skcolorspace_primaries_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright 2022 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "skia/ext/skcolorspace_primaries.h"

#include "testing/gtest/include/gtest/gtest.h"

namespace skia {
namespace {

constexpr float kEpsilon = 0.0001;

TEST(SkiaUtils, PrimariesD65) {
// DCI P3 (D65)
const auto p3 = kSkColorSpacePrimariesP3;

skcms_Matrix3x3 matrix;
EXPECT_TRUE(p3.toXYZD50(&matrix));
const auto primaries_from_matrix = GetD65PrimariesFromToXYZD50Matrix(matrix);

// The retrieved primaries from the matrix should be the same as the original
// primaries, because the original primaries had a D65 white point.
EXPECT_NEAR(p3.fRX, primaries_from_matrix.fRX, kEpsilon);
EXPECT_NEAR(p3.fRY, primaries_from_matrix.fRY, kEpsilon);
EXPECT_NEAR(p3.fGX, primaries_from_matrix.fGX, kEpsilon);
EXPECT_NEAR(p3.fGY, primaries_from_matrix.fGY, kEpsilon);
EXPECT_NEAR(p3.fBX, primaries_from_matrix.fBX, kEpsilon);
EXPECT_NEAR(p3.fBY, primaries_from_matrix.fBY, kEpsilon);
EXPECT_NEAR(p3.fWX, primaries_from_matrix.fWX, kEpsilon);
EXPECT_NEAR(p3.fWY, primaries_from_matrix.fWY, kEpsilon);
}

TEST(SkiaUtils, PrimariesD50) {
// ProPhoto (D50)
const auto pro_photo = kSkColorSpacePrimariesProPhotoD50;

// Convert primaries to a matrix.
skcms_Matrix3x3 pro_photo_matrix;
EXPECT_TRUE(pro_photo.toXYZD50(&pro_photo_matrix));

// The convert the matrix back to primaries with a D65 white point.
const auto d65 = GetD65PrimariesFromToXYZD50Matrix(pro_photo_matrix);

// And then convert the D65 primaries to a matrix.
skcms_Matrix3x3 d65_matrix;
EXPECT_TRUE(d65.toXYZD50(&d65_matrix));

// The two matrices should be the same, but the primaries will not be.
EXPECT_FALSE(pro_photo == d65);
for (size_t i = 0; i < 3; ++i) {
for (size_t j = 0; j < 3; ++j) {
EXPECT_NEAR(pro_photo_matrix.vals[i][j], d65_matrix.vals[i][j], kEpsilon);
}
}
}

} // namespace
} // namespace skia
2 changes: 1 addition & 1 deletion ui/display/util/display_util_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ TEST(DisplayUtilTest, GetColorSpaceFromEdid) {
3);

// Test with a display that supports HDR: Chromebook Samsung Galaxy (kohaku).
constexpr SkColorSpacePrimaries expected_hdr_primaries = {.fRX = 0.67960f,
constexpr SkColorSpacePrimaries expected_hdr_primaries = {.fRX = 0.67970f,
.fRY = 0.31930f,
.fGX = 0.23240f,
.fGY = 0.71870f,
Expand Down
Loading

0 comments on commit 102eed6

Please sign in to comment.