Update comparison in BackendAllocation tests

Change-Id: I11760741251b03dfb457d4b07ef3cb6a560c6f7b
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240683
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index ee0b610..53ac706 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -1515,7 +1515,7 @@
         case GrColorType::kUnknown:          return "kUnknown";
         case GrColorType::kAlpha_8:          return "kAlpha_8";
         case GrColorType::kBGR_565:          return "kRGB_565";
-        case GrColorType::kABGR_4444:        return "kARGB_4444";
+        case GrColorType::kABGR_4444:        return "kABGR_4444";
         case GrColorType::kRGBA_8888:        return "kRGBA_8888";
         case GrColorType::kRGBA_8888_SRGB:   return "kRGBA_8888_SRGB";
         case GrColorType::kRGB_888x:         return "kRGB_888x";
diff --git a/tests/BackendAllocationTest.cpp b/tests/BackendAllocationTest.cpp
index 8632dad..276b80c 100644
--- a/tests/BackendAllocationTest.cpp
+++ b/tests/BackendAllocationTest.cpp
@@ -12,6 +12,8 @@
 #include "src/gpu/GrContextPriv.h"
 #include "src/image/SkImage_Base.h"
 #include "tests/Test.h"
+#include "tests/TestUtils.h"
+#include "tools/ToolUtils.h"
 
 #ifdef SK_GL
 #include "src/gpu/gl/GrGLGpu.h"
@@ -91,38 +93,51 @@
     context->deleteBackendTexture(backendTex);
 }
 
-static bool colors_eq(SkColor colA, SkColor colB, int tol) {
-    int maxDiff = 0;
-    for (int i = 0; i < 4; ++i) {
-        int diff = SkTAbs<int>((0xFF & (colA >> i*8)) - (0xFF & (colB >> i*8)));
-        if (maxDiff < diff) {
-            maxDiff = diff;
-        }
-    }
+static void check_solid_pixmap(skiatest::Reporter* reporter,
+                               const SkColor4f& expected, const SkPixmap& actual,
+                               SkColorType ct, const char* label) {
+    // we need 0.001f across the board just for noise
+    // we need 0.01f across the board for 1010102
+    const float tols[4] = {0.01f, 0.01f, 0.01f, 0.01f};
 
-    return maxDiff <= tol;
+    auto error = std::function<ComparePixmapsErrorReporter>(
+        [reporter, ct, label](int x, int y, const float diffs[4]) {
+            SkASSERT(x >= 0 && y >= 0);
+            ERRORF(reporter, "%s %s - mismatch at %d, %d (%f, %f, %f %f)",
+                   ToolUtils::colortype_name(ct), label, x, y,
+                   diffs[0], diffs[1], diffs[2], diffs[3]);
+        });
+
+    check_solid_pixels(expected, actual, tols, error);
 }
 
-static void compare_pixmaps(const SkPixmap& expected, const SkPixmap& actual,
-                            SkColorType colorType, skiatest::Reporter* reporter) {
-    SkASSERT(expected.info() == actual.info());
-    for (int y = 0; y < expected.height(); ++y) {
-        for (int x = 0; x < expected.width(); ++x) {
+static SkColor4f get_expected_color(SkColor4f orig, SkColorType ct) {
 
-            SkColor expectedCol = expected.getColor(x, y);
-            SkColor actualCol = actual.getColor(x, y);
+    uint32_t components = SkColorTypeComponentFlags(ct);
 
-            // GPU and raster differ a bit on kGray_8_SkColorType and kRGBA_1010102_SkColorType
-            if (colors_eq(actualCol, expectedCol, 12)) {
-                continue;
-            }
-
-            ERRORF(reporter,
-                   "Mismatched pixels at %d %d ct: %d expected: 0x%x actual: 0x%x\n",
-                   x, y, colorType, expectedCol, actualCol);
-            return;
-        }
+    if (components & kGray_SkColorTypeComponentFlag) {
+        // For the GPU backends, gray implies a single channel which is opaque.
+        return { orig.fA, orig.fA, orig.fA, 1 };
     }
+
+    float r = orig.fR, g = orig.fG, b = orig.fB, a = orig.fA;
+
+    // Missing channels are set to 0
+    if (!(components & kRed_SkColorTypeComponentFlag)) {
+        r = 0;
+    }
+    if (!(components & kGreen_SkColorTypeComponentFlag)) {
+        g = 0;
+    }
+    if (!(components & kBlue_SkColorTypeComponentFlag)) {
+        b = 0;
+    }
+    // except for missing alpha - which gets set to 1
+    if (!(components & kAlpha_SkColorTypeComponentFlag)) {
+        a = 1;
+    }
+
+    return { r, g, b, a };
 }
 
 // Test initialization of GrBackendObjects to a specific color
@@ -153,24 +168,7 @@
 
     SkImageInfo ii = SkImageInfo::Make(32, 32, skColorType, at);
 
-    SkColor4f rasterColor = color;
-    if (kGray_8_SkColorType == skColorType) {
-        // For the GPU backends, gray implies a single channel which is opaque.
-        rasterColor.fR = color.fA;
-        rasterColor.fG = color.fA;
-        rasterColor.fB = color.fA;
-        rasterColor.fA = 1.0f;
-    } else if (kAlpha_8_SkColorType == skColorType) {
-        // For the GPU backends, alpha implies a single alpha channel.
-        rasterColor.fR = 0;
-        rasterColor.fG = 0;
-        rasterColor.fB = 0;
-        rasterColor.fA = color.fA;
-    }
-
-    SkAutoPixmapStorage expected;
-    SkAssertResult(expected.tryAlloc(ii));
-    expected.erase(rasterColor);
+    SkColor4f expectedColor = get_expected_color(color, skColorType);
 
     SkAutoPixmapStorage actual;
     SkAssertResult(actual.tryAlloc(ii));
@@ -187,7 +185,8 @@
             bool result = surf->readPixels(actual, 0, 0);
             REPORTER_ASSERT(reporter, result);
 
-            compare_pixmaps(expected, actual, skColorType, reporter);
+            check_solid_pixmap(reporter, expectedColor, actual, skColorType,
+                               "SkSurface::readPixels");
 
             actual.erase(SkColors::kTransparent);
         }
@@ -212,7 +211,8 @@
                             colorType);
 #endif
                 } else {
-                    compare_pixmaps(expected, actual, skColorType, reporter);
+                    check_solid_pixmap(reporter, expectedColor, actual, skColorType,
+                                       "SkImage::readPixels");
                 }
             }
 
@@ -235,10 +235,6 @@
                 SkImageInfo newII = SkImageInfo::Make(32, 32, kRGBA_8888_SkColorType,
                                                       kPremul_SkAlphaType);
 
-                SkAutoPixmapStorage actual2;
-                SkAssertResult(actual2.tryAlloc(newII));
-                actual2.erase(SkColors::kTransparent);
-
                 sk_sp<SkSurface> surf = SkSurface::MakeRenderTarget(context,
                                                                     SkBudgeted::kNo,
                                                                     newII, 1,
@@ -263,15 +259,18 @@
                     canvas->clear(SK_ColorTRANSPARENT);
                     canvas->drawImageRect(img, r, &p);
 
+                    SkImageInfo readbackII = SkImageInfo::Make(rectSize, rectSize,
+                                                               kRGBA_8888_SkColorType,
+                                                               kPremul_SkAlphaType);
+                    SkAutoPixmapStorage actual2;
+                    SkAssertResult(actual2.tryAlloc(readbackII));
+                    actual2.erase(SkColors::kTransparent);
+
                     bool result = surf->readPixels(actual2, 0, 0);
                     REPORTER_ASSERT(reporter, result);
 
-                    SkColor actualColor = actual2.getColor(0, 0);
-
-                    if (!colors_eq(actualColor, rasterColor.toSkColor(), 1)) {
-                        ERRORF(reporter, "Pixel mismatch colorType %d: level: %d e: 0x%x a: 0x%x\n",
-                               skColorType, i, rasterColor.toSkColor(), actualColor);
-                    }
+                    check_solid_pixmap(reporter, expectedColor, actual2, skColorType,
+                                       "mip-level failure");
                 }
             }
         }
@@ -408,25 +407,24 @@
 
     struct {
         SkColorType   fColorType;
-        GrPixelConfig fConfig;
         SkColor4f     fColor;
     } combinations[] = {
-        { kAlpha_8_SkColorType,      kAlpha_8_GrPixelConfig,           kTransCol           },
-        { kRGB_565_SkColorType,      kRGB_565_GrPixelConfig,           SkColors::kRed      },
-        { kARGB_4444_SkColorType,    kRGBA_4444_GrPixelConfig,         SkColors::kGreen    },
-        { kRGBA_8888_SkColorType,    kRGBA_8888_GrPixelConfig,         SkColors::kBlue     },
-        { kRGB_888x_SkColorType,     kRGB_888_GrPixelConfig,           SkColors::kCyan     },
+        { kAlpha_8_SkColorType,      kTransCol                },
+        { kRGB_565_SkColorType,      SkColors::kRed           },
+        { kARGB_4444_SkColorType,    SkColors::kGreen         },
+        { kRGBA_8888_SkColorType,    SkColors::kBlue          },
+        { kRGB_888x_SkColorType,     SkColors::kCyan          },
         // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
-        { kBGRA_8888_SkColorType,    kBGRA_8888_GrPixelConfig,         { 1, 0, 0, 1.0f }   },
+        { kBGRA_8888_SkColorType,    { 1, 0, 0, 1.0f }        },
         // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
-        { kRGBA_1010102_SkColorType, kRGBA_1010102_GrPixelConfig,      { 0.5f, 0, 0, 1.0f }},
+        { kRGBA_1010102_SkColorType, { .25f, .5f, .75f, 1.0f }},
         // The kRGB_101010x_SkColorType has no Ganesh correlate
-        { kRGB_101010x_SkColorType,  kUnknown_GrPixelConfig,           { 0, 0.5f, 0, 0.5f }},
-        { kGray_8_SkColorType,       kGray_8_GrPixelConfig,            kGrayCol            },
-        { 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      },
+        { kRGB_101010x_SkColorType,  { 0, 0.5f, 0, 0.5f }     },
+        { kGray_8_SkColorType,       kGrayCol                 },
+        { kRGBA_F16Norm_SkColorType, SkColors::kLtGray        },
+        { kRGBA_F16_SkColorType,     SkColors::kYellow        },
+        { kRGBA_F32_SkColorType,     SkColors::kGray          },
+        { kRG_88_SkColorType,        { .25f, .75f, 0, 0 }     },
     };
 
     GR_STATIC_ASSERT(kLastEnum_SkColorType == SK_ARRAY_COUNT(combinations));
diff --git a/tests/ExtendedSkColorTypeTests.cpp b/tests/ExtendedSkColorTypeTests.cpp
index db8fb65..c334ebf 100644
--- a/tests/ExtendedSkColorTypeTests.cpp
+++ b/tests/ExtendedSkColorTypeTests.cpp
@@ -12,6 +12,7 @@
 
 #include "tests/Test.h"
 #include "tests/TestUtils.h"
+#include "tools/ToolUtils.h"
 
 static constexpr int kSize = 32;
 
@@ -151,14 +152,14 @@
 
 static void compare_pixmaps(skiatest::Reporter* reporter,
                             const SkPixmap& expected, const SkPixmap& actual,
-                            SkColorType nativeCT, const char* label) {
+                            SkColorType ct, 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]) {
+        [reporter, ct, 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,
+            ERRORF(reporter, "%s %s - mismatch at %d, %d (%f, %f, %f %f)",
+                   ToolUtils::colortype_name(ct), label, x, y,
                    diffs[0], diffs[1], diffs[2], diffs[3]);
         });
 
diff --git a/tests/TestUtils.cpp b/tests/TestUtils.cpp
index 42cb808..b813ff8 100644
--- a/tests/TestUtils.cpp
+++ b/tests/TestUtils.cpp
@@ -177,6 +177,34 @@
     return true;
 }
 
+using AccessPixelFn = const float*(const char* floatBuffer, int x, int y);
+
+bool compare_pixels(int width, int height,
+                    const char* floatA, std::function<AccessPixelFn>& atA,
+                    const char* floatB, std::function<AccessPixelFn>& atB,
+                    const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
+
+    for (int y = 0; y < height; ++y) {
+        for (int x = 0; x < width; ++x) {
+            const float* rgbaA = atA(floatA, x, y);
+            const float* rgbaB = atB(floatB, x, y);
+            float diffs[4];
+            bool bad = false;
+            for (int i = 0; i < 4; ++i) {
+                diffs[i] = rgbaB[i] - rgbaA[i];
+                if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
+                    bad = true;
+                }
+            }
+            if (bad) {
+                error(x, y, diffs);
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
 bool compare_pixels(const GrPixelInfo& infoA, const char* a, size_t rowBytesA,
                     const GrPixelInfo& infoB, const char* b, size_t rowBytesB,
                     const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
@@ -210,28 +238,14 @@
     SkAssertResult(GrConvertPixels(floatInfo, floatA.get(), floatRowBytes, infoA, a, rowBytesA));
     SkAssertResult(GrConvertPixels(floatInfo, floatB.get(), floatRowBytes, infoB, b, rowBytesB));
 
-    auto at = [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
-        return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
-    };
-    for (int y = 0; y < infoA.height(); ++y) {
-        for (int x = 0; x < infoA.width(); ++x) {
-            const float* rgbaA = at(floatA.get(), x, y);
-            const float* rgbaB = at(floatB.get(), x, y);
-            float diffs[4];
-            bool bad = false;
-            for (int i = 0; i < 4; ++i) {
-                diffs[i] = rgbaB[i] - rgbaA[i];
-                if (std::abs(diffs[i]) > std::abs(tolRGBA[i])) {
-                    bad = true;
-                }
-            }
-            if (bad) {
-                error(x, y, diffs);
-                return false;
-            }
-        }
-    }
-    return true;
+    auto at = std::function<AccessPixelFn>(
+        [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
+            return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
+        });
+
+    return compare_pixels(infoA.width(), infoA.height(),
+                          floatA.get(), at, floatB.get(), at,
+                          tolRGBA, error);
 }
 
 bool compare_pixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
@@ -241,6 +255,47 @@
                           tolRGBA, error);
 }
 
+bool check_solid_pixels(const SkColor4f& col, const SkPixmap& pixmap,
+                        const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error) {
+
+    size_t floatBpp = GrColorTypeBytesPerPixel(GrColorType::kRGBA_F32);
+
+    std::unique_ptr<char[]> floatA(new char[floatBpp]);
+    // First convert 'col' to be compatible with 'pixmap'
+    {
+        sk_sp<SkColorSpace> srcCS = SkColorSpace::MakeSRGBLinear();
+        GrPixelInfo srcInfo(GrColorType::kRGBA_F32, kUnpremul_SkAlphaType, std::move(srcCS), 1, 1);
+        GrPixelInfo dstInfo(GrColorType::kRGBA_F32, pixmap.alphaType(), pixmap.refColorSpace(), 1, 1);
+
+        SkAssertResult(GrConvertPixels(dstInfo, floatA.get(), floatBpp, srcInfo,
+                                       col.vec(), floatBpp));
+    }
+
+    size_t floatRowBytes = floatBpp * pixmap.width();
+    std::unique_ptr<char[]> floatB(new char[floatRowBytes * pixmap.height()]);
+    // Then convert 'pixmap' to RGBA_F32
+    {
+        GrPixelInfo dstInfo(GrColorType::kRGBA_F32, pixmap.alphaType(), pixmap.refColorSpace(),
+                            pixmap.width(), pixmap.height());
+
+        SkAssertResult(GrConvertPixels(dstInfo, floatB.get(), floatRowBytes, pixmap.info(),
+                                       pixmap.addr(), pixmap.rowBytes()));
+    }
+
+    auto atA = std::function<AccessPixelFn>(
+        [](const char* floatBuffer, int /* x */, int /* y */) {
+            return reinterpret_cast<const float*>(floatBuffer);
+        });
+
+    auto atB = std::function<AccessPixelFn>(
+        [floatBpp, floatRowBytes](const char* floatBuffer, int x, int y) {
+            return reinterpret_cast<const float*>(floatBuffer + y * floatRowBytes + x * floatBpp);
+        });
+
+    return compare_pixels(pixmap.width(), pixmap.height(), floatA.get(), atA, floatB.get(), atB,
+                          tolRGBA, error);
+}
+
 #include "src/utils/SkCharToGlyphCache.h"
 
 static SkGlyphID hash_to_glyph(uint32_t value) {
diff --git a/tests/TestUtils.h b/tests/TestUtils.h
index 660cdb4..347139d 100644
--- a/tests/TestUtils.h
+++ b/tests/TestUtils.h
@@ -75,3 +75,9 @@
 /** Convenience version of above that takes SkPixmap inputs. */
 bool compare_pixels(const SkPixmap& a, const SkPixmap& b, const float tolRGBA[4],
                     std::function<ComparePixmapsErrorReporter>& error);
+
+/**
+ * Convenience version that checks that 'pixmap' is a solid field of 'col'
+ */
+bool check_solid_pixels(const SkColor4f& col, const SkPixmap& pixmap,
+                        const float tolRGBA[4], std::function<ComparePixmapsErrorReporter>& error);