Added kSRGBLinear_Named color space, along with tests
authorbrianosman <brianosman@google.com>
Tue, 27 Sep 2016 22:11:47 +0000 (15:11 -0700)
committerCommit bot <commit-bot@chromium.org>
Tue, 27 Sep 2016 22:11:47 +0000 (15:11 -0700)
Gradients (and other shaders) are going to end up serializing this
particular color space very frequently, so we want a shorthand way of
writing it out. I think it's also helpful to have a clearer way of
creating it (vs. NewNamed(kSRGB_Named)->makeLinearGamma()).

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2377763002

Review-Url: https://codereview.chromium.org/2377763002

gm/colorspacexform.cpp
include/core/SkColorSpace.h
src/core/SkColorSpace.cpp
src/effects/gradients/SkGradientShader.cpp
tests/ColorSpaceTest.cpp
tests/SurfaceTest.cpp

index 7e3285efbd57c4236d63e731db0bea4e009b01aa..34abdc4b79e7f828cbec7bde81892d6fdb322891 100644 (file)
@@ -60,8 +60,7 @@ protected:
 
             canvas->save();
             for (int i = 0; i < kNumColors; i++) {
-                sk_sp<SkColorSpace> space =
-                        SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+                sk_sp<SkColorSpace> space = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
                 sk_sp<SkShader> s = SkShader::MakeColorShader(colors[i], space);
                 SkPaint paint;
                 paint.setShader(s);
index b2b005e4aa6b8c2e6e82b4f36474a5daec68dea9..a6a800d140d9e0faf408cc50896dcdb0a893429c 100644 (file)
@@ -31,6 +31,12 @@ public:
          *  Often used by images and monitors.
          */
         kAdobeRGB_Named,
+
+        /**
+         *  Colorspace with the sRGB primaries, but a linear (1.0) gamma. Commonly used for
+         *  half-float surfaces, and high precision individual colors (gradient stops, etc...)
+         */
+        kSRGBLinear_Named,
     };
 
     enum RenderTargetGamma : uint8_t {
index 90fc96e111ea0eddc2f24a01565aaacb4b36f59c..225cfe146451d7e0f154abec8e9d1b0441326582 100644 (file)
@@ -113,6 +113,11 @@ sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(SkGammaNamed gammaNamed, const SkM
                 return SkColorSpace::NewNamed(kAdobeRGB_Named);
             }
             break;
+        case kLinear_SkGammaNamed:
+            if (xyz_almost_equal(toXYZD50, gSRGB_toXYZD50)) {
+                return SkColorSpace::NewNamed(kSRGBLinear_Named);
+            }
+            break;
         case kNonStandard_SkGammaNamed:
             // This is not allowed.
             return nullptr;
@@ -136,10 +141,12 @@ sk_sp<SkColorSpace> SkColorSpace::NewRGB(RenderTargetGamma gamma, const SkMatrix
 
 static SkColorSpace* gAdobeRGB;
 static SkColorSpace* gSRGB;
+static SkColorSpace* gSRGBLinear;
 
 sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) {
     static SkOnce sRGBOnce;
     static SkOnce adobeRGBOnce;
+    static SkOnce sRGBLinearOnce;
 
     switch (named) {
         case kSRGB_Named: {
@@ -164,6 +171,17 @@ sk_sp<SkColorSpace> SkColorSpace::NewNamed(Named named) {
             });
             return sk_ref_sp<SkColorSpace>(gAdobeRGB);
         }
+        case kSRGBLinear_Named: {
+            sRGBLinearOnce([] {
+                SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
+                srgbToxyzD50.set3x3RowMajorf(gSRGB_toXYZD50);
+
+                // Force the mutable type mask to be computed.  This avoids races.
+                (void)srgbToxyzD50.getType();
+                gSRGBLinear = new SkColorSpace_Base(kLinear_SkGammaNamed, srgbToxyzD50);
+            });
+            return sk_ref_sp<SkColorSpace>(gSRGBLinear);
+        }
         default:
             break;
     }
@@ -238,7 +256,7 @@ struct ColorSpaceHeader {
         SkASSERT(k0_Version == version);
         header.fVersion = (uint8_t) version;
 
-        SkASSERT(named <= SkColorSpace::kAdobeRGB_Named);
+        SkASSERT(named <= SkColorSpace::kSRGBLinear_Named);
         header.fNamed = (uint8_t) named;
 
         SkASSERT(gammaNamed <= kNonStandard_SkGammaNamed);
@@ -273,6 +291,14 @@ size_t SkColorSpace::writeToMemory(void* memory) const {
                         ColorSpaceHeader::Pack(k0_Version, kAdobeRGB_Named,
                                                as_CSB(this)->fGammaNamed, 0);
             }
+            return sizeof(ColorSpaceHeader);
+        } else if (this == gSRGBLinear) {
+            if (memory) {
+                *((ColorSpaceHeader*)memory) =
+                        ColorSpaceHeader::Pack(k0_Version, kSRGBLinear_Named,
+                                               as_CSB(this)->fGammaNamed, 0);
+            }
+            return sizeof(ColorSpaceHeader);
         }
 
         // If we have a named gamma, write the enum and the matrix.
index 31ff9ab8779cbaad20e0f2db94357ee5b66647a8..0faf006d73b9de01f7d363be6114a3b48876c33b 100644 (file)
@@ -141,7 +141,7 @@ SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatri
         }
 
         // Color space refers to fColors4f, so it's always linear gamma
-        fColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+        fColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
     } else {
         SkASSERT(desc.fColors4f && desc.fColorSpace && desc.fColorSpace->gammaIsLinear());
 
@@ -683,10 +683,9 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap,
                                              SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named));
                     break;
                 case GradientBitmapType::kHalfFloat:
-                    info = SkImageInfo::Make(kCache32Count, 1, kRGBA_F16_SkColorType,
-                                             kPremul_SkAlphaType,
-                                             SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)
-                                                ->makeLinearGamma());
+                    info = SkImageInfo::Make(
+                        kCache32Count, 1, kRGBA_F16_SkColorType, kPremul_SkAlphaType,
+                        SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named));
                     break;
                 default:
                     SkFAIL("Unexpected bitmap type");
index 7e247d304d60860329966a4e58af8fef288df619..d749931de1ffac3664f3a44d52e7be07e23dd5cb 100644 (file)
@@ -115,6 +115,29 @@ DEF_TEST(ColorSpaceSRGBCompare, r) {
     REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace);
 }
 
+DEF_TEST(ColorSpaceSRGBLinearCompare, r) {
+    // Create the linear sRGB color space by name
+    sk_sp<SkColorSpace> namedColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
+
+    // Create the linear sRGB color space via the sRGB color space's makeLinearGamma()
+    sk_sp<SkColorSpace> viaSrgbColorSpace =
+        SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)->makeLinearGamma();
+    REPORTER_ASSERT(r, namedColorSpace == viaSrgbColorSpace);
+
+    // Create a linear sRGB color space by value
+    SkMatrix44 srgbToxyzD50(SkMatrix44::kUninitialized_Constructor);
+    srgbToxyzD50.set3x3RowMajorf(g_sRGB_XYZ);
+    sk_sp<SkColorSpace> rgbColorSpace =
+        SkColorSpace::NewRGB(SkColorSpace::kLinear_RenderTargetGamma, srgbToxyzD50);
+    REPORTER_ASSERT(r, rgbColorSpace == namedColorSpace);
+
+    // Change a single value from the sRGB matrix
+    srgbToxyzD50.set(2, 2, 0.5f);
+    sk_sp<SkColorSpace> strangeColorSpace =
+        SkColorSpace::NewRGB(SkColorSpace::kLinear_RenderTargetGamma, srgbToxyzD50);
+    REPORTER_ASSERT(r, strangeColorSpace != namedColorSpace);
+}
+
 class ColorSpaceTest {
 public:
     static sk_sp<SkData> WriteToICC(SkColorSpace* space) {
@@ -150,21 +173,18 @@ DEF_TEST(ColorSpaceWriteICC, r) {
 DEF_TEST(ColorSpace_Named, r) {
     const struct {
         SkColorSpace::Named fNamed;
-        bool fIsSRGB;
+        SkGammaNamed fExpectedGamma;
     } recs[] {
-        { SkColorSpace::kSRGB_Named,     true },
-        { SkColorSpace::kAdobeRGB_Named, false },
+        { SkColorSpace::kSRGB_Named,       kSRGB_SkGammaNamed },
+        { SkColorSpace::kAdobeRGB_Named,   k2Dot2Curve_SkGammaNamed },
+        { SkColorSpace::kSRGBLinear_Named, kLinear_SkGammaNamed },
     };
 
     for (auto rec : recs) {
         auto cs = SkColorSpace::NewNamed(rec.fNamed);
         REPORTER_ASSERT(r, cs);
         if (cs) {
-            if (rec.fIsSRGB) {
-                REPORTER_ASSERT(r, kSRGB_SkGammaNamed == as_CSB(cs)->gammaNamed());
-            } else {
-                REPORTER_ASSERT(r, k2Dot2Curve_SkGammaNamed == as_CSB(cs)->gammaNamed());
-            }
+            REPORTER_ASSERT(r, rec.fExpectedGamma == as_CSB(cs)->gammaNamed());
         }
     }
 
@@ -194,6 +214,7 @@ static void test_serialize(skiatest::Reporter* r, SkColorSpace* space, bool isNa
 DEF_TEST(ColorSpace_Serialize, r) {
     test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).get(), true);
     test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kAdobeRGB_Named).get(), true);
+    test_serialize(r, SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named).get(), true);
 
     sk_sp<SkData> monitorData = SkData::MakeFromFileName(
             GetResourcePath("icc_profiles/HP_ZR30w.icc").c_str());
index 775b8c6c0567c527aa6f76de15fbe7bfb3f40b78..6706fef7e4e1051d8b2f7ec5fe83496385f6bdec 100644 (file)
@@ -924,7 +924,7 @@ static void test_surface_creation_and_snapshot_with_color_space(
     SkMatrix44 srgbMatrix = srgbColorSpace->toXYZD50();
     const float oddGamma[] = { 2.4f, 2.4f, 2.4f };
     auto oddColorSpace = SkColorSpace_Base::NewRGB(oddGamma, srgbMatrix);
-    auto linearColorSpace = srgbColorSpace->makeLinearGamma();
+    auto linearColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGBLinear_Named);
 
     const struct {
         SkColorType         fColorType;