non-linear blending first steps

Code:
  - Add a non-linear blending bit and makeNonlinearBlending()
    to SkColorSpace
  - remove enough F16=linear checks to make it possible to
    create surfaces and encode pngs with nonlinear F16

Testing:
  - add "esrgb" software config to DM, run it
  - add "srgbnl" software config, run it
  - deemphasize importance of "srgb" config on bots
  - update unit tests to reflect relaxed F16 constraints
  - add a new unit test file with _really_ basic tests,
    and a new unit test that's not working yet

Bug: skia:7942

Change-Id: I8ac042bdf9f3d791765393b68fd9256375184d83
Reviewed-on: https://skia-review.googlesource.com/127325
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
index 53fa6f4..f67e6c0 100644
--- a/src/codec/SkCodec.cpp
+++ b/src/codec/SkCodec.cpp
@@ -169,7 +169,7 @@
         case kBGRA_8888_SkColorType:
             return true;
         case kRGBA_F16_SkColorType:
-            return dst.colorSpace() && dst.colorSpace()->gammaIsLinear();
+            return dst.colorSpace();
         case kRGB_565_SkColorType:
             return srcIsOpaque;
         case kGray_8_SkColorType:
diff --git a/src/codec/SkHeifCodec.cpp b/src/codec/SkHeifCodec.cpp
index 6e82904..31057a0 100644
--- a/src/codec/SkHeifCodec.cpp
+++ b/src/codec/SkHeifCodec.cpp
@@ -192,10 +192,6 @@
 
         case kRGBA_F16_SkColorType:
             SkASSERT(this->colorXform());
-
-            if (!dstInfo.colorSpace()->gammaIsLinear()) {
-                return false;
-            }
             return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
 
         default:
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index 2cc7921..d44258f 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -433,11 +433,6 @@
             break;
         case kRGBA_F16_SkColorType:
             SkASSERT(this->colorXform());
-
-            if (!dstInfo.colorSpace()->gammaIsLinear()) {
-                return false;
-            }
-
             fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
             break;
         default:
diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp
index d8b1028..b5fd591 100644
--- a/src/codec/SkWbmpCodec.cpp
+++ b/src/codec/SkWbmpCodec.cpp
@@ -29,7 +29,7 @@
         case kRGB_565_SkColorType:
             return true;
         case kRGBA_F16_SkColorType:
-            return dstInfo.colorSpace() && dstInfo.colorSpace()->gammaIsLinear();
+            return dstInfo.colorSpace();
         default:
             return false;
     }
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp
index be399bd..b75edce 100644
--- a/src/core/SkColorSpace.cpp
+++ b/src/core/SkColorSpace.cpp
@@ -500,6 +500,10 @@
         return false;
     }
 
+    if (src->nonlinearBlending() != dst->nonlinearBlending()) {
+        return false;
+    }
+
     const SkData* srcData = src->onProfileData();
     const SkData* dstData = dst->onProfileData();
     if (srcData || dstData) {
diff --git a/src/core/SkColorSpace_XYZ.cpp b/src/core/SkColorSpace_XYZ.cpp
index 17462a1..968f01d 100644
--- a/src/core/SkColorSpace_XYZ.cpp
+++ b/src/core/SkColorSpace_XYZ.cpp
@@ -119,3 +119,13 @@
     tables[1] = fToDstGammaTables[1];
     tables[2] = fToDstGammaTables[2];
 }
+
+sk_sp<SkColorSpace> SkColorSpace_XYZ::makeNonlinearBlending() const {
+    if (this->nonlinearBlending()) {
+        return sk_ref_sp(const_cast<SkColorSpace_XYZ*>(this));
+    }
+
+    auto cs = sk_make_sp<SkColorSpace_XYZ>(fGammaNamed, fGammas, fToXYZD50, fProfileData);
+    cs->fNonlinearBlending = true;
+    return cs;
+}
diff --git a/src/core/SkColorSpace_XYZ.h b/src/core/SkColorSpace_XYZ.h
index 2ad2e38..d0984ec 100644
--- a/src/core/SkColorSpace_XYZ.h
+++ b/src/core/SkColorSpace_XYZ.h
@@ -23,12 +23,14 @@
     bool onGammaCloseToSRGB() const override;
     bool onGammaIsLinear() const override;
     bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override;
+    bool nonlinearBlending() const override { return fNonlinearBlending; }
 
     const SkData* onProfileData() const override { return fProfileData.get(); }
 
     sk_sp<SkColorSpace> makeLinearGamma() const override;
     sk_sp<SkColorSpace> makeSRGBGamma() const override;
     sk_sp<SkColorSpace> makeColorSpin() const override;
+    sk_sp<SkColorSpace> makeNonlinearBlending() const override;
 
     SkGammaNamed onGammaNamed() const override { return fGammaNamed; }
 
@@ -56,6 +58,8 @@
     mutable const uint8_t* fToDstGammaTables[3];
     mutable SkOnce         fToDstGammaOnce;
 
+    bool fNonlinearBlending = false;
+
     friend class SkColorSpace;
     friend class ColorSpaceXformTest;
 };
diff --git a/src/core/SkPictureImageGenerator.cpp b/src/core/SkPictureImageGenerator.cpp
index 4b68ffd..f17ff64 100644
--- a/src/core/SkPictureImageGenerator.cpp
+++ b/src/core/SkPictureImageGenerator.cpp
@@ -23,10 +23,6 @@
         return nullptr;
     }
 
-    if (SkImage::BitDepth::kF16 == bitDepth && (!colorSpace || !colorSpace->gammaIsLinear())) {
-        return nullptr;
-    }
-
     if (colorSpace && (!colorSpace->gammaCloseToSRGB() && !colorSpace->gammaIsLinear())) {
         return nullptr;
     }
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 99465f6..60586ea 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -300,6 +300,7 @@
     if (!colorSpace) {
         return kRGBA_8888_GrPixelConfig;
     } else if (colorSpace->gammaIsLinear()) {
+        // TODO
         return kRGBA_half_GrPixelConfig;
     } else if (colorSpace->gammaCloseToSRGB()) {
         return kSRGBA_8888_GrPixelConfig;
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index b646f9e..d86b316 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -271,7 +271,7 @@
 bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
     switch (info.colorType()) {
         case kRGBA_F16_SkColorType:
-            return (!info.colorSpace()) || info.colorSpace()->gammaIsLinear();
+            return true;
         case kRGBA_8888_SkColorType:
         case kBGRA_8888_SkColorType:
             return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB();
@@ -283,7 +283,7 @@
 bool SkSurface_Gpu::Valid(const GrCaps* caps, GrPixelConfig config, SkColorSpace* colorSpace) {
     switch (config) {
         case kRGBA_half_GrPixelConfig:
-            return (!colorSpace) || colorSpace->gammaIsLinear();
+            return true;
         case kSRGBA_8888_GrPixelConfig:
         case kSBGRA_8888_GrPixelConfig:
             return caps->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB();
diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp
index 47d5542..fd12007 100644
--- a/src/image/SkSurface_Raster.cpp
+++ b/src/image/SkSurface_Raster.cpp
@@ -68,9 +68,6 @@
             }
             break;
         case kRGBA_F16_SkColorType:
-            if (info.colorSpace() && (!info.colorSpace()->gammaIsLinear())) {
-                return false;
-            }
             break;
         default:
             return false;
diff --git a/src/images/SkJpegEncoder.cpp b/src/images/SkJpegEncoder.cpp
index 305152d..606b553 100644
--- a/src/images/SkJpegEncoder.cpp
+++ b/src/images/SkJpegEncoder.cpp
@@ -118,7 +118,7 @@
             numComponents = 1;
             break;
         case kRGBA_F16_SkColorType:
-            if (!srcInfo.colorSpace() || !srcInfo.colorSpace()->gammaIsLinear() ||
+            if (!srcInfo.colorSpace() ||
                     SkTransferFunctionBehavior::kRespect != options.fBlendBehavior) {
                 return false;
             }
diff --git a/src/images/SkPngEncoder.cpp b/src/images/SkPngEncoder.cpp
index c7952df..19fc27e 100644
--- a/src/images/SkPngEncoder.cpp
+++ b/src/images/SkPngEncoder.cpp
@@ -106,7 +106,7 @@
     int bitDepth = 8;
     switch (srcInfo.colorType()) {
         case kRGBA_F16_SkColorType:
-            SkASSERT(srcInfo.colorSpace() && srcInfo.colorSpace()->gammaIsLinear());
+            SkASSERT(srcInfo.colorSpace());
             sigBit.red = 16;
             sigBit.green = 16;
             sigBit.blue = 16;
diff --git a/src/images/SkWebpEncoder.cpp b/src/images/SkWebpEncoder.cpp
index a7809b2..ee13563 100644
--- a/src/images/SkWebpEncoder.cpp
+++ b/src/images/SkWebpEncoder.cpp
@@ -88,10 +88,6 @@
         case kGray_8_SkColorType:
             return transform_scanline_gray;
         case kRGBA_F16_SkColorType:
-            if (!info.colorSpace() || !info.colorSpace()->gammaIsLinear()) {
-                return nullptr;
-            }
-
             switch (info.alphaType()) {
                 case kOpaque_SkAlphaType:
                 case kUnpremul_SkAlphaType: