Add kRG_88_SkColorType

Bug: skia:9121

Change-Id: Id2a12a5d607b84ce393d2b58233bf8e23f646059
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/235797
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/tests/BackendAllocationTest.cpp b/tests/BackendAllocationTest.cpp
index 70a1c6b..8632dad 100644
--- a/tests/BackendAllocationTest.cpp
+++ b/tests/BackendAllocationTest.cpp
@@ -47,7 +47,7 @@
         return;
     }
 
-    if (GrRenderable::kYes == renderable) {
+    if (GrRenderable::kYes == renderable && context->colorTypeSupportedAsSurface(skColorType)) {
         sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(context,
                                                                   backendTex,
                                                                   kTopLeft_GrSurfaceOrigin,
@@ -176,7 +176,7 @@
     SkAssertResult(actual.tryAlloc(ii));
     actual.erase(SkColors::kTransparent);
 
-    if (GrRenderable::kYes == renderable) {
+    if (GrRenderable::kYes == renderable && context->colorTypeSupportedAsSurface(skColorType)) {
         sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(context,
                                                                   backendTex,
                                                                   kTopLeft_GrSurfaceOrigin,
@@ -426,6 +426,7 @@
         { kRGBA_F16Norm_SkColorType, kRGBA_half_Clamped_GrPixelConfig, SkColors::kLtGray   },
         { kRGBA_F16_SkColorType,     kRGBA_half_GrPixelConfig,         SkColors::kYellow   },
         { kRGBA_F32_SkColorType,     kRGBA_float_GrPixelConfig,        SkColors::kGray     },
+        { kRG_88_SkColorType,        kRG_88_GrPixelConfig,             SkColors::kRed      },
     };
 
     GR_STATIC_ASSERT(kLastEnum_SkColorType == SK_ARRAY_COUNT(combinations));
@@ -571,7 +572,7 @@
         { GrColorType::kRGBA_F16_Clamped, GR_GL_RGBA16F,              SkColors::kLtGray    },
         { GrColorType::kRGBA_F16,         GR_GL_RGBA16F,              SkColors::kYellow    },
 
-        { GrColorType::kRG_88,            GR_GL_RG8,                  { 0.5f, 0.5f, 0, 0 } },
+        { GrColorType::kRG_88,            GR_GL_RG8,                  { 1, 0.5f, 0, 1 }    },
         { GrColorType::kAlpha_F16,        GR_GL_R16F,                 { 1.0f, 0, 0, 0.5f } },
         { GrColorType::kAlpha_F16,        GR_GL_LUMINANCE16F,         kGrayCol             },
 
@@ -707,7 +708,7 @@
         { GrColorType::kRGBA_F16,         VK_FORMAT_R16G16B16A16_SFLOAT,      SkColors::kYellow   },
 
         // These backend formats don't have SkColorType equivalents
-        { GrColorType::kRG_88,            VK_FORMAT_R8G8_UNORM,               { 0.5f, 0.5f, 0, 0 }},
+        { GrColorType::kRG_88,            VK_FORMAT_R8G8_UNORM,               { 1, 0.5f, 0, 1 }   },
         { GrColorType::kAlpha_F16,        VK_FORMAT_R16_SFLOAT,               { 1.0f, 0, 0, 0.5f }},
 
         { GrColorType::kR_16,             VK_FORMAT_R16_UNORM,                SkColors::kRed      },
diff --git a/tests/BitmapTest.cpp b/tests/BitmapTest.cpp
index dbc5150..259ab08 100644
--- a/tests/BitmapTest.cpp
+++ b/tests/BitmapTest.cpp
@@ -178,20 +178,9 @@
 
 // Test that SkBitmap::ComputeOpaque() is correct for various colortypes.
 DEF_TEST(Bitmap_compute_is_opaque, r) {
-    SkColorType colorTypes[] = {
-        kAlpha_8_SkColorType,
-        kRGB_565_SkColorType,
-        kARGB_4444_SkColorType,
-        kRGBA_8888_SkColorType,
-        kRGB_888x_SkColorType,
-        kBGRA_8888_SkColorType,
-        kRGBA_1010102_SkColorType,
-        kRGB_101010x_SkColorType,
-        kGray_8_SkColorType,
-        kRGBA_F16_SkColorType,
-        kRGBA_F32_SkColorType,
-    };
-    for (auto ct : colorTypes) {
+
+    for (int i = 1; i <= kLastEnum_SkColorType; ++i) {
+        SkColorType ct = (SkColorType) i;
         SkBitmap bm;
         SkAlphaType at = SkColorTypeIsAlwaysOpaque(ct) ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
         bm.allocPixels(SkImageInfo::Make(13, 17, ct, at));
@@ -342,6 +331,7 @@
     } recs[] = {
         { kRGB_565_SkColorType,     opaque },
         { kGray_8_SkColorType,      opaque },
+        { kRG_88_SkColorType,       opaque },
         { kRGB_888x_SkColorType,    opaque },
         { kRGB_101010x_SkColorType, opaque },
 
diff --git a/tests/DeferredDisplayListTest.cpp b/tests/DeferredDisplayListTest.cpp
index 03b12e1..7328dd0 100644
--- a/tests/DeferredDisplayListTest.cpp
+++ b/tests/DeferredDisplayListTest.cpp
@@ -144,6 +144,10 @@
     SkSurfaceCharacterization createCharacterization(GrContext* context) const {
         size_t maxResourceBytes = context->getResourceCacheLimit();
 
+        if (!context->colorTypeSupportedAsSurface(fColorType)) {
+            return SkSurfaceCharacterization();
+        }
+
         // Note that Ganesh doesn't make use of the SkImageInfo's alphaType
         SkImageInfo ii = SkImageInfo::Make(fWidth, fHeight, fColorType,
                                            kPremul_SkAlphaType, fColorSpace);
diff --git a/tests/ExtendedSkColorTypeTests.cpp b/tests/ExtendedSkColorTypeTests.cpp
new file mode 100644
index 0000000..db8fb65
--- /dev/null
+++ b/tests/ExtendedSkColorTypeTests.cpp
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/core/SkImage.h"
+#include "include/core/SkSurface.h"
+#include "src/core/SkAutoPixmapStorage.h"
+#include "src/gpu/GrContextPriv.h"
+
+#include "tests/Test.h"
+#include "tests/TestUtils.h"
+
+static constexpr int kSize = 32;
+
+static SkColor4f get_trans_black_expected_color(SkColorTypeComponentFlag components) {
+    float a = 0;
+    if (!(components & kAlpha_SkColorTypeComponentFlag)) {
+        a = 1;
+    }
+
+    return { 0, 0, 0, a };
+}
+
+static SkColor4f get_opaque_white_expected_color(SkColorTypeComponentFlag components) {
+
+    if (components & kGray_SkColorTypeComponentFlag) {
+        return { 1, 1, 1, 1 };
+    }
+
+    float r = 1, g = 1, b = 1;
+    if (!(components & kRed_SkColorTypeComponentFlag)) {
+        r = 0;
+    }
+    if (!(components & kGreen_SkColorTypeComponentFlag)) {
+        g = 0;
+    }
+    if (!(components & kBlue_SkColorTypeComponentFlag)) {
+        b = 0;
+    }
+
+    return { r, g, b, 1.0f };
+}
+
+struct TestCase {
+    SkColorType              fColorType;
+    SkAlphaType              fAlphaType;
+    SkColorTypeComponentFlag fComponents;
+    bool                     fCanMakeSurfaces;
+};
+
+static const TestCase gTests[] = {
+    { kAlpha_8_SkColorType,      kPremul_SkAlphaType, kAlpha_SkColorTypeComponentFlag, true  },
+    { kRGB_565_SkColorType,      kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags,  true  },
+    { kARGB_4444_SkColorType,    kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRGBA_8888_SkColorType,    kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRGB_888x_SkColorType,     kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags,  true  },
+    { kBGRA_8888_SkColorType,    kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRGBA_1010102_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRGB_101010x_SkColorType,  kOpaque_SkAlphaType, kRGB_SkColorTypeComponentFlags,  true  },
+    { kGray_8_SkColorType,       kOpaque_SkAlphaType, kGray_SkColorTypeComponentFlag,  true  },
+    { kRGBA_F16Norm_SkColorType, kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRGBA_F16_SkColorType,     kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRGBA_F32_SkColorType,     kPremul_SkAlphaType, kRGBA_SkColorTypeComponentFlags, true  },
+    { kRG_88_SkColorType,        kOpaque_SkAlphaType, kRG_SkColorTypeComponentFlags,   false }
+};
+
+static void raster_tests(skiatest::Reporter* reporter, const TestCase& test) {
+
+    const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
+    const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
+                                                      kUnpremul_SkAlphaType);
+
+    uint32_t actualComponents = SkColorTypeComponentFlags(test.fColorType);
+    REPORTER_ASSERT(reporter, test.fComponents == actualComponents);
+
+    // Not all colorTypes can be drawn to
+    {
+        auto s = SkSurface::MakeRaster(nativeII);
+        REPORTER_ASSERT(reporter, SkToBool(s) == test.fCanMakeSurfaces);
+    }
+
+    // opaque formats should make transparent black become opaque
+    {
+        SkAutoPixmapStorage pm;
+        pm.alloc(nativeII);
+        pm.erase(SkColors::kTransparent);
+        SkColor actual = pm.getColor(0, 0);
+        SkColor4f expected = get_trans_black_expected_color(test.fComponents);
+        REPORTER_ASSERT(reporter, expected.toSkColor() == actual);
+    }
+
+    // unused channels should drop out
+    {
+        SkAutoPixmapStorage pm;
+        pm.alloc(nativeII);
+        pm.erase(SkColors::kWhite);
+        SkColor actual = pm.getColor(0, 0);
+        SkColor4f expected = get_opaque_white_expected_color(test.fComponents);
+        REPORTER_ASSERT(reporter, expected.toSkColor() == actual);
+    }
+
+    // Reading back from an image to the same colorType should always work
+    {
+        SkAutoPixmapStorage srcPM;
+        srcPM.alloc(nativeII);
+        srcPM.erase(SkColors::kWhite);
+        auto i = SkImage::MakeFromRaster(srcPM, nullptr, nullptr);
+        REPORTER_ASSERT(reporter, SkToBool(i));
+
+        SkAutoPixmapStorage readbackPM;
+        readbackPM.alloc(nativeII);
+        readbackPM.erase(SkColors::kTransparent);
+
+        REPORTER_ASSERT(reporter, i->readPixels(readbackPM, 0, 0));
+
+        SkColor expected = srcPM.getColor(0, 0);
+        SkColor actual = readbackPM.getColor(0, 0);
+        REPORTER_ASSERT(reporter, expected == actual);
+    }
+
+    // Rendering to an F32 surface should always work
+    {
+        SkAutoPixmapStorage srcPM;
+        srcPM.alloc(nativeII);
+        srcPM.erase(SkColors::kWhite);
+        auto i = SkImage::MakeFromRaster(srcPM, nullptr, nullptr);
+        REPORTER_ASSERT(reporter, SkToBool(i));
+
+        auto s = SkSurface::MakeRaster(f32Unpremul);
+        REPORTER_ASSERT(reporter, SkToBool(s));
+
+        {
+            auto c = s->getCanvas();
+            c->drawImage(i, 0, 0);
+        }
+
+        SkAutoPixmapStorage readbackPM;
+        readbackPM.alloc(f32Unpremul);
+        readbackPM.erase(SkColors::kTransparent);
+
+        REPORTER_ASSERT(reporter, i->readPixels(readbackPM, 0, 0));
+
+        SkColor expected = srcPM.getColor(0, 0);
+        SkColor actual = readbackPM.getColor(0, 0);
+        REPORTER_ASSERT(reporter, expected == actual);
+    }
+}
+
+static void compare_pixmaps(skiatest::Reporter* reporter,
+                            const SkPixmap& expected, const SkPixmap& actual,
+                            SkColorType nativeCT, const char* label) {
+    const float tols[4] = {0.0f, 0.0f, 0.0f, 0};
+
+    auto error = std::function<ComparePixmapsErrorReporter>(
+        [reporter, nativeCT, label](int x, int y, const float diffs[4]) {
+            SkASSERT(x >= 0 && y >= 0);
+            ERRORF(reporter, "%d %s - mismatch at %d, %d (%f, %f, %f %f)",
+                   nativeCT, label, x, y,
+                   diffs[0], diffs[1], diffs[2], diffs[3]);
+        });
+
+    compare_pixels(expected, actual, tols, error);
+}
+
+static void gpu_tests(GrContext* context, skiatest::Reporter* reporter, const TestCase& test) {
+
+    const SkImageInfo nativeII = SkImageInfo::Make(kSize, kSize, test.fColorType, test.fAlphaType);
+    const SkImageInfo f32Unpremul = SkImageInfo::Make(kSize, kSize, kRGBA_F32_SkColorType,
+                                                      kUnpremul_SkAlphaType);
+
+    // We had better not be able to render to prohibited colorTypes
+    if (!test.fCanMakeSurfaces) {
+        auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, nativeII);
+        REPORTER_ASSERT(reporter, !SkToBool(s));
+    }
+
+    if (!context->colorTypeSupportedAsImage(test.fColorType)) {
+        return;
+    }
+
+    SkAutoPixmapStorage nativeExpected;
+    nativeExpected.alloc(nativeII);
+    nativeExpected.erase(SkColors::kWhite);
+
+    for (bool fullInit : { false, true }) {
+        GrBackendTexture backendTex;
+
+        if (fullInit) {
+            backendTex = context->priv().createBackendTexture(&nativeExpected, 1,
+                                                              GrRenderable::kNo,
+                                                              GrProtected::kNo);
+        } else {
+            backendTex = context->createBackendTexture(kSize, kSize, test.fColorType,
+                                                       SkColors::kWhite, GrMipMapped::kNo,
+                                                       GrRenderable::kNo, GrProtected::kNo);
+        }
+        REPORTER_ASSERT(reporter, backendTex.isValid());
+
+        auto img = SkImage::MakeFromTexture(context, backendTex, kTopLeft_GrSurfaceOrigin,
+                                            test.fColorType, test.fAlphaType, nullptr);
+        REPORTER_ASSERT(reporter, SkToBool(img));
+
+        {
+            SkAutoPixmapStorage nativeActual;
+            nativeActual.alloc(nativeII);
+            nativeActual.erase(SkColors::kTransparent);
+
+            if (img->readPixels(nativeActual, 0, 0)) {
+                compare_pixmaps(reporter, nativeExpected, nativeActual,
+                                test.fColorType, "SkImage::readPixels to native CT");
+            }
+
+            // SkSurface::readPixels with the same colorType as the source pixels round trips
+            // (when allowed)
+            if (context->colorTypeSupportedAsSurface(test.fColorType)) {
+                auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, nativeII);
+                REPORTER_ASSERT(reporter, SkToBool(s));
+
+                {
+                    SkCanvas* c = s->getCanvas();
+                    c->drawImage(img, 0, 0);
+                }
+
+                nativeActual.erase(SkColors::kTransparent);
+                REPORTER_ASSERT(reporter, s->readPixels(nativeActual, 0, 0));
+
+                compare_pixmaps(reporter, nativeExpected, nativeActual,
+                                test.fColorType, "SkSurface::readPixels to native CT");
+            }
+        }
+
+        {
+            SkAutoPixmapStorage f32Expected;
+            f32Expected.alloc(f32Unpremul);
+            f32Expected.erase(get_opaque_white_expected_color(test.fComponents));
+
+            // read back to F32 if possible
+            {
+                SkAutoPixmapStorage f32Actual;
+                f32Actual.alloc(f32Unpremul);
+                f32Actual.erase(SkColors::kTransparent);
+                if (img->readPixels(f32Actual, 0, 0)) {
+                    compare_pixmaps(reporter, f32Expected, f32Actual,
+                                    test.fColorType, "SkImage::readPixels to F32");
+                }
+            }
+
+            // drawing a native SkImage works appropriately (as assessed by reading back from an
+            // RGBA8 surface to an F32 pixmap)
+            {
+                const SkImageInfo rgba8888Premul = SkImageInfo::Make(kSize, kSize,
+                                                                     kRGBA_8888_SkColorType,
+                                                                     kPremul_SkAlphaType);
+
+                auto s = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, rgba8888Premul);
+                REPORTER_ASSERT(reporter, SkToBool(s));
+
+                {
+                    SkCanvas* c = s->getCanvas();
+                    c->drawImage(img, 0, 0);
+                }
+
+                SkAutoPixmapStorage f32Actual;
+                f32Actual.alloc(f32Unpremul);
+                f32Actual.erase(SkColors::kTransparent);
+                REPORTER_ASSERT(reporter, s->readPixels(f32Actual, 0, 0));
+
+                compare_pixmaps(reporter, f32Expected, f32Actual,
+                                test.fColorType, "SkSurface::drawn to RGBA8888");
+            }
+        }
+
+        img.reset();
+        context->flush();
+        context->deleteBackendTexture(backendTex);
+    }
+}
+
+DEF_TEST(ExtendedSkColorTypeTests_raster, reporter) {
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
+        raster_tests(reporter, gTests[i]);
+    }
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ExtendedSkColorTypeTests_gpu, reporter, ctxInfo) {
+    GrContext* context = ctxInfo.grContext();
+
+    for (size_t i = 0; i < SK_ARRAY_COUNT(gTests); ++i) {
+        gpu_tests(context, reporter, gTests[i]);
+    }
+}
diff --git a/tests/MtlBackendAllocationTest.mm b/tests/MtlBackendAllocationTest.mm
index 3137e23..81803d6 100644
--- a/tests/MtlBackendAllocationTest.mm
+++ b/tests/MtlBackendAllocationTest.mm
@@ -63,7 +63,7 @@
         { GrColorType::kRGBA_F16_Clamped, MTLPixelFormatRGBA16Float,     SkColors::kLtGray    },
         { GrColorType::kRGBA_F16,         MTLPixelFormatRGBA16Float,     SkColors::kYellow    },
 
-        { GrColorType::kRG_88,            MTLPixelFormatRG8Unorm,        { 0.5f, 0.5f, 0, 0 } },
+        { GrColorType::kRG_88,            MTLPixelFormatRG8Unorm,        { 0.5f, 0.5f, 0, 1 } },
         { GrColorType::kAlpha_F16,        MTLPixelFormatR16Float,        { 1.0f, 0, 0, 0.5f } },
 
         { GrColorType::kR_16,             MTLPixelFormatR16Unorm,        SkColors::kRed       },
diff --git a/tests/ReadPixelsTest.cpp b/tests/ReadPixelsTest.cpp
index 438f2ca..b1450a1 100644
--- a/tests/ReadPixelsTest.cpp
+++ b/tests/ReadPixelsTest.cpp
@@ -626,6 +626,7 @@
         case kAlpha_8_SkColorType:      return 8;
         case kRGB_565_SkColorType:      return 5;
         case kARGB_4444_SkColorType:    return 4;
+        case kRG_88_SkColorType:        return 8;
         case kRGBA_8888_SkColorType:    return 8;
         case kRGB_888x_SkColorType:     return 8;
         case kBGRA_8888_SkColorType:    return 8;