Expand backend allocation API to allow an initialization color (only for GL to start)

Change-Id: I8e676e80f85f14c81c3cec8d766d0fdc7e25f426
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/214445
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index d6ce983..23ffc43 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -81,6 +81,8 @@
   "$_src/gpu/GrContextThreadSafeProxyPriv.h",
   "$_src/gpu/GrCoordTransform.h",
   "$_src/gpu/GrCpuBuffer.h",
+  "$_src/gpu/GrDataUtils.h",
+  "$_src/gpu/GrDataUtils.cpp",
   "$_src/gpu/GrDDLContext.cpp",
   "$_src/gpu/GrDefaultGeoProcFactory.cpp",
   "$_src/gpu/GrDefaultGeoProcFactory.h",
diff --git a/src/gpu/GrContextPriv.cpp b/src/gpu/GrContextPriv.cpp
index 09b5327..ab4b2f0 100644
--- a/src/gpu/GrContextPriv.cpp
+++ b/src/gpu/GrContextPriv.cpp
@@ -764,3 +764,48 @@
     fContext->drawingManager()->testingOnly_removeOnFlushCallbackObject(cb);
 }
 #endif
+
+//////////////////////////////////////////////////////////////////////////////
+GrBackendTexture GrContextPriv::createBackendTexture(int width, int height,
+                                                     GrBackendFormat backendFormat,
+                                                     const SkColor4f& color,
+                                                     GrMipMapped mipMapped,
+                                                     GrRenderable renderable) {
+    if (!fContext->asDirectContext()) {
+        return GrBackendTexture();
+    }
+
+    if (this->abandoned()) {
+        return GrBackendTexture();
+    }
+
+    if (!backendFormat.isValid()) {
+        return GrBackendTexture();
+    }
+
+    GrGpu* gpu = fContext->fGpu.get();
+
+    return gpu->createBackendTexture(width, height, backendFormat,
+                                     mipMapped, renderable, nullptr, 0, color);
+}
+
+GrBackendTexture GrContextPriv::createBackendTexture(int width, int height,
+                                                     SkColorType colorType,
+                                                     const SkColor4f& color,
+                                                     GrMipMapped mipMapped,
+                                                     GrRenderable renderable) {
+    if (!fContext->asDirectContext()) {
+        return GrBackendTexture();
+    }
+
+    if (this->abandoned()) {
+        return GrBackendTexture();
+    }
+
+    GrBackendFormat format = fContext->caps()->getBackendFormatFromColorType(colorType);
+    if (!format.isValid()) {
+        return GrBackendTexture();
+    }
+
+    return this->createBackendTexture(width, height, format, color, mipMapped, renderable);
+}
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index 86af1f3..5dbb038 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -292,6 +292,20 @@
     void testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject*);
 #endif
 
+    // If possible, create a backend texture initialized to a particular color. The client should
+    // ensure that the returned backend texture is valid.
+    GrBackendTexture createBackendTexture(int width, int height,
+                                          GrBackendFormat, const SkColor4f& color,
+                                          GrMipMapped, GrRenderable);
+
+    // If possible, create a backend texture initialized to a particular color. The client should
+    // ensure that the returned backend texture is valid.
+    // If successful, the created backend texture will be compatible with the provided
+    // SkColorType.
+    GrBackendTexture createBackendTexture(int width, int height,
+                                          SkColorType, const SkColor4f& color,
+                                          GrMipMapped, GrRenderable);
+
 private:
     explicit GrContextPriv(GrContext* context) : fContext(context) {}
     GrContextPriv(const GrContextPriv&); // unimpl
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
new file mode 100644
index 0000000..40d69e0
--- /dev/null
+++ b/src/gpu/GrDataUtils.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrDataUtils.h"
+
+#include "include/private/GrColor.h"
+
+static const int kNumModifierTables = 8;
+static const int kNumPixelIndices = 4;
+
+// The index of each row in this table is the ETC1 table codeword
+// The index of each column in this table is the ETC1 pixel index value
+static const int kModifierTables[kNumModifierTables][kNumPixelIndices] = {
+    /* 0 */ { 2,    8,  -2,   -8 },
+    /* 1 */ { 5,   17,  -5,  -17 },
+    /* 2 */ { 9,   29,  -9,  -29 },
+    /* 3 */ { 13,  42, -13,  -42 },
+    /* 4 */ { 18,  60, -18,  -60 },
+    /* 5 */ { 24,  80, -24,  -80 },
+    /* 6 */ { 33, 106, -33, -106 },
+    /* 7 */ { 47, 183, -47, -183 }
+};
+
+static inline int convert_5To8(int b) {
+    int c = b & 0x1f;
+    return (c << 3) | (c >> 2);
+}
+
+// Evaluate one of the entries in 'kModifierTables' to see how close it can get (r8,g8,b8) to
+// the original color (rOrig, gOrib, bOrig).
+static int test_table_entry(int rOrig, int gOrig, int bOrig,
+                            int r8, int g8, int b8,
+                            int table, int offset) {
+    SkASSERT(0 <= table && table < 8);
+    SkASSERT(0 <= offset && offset < 4);
+
+    r8 = SkTPin<uint8_t>(r8 + kModifierTables[table][offset], 0, 255);
+    g8 = SkTPin<uint8_t>(g8 + kModifierTables[table][offset], 0, 255);
+    b8 = SkTPin<uint8_t>(b8 + kModifierTables[table][offset], 0, 255);
+
+    return SkTAbs(rOrig - r8) + SkTAbs(gOrig - g8) + SkTAbs(bOrig - b8);
+}
+
+// Create an ETC1 compressed block that is filled with 'col'
+static void create_etc1_block(SkColor col, ETC1Block* block) {
+    block->fHigh = 0;
+    block->fLow = 0;
+
+    int rOrig = SkColorGetR(col);
+    int gOrig = SkColorGetG(col);
+    int bOrig = SkColorGetB(col);
+
+    int r5 = SkMulDiv255Round(31, rOrig);
+    int g5 = SkMulDiv255Round(31, gOrig);
+    int b5 = SkMulDiv255Round(31, bOrig);
+
+    int r8 = convert_5To8(r5);
+    int g8 = convert_5To8(g5);
+    int b8 = convert_5To8(b5);
+
+    // We always encode solid color textures as 555 + zero diffs
+    block->fHigh |= (r5 << 27) | (g5 << 19) | (b5 << 11) | 0x2;
+
+    int bestTableIndex = 0, bestPixelIndex = 0;
+    int bestSoFar = 1024;
+    for (int tableIndex = 0; tableIndex < kNumModifierTables; ++tableIndex) {
+        for (int pixelIndex = 0; pixelIndex < kNumPixelIndices; ++pixelIndex) {
+            int score = test_table_entry(rOrig, gOrig, bOrig, r8, g8, b8,
+                                         tableIndex, pixelIndex);
+
+            if (bestSoFar > score) {
+                bestSoFar = score;
+                bestTableIndex = tableIndex;
+                bestPixelIndex = pixelIndex;
+            }
+        }
+    }
+
+    block->fHigh |= (bestTableIndex << 5) | (bestTableIndex << 2);
+
+    for (int i = 0; i < 16; ++i) {
+        block->fLow |= bestPixelIndex << 2*i;
+    }
+}
+
+int GrNumETC1Blocks(int w, int h) {
+    if (w < 4) {
+        w = 1;
+    } else {
+       SkASSERT((w & 3) == 0);
+       w >>= 2;
+    }
+
+    if (h < 4) {
+        h = 1;
+    } else {
+       SkASSERT((h & 3) == 0);
+       h >>= 2;
+    }
+
+    return w * h;
+}
+
+void GrFillInETC1WithColor(const SkColor4f& colorf, ETC1Block* blocks, int numBlocks) {
+    SkColor color = colorf.toSkColor();
+
+    ETC1Block block;
+    create_etc1_block(color, &block);
+
+    for (int i = 0; i < numBlocks; ++i) {
+        blocks[i] = block;
+    }
+}
+
+bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
+                           const SkColor4f& colorf, void* dest) {
+    SkASSERT(kRGB_ETC1_GrPixelConfig != config);
+
+    GrColor color = colorf.toBytes_RGBA();
+
+    uint8_t r = GrColorUnpackR(color);
+    uint8_t g = GrColorUnpackG(color);
+    uint8_t b = GrColorUnpackB(color);
+    uint8_t a = GrColorUnpackA(color);
+
+    // TODO: use sk_memset32, sk_memset16, and SkOpts::rect_memset16/32/64
+    switch (config) {
+        case kAlpha_8_GrPixelConfig:                            // fall through
+        case kAlpha_8_as_Alpha_GrPixelConfig:                   // fall through
+        case kAlpha_8_as_Red_GrPixelConfig: {
+            memset(dest, a, width * height);
+            break;
+        }
+        case kGray_8_GrPixelConfig:                             // fall through
+        case kGray_8_as_Lum_GrPixelConfig:                      // fall through
+        case kGray_8_as_Red_GrPixelConfig: {
+            uint8_t gray8 = SkComputeLuminance(r, g, b);
+            memset(dest, gray8, width * height);
+            break;
+        }
+        case kRGB_565_GrPixelConfig: {
+            uint16_t* dest16 = (uint16_t*) dest;
+            uint16_t rgb565 = SkPack888ToRGB16(r, g, b);
+            for (int i = 0; i < width * height; ++i) {
+                dest16[i] = rgb565;
+            }
+            break;
+        }
+        case kRGBA_4444_GrPixelConfig: {
+            uint16_t* dest16 = (uint16_t*) dest;
+            uint8_t r4 = (r >> 4) & 0xF;
+            uint8_t g4 = (g >> 4) & 0xF;
+            uint8_t b4 = (b >> 4) & 0xF;
+            uint8_t a4 = (a >> 4) & 0xF;
+
+            uint16_t rgba4444 = r4 << SK_R4444_SHIFT | g4 << SK_G4444_SHIFT |
+                                b4 << SK_B4444_SHIFT | a4 << SK_A4444_SHIFT;
+
+            for (int i = 0; i < width * height; ++i) {
+                dest16[i] = rgba4444;
+            }
+            break;
+        }
+        case kRGBA_8888_GrPixelConfig: {
+            GrColor* destColor = (GrColor *) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = color;
+            }
+            break;
+        }
+        case kRGB_888_GrPixelConfig: {
+            uint8_t* dest8 = (uint8_t*) dest;
+            for (int i = 0; i < width * height; ++i, dest8 += 3) {
+                dest8[0] = r;
+                dest8[1] = g;
+                dest8[2] = b;
+            }
+            break;
+        }
+        case kRGB_888X_GrPixelConfig: {
+            GrColor opaque = GrColorPackRGBA(r, g, b, 0xFF);
+
+            GrColor* destColor = (GrColor *) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = opaque;
+            }
+            break;
+        }
+        case kRG_88_GrPixelConfig: {
+            uint8_t* dest8 = (uint8_t*) dest;
+            for (int i = 0; i < width * height; ++i, dest8 += 2) {
+                dest8[0] = r;
+                dest8[1] = g;
+            }
+            break;
+        }
+        case kBGRA_8888_GrPixelConfig: {
+            GrColor swizzled = GrColorPackRGBA(b, g, r, a);
+
+            GrColor* destColor = (GrColor *) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = swizzled;
+            }
+            break;
+        }
+        case kSRGBA_8888_GrPixelConfig: {
+            // TODO: ask Brian O. what to do here
+            GrColor* destColor = (GrColor *) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = color;
+            }
+            break;
+        }
+        case kSBGRA_8888_GrPixelConfig: {
+            // TODO: ask Brian O. what to do here
+            GrColor swizzled = GrColorPackRGBA(b, g, r, a);
+
+            GrColor* destColor = (GrColor *) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = swizzled;
+            }
+            break;
+        }
+        case kRGBA_1010102_GrPixelConfig: {
+            uint32_t r10 = SkScalarRoundToInt(colorf.fR * 1023.0f);
+            uint32_t g10 = SkScalarRoundToInt(colorf.fG * 1023.0f);
+            uint32_t b10 = SkScalarRoundToInt(colorf.fB * 1023.0f);
+            uint8_t  a2  = SkScalarRoundToInt(colorf.fA * 3.0f);
+
+            uint32_t rgba1010102 = a2 << 30 | b10 << 20 | g10 << 10 | r10;
+
+            uint32_t* destColor = (uint32_t *) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = rgba1010102;
+            }
+            break;
+        }
+        case kRGBA_float_GrPixelConfig: {
+            SkColor4f* destColor = (SkColor4f*) dest;
+            for (int i = 0; i < width * height; ++i) {
+                destColor[i] = colorf;
+            }
+            break;
+        }
+        case kRG_float_GrPixelConfig: {
+            float* destFloat = (float*) dest;
+            for (int i = 0; i < width * height; ++i, destFloat += 2) {
+                destFloat[0] = colorf.fR;
+                destFloat[1] = colorf.fG;
+            }
+            break;
+        }
+        case kAlpha_half_as_Red_GrPixelConfig:                  // fall through
+        case kAlpha_half_GrPixelConfig: {
+            SkHalf* destHalf = (SkHalf*) dest;
+            SkHalf alphaHalf = SkFloatToHalf(colorf.fA);
+            for (int i = 0; i < width * height; ++i) {
+                destHalf[i] = alphaHalf;
+            }
+            break;
+        }
+        case kRGBA_half_GrPixelConfig:                          // fall through
+        case kRGBA_half_Clamped_GrPixelConfig: {
+            SkHalf* destHalf = (SkHalf*) dest;
+            SkHalf rHalf = SkFloatToHalf(colorf.fR);
+            SkHalf gHalf = SkFloatToHalf(colorf.fG);
+            SkHalf bHalf = SkFloatToHalf(colorf.fB);
+            SkHalf aHalf = SkFloatToHalf(colorf.fA);
+            for (int i = 0; i < width * height; ++i, destHalf += 4) {
+                destHalf[0] = rHalf;
+                destHalf[1] = gHalf;
+                destHalf[2] = bHalf;
+                destHalf[3] = aHalf;
+            }
+            break;
+        }
+        default:
+            return false;
+            break;
+    }
+
+    return true;
+}
diff --git a/src/gpu/GrDataUtils.h b/src/gpu/GrDataUtils.h
new file mode 100644
index 0000000..a700a74
--- /dev/null
+++ b/src/gpu/GrDataUtils.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrDataUtils_DEFINED
+#define GrDataUtils_DEFINED
+
+#include "include/core/SkColor.h"
+#include "include/private/GrTypesPriv.h"
+
+// Fill in the width x height 'dest' with the munged version of 'color' that matches 'config'
+bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
+                           const SkColor4f& color, void* dest);
+
+struct ETC1Block {
+    uint32_t fHigh;
+    uint32_t fLow;
+};
+
+int GrNumETC1Blocks(int w, int h);
+
+// Fill in 'blocks' with ETC1 blocks derived from 'color'
+void GrFillInETC1WithColor(const SkColor4f& color, ETC1Block* blocks, int numBlocks);
+
+#endif
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 86aa109..630644a 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -403,10 +403,14 @@
     /**
      * Creates a texture directly in the backend API without wrapping it in a GrTexture.
      * Must be matched with a call to deleteBackendTexture().
+     * Right now, the color is ignored if pixel data is provided.
+     * In the future, if neither a color nor pixels are provided then the backend texture
+     * will be uninitialized.
      */
     virtual GrBackendTexture createBackendTexture(int w, int h, const GrBackendFormat&,
                                                   GrMipMapped, GrRenderable,
-                                                  const void* pixels, size_t rowBytes) = 0;
+                                                  const void* pixels, size_t rowBytes,
+                                                  const SkColor4f& = SkColors::kTransparent) = 0;
 
     /**
      * Frees a texture created by createBackendTexture(). If ownership of the backend
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 07adb70..de653bc 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -21,6 +21,7 @@
 #include "src/core/SkTraceEvent.h"
 #include "src/gpu/GrContextPriv.h"
 #include "src/gpu/GrCpuBuffer.h"
+#include "src/gpu/GrDataUtils.h"
 #include "src/gpu/GrFixedClip.h"
 #include "src/gpu/GrGpuResourcePriv.h"
 #include "src/gpu/GrMesh.h"
@@ -4057,7 +4058,8 @@
                                                const GrBackendFormat& format,
                                                GrMipMapped mipMapped,
                                                GrRenderable renderable,
-                                               const void* pixels, size_t rowBytes) {
+                                               const void* pixels, size_t rowBytes,
+                                               const SkColor4f& colorf) {
     this->handleDirtyContext();
 
     const GrGLenum* glFormat = format.getGLFormat();
@@ -4123,6 +4125,13 @@
         SkASSERT(GrRenderable::kNo == renderable);
         SkASSERT(0 == rowBytes);
 
+        int numBlocks = GrNumETC1Blocks(w, h);
+        SkAutoTMalloc<ETC1Block> defaultStorage(numBlocks);
+        if (!pixels) {
+            GrFillInETC1WithColor(colorf, defaultStorage.get(), numBlocks);
+            pixels = defaultStorage.get();
+        }
+
         for (int i = 0; i < mipLevelCount; ++i) {
             // TODO: this isn't correct when pixels for additional mip levels are passed in
             texels.get()[i] = { pixels, 0 };
@@ -4140,8 +4149,11 @@
         size_t baseLayerSize = bpp * w * h;
         SkAutoMalloc defaultStorage(baseLayerSize);
         if (!pixels) {
-            // Fill in the texture with all zeros so we don't have random garbage
-            memset(defaultStorage.get(), 0, baseLayerSize);
+            if (!GrFillBufferWithColor(config, w, h, colorf, defaultStorage.get())) {
+                GL_CALL(DeleteTextures(1, &(info.fID)));
+                return GrBackendTexture();
+            }
+
             pixels = defaultStorage.get();
             rowBytes = trimRowBytes;
         }
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index feb7597..869a3f2 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -138,7 +138,8 @@
                                                                 int height) override;
     GrBackendTexture createBackendTexture(int w, int h, const GrBackendFormat&,
                                           GrMipMapped, GrRenderable,
-                                          const void* pixels, size_t rowBytes) override;
+                                          const void* pixels, size_t rowBytes,
+                                          const SkColor4f& color = SkColors::kTransparent) override;
     void deleteBackendTexture(const GrBackendTexture&) override;
 
 #if GR_TEST_UTILS
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index 5102ef6..3c67b63 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -201,7 +201,8 @@
                                                  GrMipMapped mipMapped,
                                                  GrRenderable /* renderable */,
                                                  const void* /* pixels */,
-                                                 size_t /* rowBytes */) {
+                                                 size_t /* rowBytes */,
+                                                 const SkColor4f& /* color */) {
 
     const GrPixelConfig* pixelConfig = format.getMockFormat();
     if (!pixelConfig) {
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 97c06cf..cf49972 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -123,7 +123,8 @@
                                                                 int height) override;
     GrBackendTexture createBackendTexture(int w, int h, const GrBackendFormat&,
                                           GrMipMapped, GrRenderable,
-                                          const void* pixels, size_t rowBytes) override;
+                                          const void* pixels, size_t rowBytes,
+                                          const SkColor4f& color = SkColors::kTransparent) override;
     void deleteBackendTexture(const GrBackendTexture&) override;
 
 #if GR_TEST_UTILS
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 6a8c082..14a47b3 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -62,7 +62,9 @@
 
     GrBackendTexture createBackendTexture(int w, int h, const GrBackendFormat&,
                                           GrMipMapped, GrRenderable,
-                                          const void* pixels, size_t rowBytes) override;
+                                          const void* pixels, size_t rowBytes,
+                                          const SkColor4f& color = SkColors::kTransparent) override;
+
     void deleteBackendTexture(const GrBackendTexture&) override;
 
 #if GR_TEST_UTILS
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 5506f9c..8fae4b6 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -770,7 +770,8 @@
                                                 const GrBackendFormat& format,
                                                 GrMipMapped mipMapped,
                                                 GrRenderable renderable,
-                                                const void* pixels, size_t rowBytes) {
+                                                const void* pixels, size_t rowBytes,
+                                                const SkColor4f& color) {
     if (w > this->caps()->maxTextureSize() || h > this->caps()->maxTextureSize()) {
         return GrBackendTexture();
     }
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 5cdbc70..7d5a9d5 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1894,7 +1894,8 @@
                                                const GrBackendFormat& format,
                                                GrMipMapped mipMapped,
                                                GrRenderable renderable,
-                                               const void* srcData, size_t rowBytes) {
+                                               const void* srcData, size_t rowBytes,
+                                               const SkColor4f& color) {
     this->handleDirtyContext();
 
 
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 9b24df1..1caa2f0 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -82,7 +82,8 @@
 
     GrBackendTexture createBackendTexture(int w, int h, const GrBackendFormat&,
                                           GrMipMapped, GrRenderable,
-                                          const void* pixels, size_t rowBytes) override;
+                                          const void* pixels, size_t rowBytes,
+                                          const SkColor4f& color = SkColors::kTransparent) override;
     void deleteBackendTexture(const GrBackendTexture&) override;
 #if GR_TEST_UTILS
     bool isTestingOnlyBackendTexture(const GrBackendTexture&) const override;
diff --git a/tests/BackendAllocationTest.cpp b/tests/BackendAllocationTest.cpp
index 30eefc0..52262a3 100644
--- a/tests/BackendAllocationTest.cpp
+++ b/tests/BackendAllocationTest.cpp
@@ -8,6 +8,8 @@
 #include "include/core/SkSurface.h"
 #include "include/gpu/GrContext.h"
 #include "src/gpu/GrContextPriv.h"
+#include "include/core/SkSurface.h"
+#include "src/core/SkAutoPixmapStorage.h"
 #include "src/image/SkImage_Base.h"
 #include "tests/Test.h"
 
@@ -39,11 +41,11 @@
 
     if (GrRenderable::kYes == renderable) {
         sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(context,
-                                                                    backendTex,
-                                                                    kTopLeft_GrSurfaceOrigin,
-                                                                    0,
-                                                                    colorType,
-                                                                    nullptr, nullptr);
+                                                                  backendTex,
+                                                                  kTopLeft_GrSurfaceOrigin,
+                                                                  0,
+                                                                  colorType,
+                                                                  nullptr, nullptr);
         if (!surf) {
             ERRORF(reporter, "Couldn't make surface from backendTexture for colorType %d\n",
                     colorType);
@@ -54,11 +56,11 @@
 
     {
         sk_sp<SkImage> img = SkImage::MakeFromTexture(context,
-                                                        backendTex,
-                                                        kTopLeft_GrSurfaceOrigin,
-                                                        colorType,
-                                                        kPremul_SkAlphaType,
-                                                        nullptr);
+                                                      backendTex,
+                                                      kTopLeft_GrSurfaceOrigin,
+                                                      colorType,
+                                                      kPremul_SkAlphaType,
+                                                      nullptr);
         if (!img) {
             ERRORF(reporter, "Couldn't make image from backendTexture for colorType %d\n",
                     colorType);
@@ -81,28 +83,135 @@
     context->deleteBackendTexture(backendTex);
 }
 
+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) {
+
+            SkColor expectedCol = expected.getColor(x, y);
+            SkColor actualCol = actual.getColor(x, y);
+
+            int maxDiff = 0;
+            for (int i = 0; i < 4; ++i) {
+                int diff = SkTAbs<int>((0xFF & (actualCol >> i*8)) - (0xFF & (expectedCol >> i*8)));
+                if (maxDiff < diff) {
+                    maxDiff = diff;
+                }
+            }
+
+            // GPU and raster differ a bit on kGray_8_SkColorType and kRGBA_1010102_SkColorType
+            if (maxDiff <= 12) {
+                continue;
+            }
+
+            ERRORF(reporter,
+                   "Mismatched pixels at %d %d ct: %d expected: 0x%x actual: 0x%x diff: %d\n",
+                   x, y, colorType, expectedCol, actualCol, maxDiff);
+            return;
+        }
+    }
+}
+
+// Test initialization of GrBackendObjects to a specific color
+void test_color_init(GrContext* context, skiatest::Reporter* reporter,
+                     std::function<GrBackendTexture (GrContext*,
+                                                     const SkColor4f&,
+                                                     GrMipMapped,
+                                                     GrRenderable)> create,
+                     SkColorType colorType, const SkColor4f& color,
+                     GrMipMapped mipMapped, GrRenderable renderable) {
+    GrBackendTexture backendTex = create(context, color, mipMapped, renderable);
+    if (!backendTex.isValid()) {
+        // errors here should be reported by the test_wrapping test
+        return;
+    }
+
+    if (kUnknown_SkColorType == colorType) {
+        // TODO: burrow in and scrappily check that data was uploaded!
+        context->deleteBackendTexture(backendTex);
+        return;
+    }
+
+    SkImageInfo ii = SkImageInfo::Make(32, 32, colorType, kPremul_SkAlphaType);
+
+    SkAutoPixmapStorage expected;
+    SkAssertResult(expected.tryAlloc(ii));
+    expected.erase(color);
+
+    SkAutoPixmapStorage actual;
+    SkAssertResult(actual.tryAlloc(ii));
+    actual.erase(SkColors::kTransparent);
+
+    if (GrRenderable::kYes == renderable) {
+        sk_sp<SkSurface> surf = SkSurface::MakeFromBackendTexture(context,
+                                                                  backendTex,
+                                                                  kTopLeft_GrSurfaceOrigin,
+                                                                  0,
+                                                                  colorType,
+                                                                  nullptr, nullptr);
+        if (surf) {
+            bool result = surf->readPixels(actual, 0, 0);
+            REPORTER_ASSERT(reporter, result);
+
+            compare_pixmaps(expected, actual, colorType, reporter);
+
+            actual.erase(SkColors::kTransparent);
+        }
+    }
+
+    {
+        sk_sp<SkImage> img = SkImage::MakeFromTexture(context,
+                                                      backendTex,
+                                                      kTopLeft_GrSurfaceOrigin,
+                                                      colorType,
+                                                      kPremul_SkAlphaType,
+                                                      nullptr);
+        if (img) {
+            bool result = img->readPixels(actual, 0, 0);
+            if (!result) {
+                // TODO: we need a better way to tell a priori if readPixels will work for an
+                // arbitrary colorType
+#if 0
+                ERRORF(reporter, "Couldn't readback from SkImage for colorType: %d\n",
+                        colorType);
+#endif
+            } else {
+                compare_pixmaps(expected, actual, colorType, reporter);
+            }
+        }
+    }
+
+    context->deleteBackendTexture(backendTex);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ColorTypeBackendAllocationTest, reporter, ctxInfo) {
     GrContext* context = ctxInfo.grContext();
     const GrCaps* caps = context->priv().caps();
 
+    constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
+
     struct {
         SkColorType   fColorType;
         GrPixelConfig fConfig;
+        SkColor4f     fColor;
     } combinations[] = {
-        { kAlpha_8_SkColorType,      kAlpha_8_GrPixelConfig           },
-        { kRGB_565_SkColorType,      kRGB_565_GrPixelConfig           },
-        { kARGB_4444_SkColorType,    kRGBA_4444_GrPixelConfig         },
-        { kRGBA_8888_SkColorType,    kRGBA_8888_GrPixelConfig         },
-        { kRGB_888x_SkColorType,     kRGB_888_GrPixelConfig           },
-        { kBGRA_8888_SkColorType,    kBGRA_8888_GrPixelConfig         },
-        { kRGBA_1010102_SkColorType, kRGBA_1010102_GrPixelConfig      },
+        { 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     },
+        // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
+        { kBGRA_8888_SkColorType,    kBGRA_8888_GrPixelConfig,         { 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 }},
         // The kRGB_101010x_SkColorType has no Ganesh correlate
-        { kRGB_101010x_SkColorType,  kUnknown_GrPixelConfig           },
-        { kGray_8_SkColorType,       kGray_8_GrPixelConfig            },
-        { kRGBA_F16Norm_SkColorType, kRGBA_half_Clamped_GrPixelConfig },
-        { kRGBA_F16_SkColorType,     kRGBA_half_GrPixelConfig         },
-        { kRGBA_F32_SkColorType,     kRGBA_float_GrPixelConfig        },
+        { kRGB_101010x_SkColorType,  kUnknown_GrPixelConfig,           { 0, 0.5f, 0, 0.5f }},
+        { kGray_8_SkColorType,       kGray_8_GrPixelConfig,            SkColors::kDkGray   },
+        { 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     },
     };
 
     SkASSERT(kLastEnum_SkColorType == SK_ARRAY_COUNT(combinations));
@@ -148,6 +257,29 @@
                     test_wrapping(context, reporter, uninitCreateMtd,
                                   colorType, mipMapped, renderable);
                 }
+
+                {
+                    // GL has difficulties reading back from these combinations
+                    if (GrBackendApi::kOpenGL == context->backend()) {
+                        if (kAlpha_8_SkColorType == combo.fColorType) {
+                            continue;
+                        }
+                    } else {
+                        // Not yet implemented for Vulkan and Metal
+                        continue;
+                    }
+
+                    auto createWithColorMtd = [colorType](GrContext* context,
+                                                          const SkColor4f& color,
+                                                          GrMipMapped mipMapped,
+                                                          GrRenderable renderable) {
+                        return context->priv().createBackendTexture(32, 32, colorType, color,
+                                                                    mipMapped, renderable);
+                    };
+
+                    test_color_init(context, reporter, createWithColorMtd,
+                                    colorType, combo.fColor, mipMapped, renderable);
+                }
             }
         }
     }
@@ -166,42 +298,67 @@
     GrContext* context = ctxInfo.grContext();
     const GrGLCaps* glCaps = static_cast<const GrGLCaps*>(context->priv().caps());
 
+    constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
+
     struct {
         SkColorType   fColorType;
         GrGLenum      fFormat;
         // TODO: remove 'fConfig' and directly use 'fFormat' in GrGLCaps::isFormatTexturable
         GrPixelConfig fConfig;
+        SkColor4f     fColor;
     } combinations[] = {
-        { kRGBA_8888_SkColorType,    GR_GL_RGBA8,                kRGBA_8888_GrPixelConfig         },
-        { kRGBA_8888_SkColorType,    GR_GL_SRGB8_ALPHA8,         kSRGBA_8888_GrPixelConfig        },
+        { kRGBA_8888_SkColorType,           GR_GL_RGBA8,
+          kRGBA_8888_GrPixelConfig,         SkColors::kRed      },
+        { kRGBA_8888_SkColorType,           GR_GL_SRGB8_ALPHA8,
+          kSRGBA_8888_GrPixelConfig,        SkColors::kRed      },
 
-        { kRGB_888x_SkColorType,     GR_GL_RGBA8,                kRGBA_8888_GrPixelConfig         },
-        { kRGB_888x_SkColorType,     GR_GL_RGB8,                 kRGB_888_GrPixelConfig           },
+        { kRGB_888x_SkColorType,            GR_GL_RGBA8,
+          kRGBA_8888_GrPixelConfig,         { 1, 1, 0, 0.5f }   },
+        { kRGB_888x_SkColorType,            GR_GL_RGB8,
+          kRGB_888_GrPixelConfig,           { 0, 1, 1, 0.5f }  },
 
-        { kBGRA_8888_SkColorType,    GR_GL_RGBA8,                kRGBA_8888_GrPixelConfig         },
-        { kBGRA_8888_SkColorType,    GR_GL_BGRA8,                kBGRA_8888_GrPixelConfig         },
-        { kBGRA_8888_SkColorType,    GR_GL_SRGB8_ALPHA8,         kSBGRA_8888_GrPixelConfig        },
+        { kBGRA_8888_SkColorType,           GR_GL_RGBA8,
+          kRGBA_8888_GrPixelConfig,         SkColors::kBlue     },
+        { kBGRA_8888_SkColorType,           GR_GL_BGRA8,
+          kBGRA_8888_GrPixelConfig,         SkColors::kBlue     },
+        { kBGRA_8888_SkColorType,           GR_GL_SRGB8_ALPHA8,
+          kSBGRA_8888_GrPixelConfig,        SkColors::kCyan     },
 
-        { kRGBA_1010102_SkColorType, GR_GL_RGB10_A2,             kRGBA_1010102_GrPixelConfig      },
-        { kRGB_565_SkColorType,      GR_GL_RGB565,               kRGB_565_GrPixelConfig           },
-        { kARGB_4444_SkColorType,    GR_GL_RGBA4,                kRGBA_4444_GrPixelConfig         },
+        { kRGBA_1010102_SkColorType,        GR_GL_RGB10_A2,
+          // TODO: readback is busted when alpha = 0.5f (perhaps premul vs. unpremul)
+          kRGBA_1010102_GrPixelConfig,      { 0.5f, 0, 0, 1.0f }},
+        { kRGB_565_SkColorType,             GR_GL_RGB565,
+          kRGB_565_GrPixelConfig,           SkColors::kRed      },
+        { kARGB_4444_SkColorType,           GR_GL_RGBA4,
+          kRGBA_4444_GrPixelConfig,         SkColors::kGreen    },
 
-        { kAlpha_8_SkColorType,      GR_GL_ALPHA8,               kAlpha_8_as_Alpha_GrPixelConfig  },
-        { kAlpha_8_SkColorType,      GR_GL_R8,                   kAlpha_8_as_Red_GrPixelConfig    },
+        { kAlpha_8_SkColorType,             GR_GL_ALPHA8,
+          kAlpha_8_as_Alpha_GrPixelConfig,  kTransCol           },
+        { kAlpha_8_SkColorType,             GR_GL_R8,
+          kAlpha_8_as_Red_GrPixelConfig,    kTransCol           },
 
-        { kGray_8_SkColorType,       GR_GL_LUMINANCE8,           kGray_8_as_Lum_GrPixelConfig     },
-        { kGray_8_SkColorType,       GR_GL_R8,                   kGray_8_as_Red_GrPixelConfig     },
+        { kGray_8_SkColorType,              GR_GL_LUMINANCE8,
+          kGray_8_as_Lum_GrPixelConfig,     SkColors::kLtGray   },
+        { kGray_8_SkColorType,              GR_GL_R8,
+          kGray_8_as_Red_GrPixelConfig,     SkColors::kDkGray   },
 
-        { kRGBA_F32_SkColorType,     GR_GL_RGBA32F,              kRGBA_float_GrPixelConfig        },
+        { kRGBA_F32_SkColorType,            GR_GL_RGBA32F,
+          kRGBA_float_GrPixelConfig,        SkColors::kRed      },
 
-        { kRGBA_F16Norm_SkColorType, GR_GL_RGBA16F,              kRGBA_half_Clamped_GrPixelConfig },
-        { kRGBA_F16_SkColorType,     GR_GL_RGBA16F,              kRGBA_half_GrPixelConfig         },
+        { kRGBA_F16Norm_SkColorType,        GR_GL_RGBA16F,
+          kRGBA_half_Clamped_GrPixelConfig, SkColors::kLtGray   },
+        { kRGBA_F16_SkColorType,            GR_GL_RGBA16F,
+          kRGBA_half_GrPixelConfig,         SkColors::kYellow   },
 
         // These backend formats don't have SkColorType equivalents
-        { kUnknown_SkColorType,      GR_GL_RG32F,                kRG_float_GrPixelConfig          },
-        { kUnknown_SkColorType,      GR_GL_RG8,                  kRG_88_GrPixelConfig             },
-        { kUnknown_SkColorType,      GR_GL_R16F,                 kAlpha_half_as_Red_GrPixelConfig },
-        { kUnknown_SkColorType,      GR_GL_COMPRESSED_RGB8_ETC2, kRGB_ETC1_GrPixelConfig          },
+        { kUnknown_SkColorType,             GR_GL_RG32F,
+          kRG_float_GrPixelConfig,          { 0.7f, 0.7f, 0, 0 }},
+        { kUnknown_SkColorType,             GR_GL_RG8,
+          kRG_88_GrPixelConfig,             { 0.5f, 0.5f, 0, 0 }},
+        { kUnknown_SkColorType,             GR_GL_R16F,
+          kAlpha_half_as_Red_GrPixelConfig, { 1.0f, 0, 0, 0.5f }},
+        { kUnknown_SkColorType,             GR_GL_COMPRESSED_RGB8_ETC2,
+          kRGB_ETC1_GrPixelConfig,          SkColors::kRed      },
     };
 
     for (auto combo : combinations) {
@@ -252,6 +409,28 @@
                     test_wrapping(context, reporter, uninitCreateMtd,
                                   combo.fColorType, mipMapped, renderable);
                 }
+
+                {
+                    // GL has difficulties reading back from these combinations
+                    if (kAlpha_8_SkColorType == combo.fColorType) {
+                        continue;
+                    }
+                    if (GrRenderable::kYes != renderable ||
+                        kRGB_888x_SkColorType == combo.fColorType) {
+                        continue;
+                    }
+
+                    auto createWithColorMtd = [format](GrContext* context,
+                                                       const SkColor4f& color,
+                                                       GrMipMapped mipMapped,
+                                                       GrRenderable renderable) {
+                        return context->priv().createBackendTexture(32, 32, format, color,
+                                                                    mipMapped, renderable);
+                    };
+
+                    test_color_init(context, reporter, createWithColorMtd,
+                                    combo.fColorType, combo.fColor, mipMapped, renderable);
+                }
             }
         }
     }
@@ -269,37 +448,40 @@
     GrContext* context = ctxInfo.grContext();
     const GrVkCaps* vkCaps = static_cast<const GrVkCaps*>(context->priv().caps());
 
+    constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
+
     struct {
         SkColorType fColorType;
         VkFormat    fFormat;
+        SkColor4f   fColor;
     } combinations[] = {
-        { kRGBA_8888_SkColorType,    VK_FORMAT_R8G8B8A8_UNORM           },
-        { kRGBA_8888_SkColorType,    VK_FORMAT_R8G8B8A8_SRGB            },
+        { kRGBA_8888_SkColorType,    VK_FORMAT_R8G8B8A8_UNORM,           SkColors::kRed       },
+        { kRGBA_8888_SkColorType,    VK_FORMAT_R8G8B8A8_SRGB,            SkColors::kRed       },
 
-        { kRGB_888x_SkColorType,     VK_FORMAT_R8G8B8_UNORM             },
-        { kRGB_888x_SkColorType,     VK_FORMAT_R8G8B8A8_UNORM           },
+        { kRGB_888x_SkColorType,     VK_FORMAT_R8G8B8A8_UNORM,           { 1, 1, 0, 0.5f }    },
+        { kRGB_888x_SkColorType,     VK_FORMAT_R8G8B8_UNORM,             { 0, 1, 1, 0.5f }    },
 
-        { kBGRA_8888_SkColorType,    VK_FORMAT_B8G8R8A8_UNORM           },
-        { kBGRA_8888_SkColorType,    VK_FORMAT_B8G8R8A8_SRGB            },
+        { kBGRA_8888_SkColorType,    VK_FORMAT_B8G8R8A8_UNORM,           SkColors::kBlue      },
+        { kBGRA_8888_SkColorType,    VK_FORMAT_B8G8R8A8_SRGB,            SkColors::kCyan      },
 
-        { kRGBA_1010102_SkColorType, VK_FORMAT_A2B10G10R10_UNORM_PACK32 },
-        { kRGB_565_SkColorType,      VK_FORMAT_R5G6B5_UNORM_PACK16      },
+        { kRGBA_1010102_SkColorType, VK_FORMAT_A2B10G10R10_UNORM_PACK32, { 0.5f, 0, 0, 1.0f } },
+        { kRGB_565_SkColorType,      VK_FORMAT_R5G6B5_UNORM_PACK16,      SkColors::kRed       },
 
-        { kARGB_4444_SkColorType,    VK_FORMAT_R4G4B4A4_UNORM_PACK16    },
-        { kARGB_4444_SkColorType,    VK_FORMAT_B4G4R4A4_UNORM_PACK16    },
+        { kARGB_4444_SkColorType,    VK_FORMAT_R4G4B4A4_UNORM_PACK16,    SkColors::kGreen     },
+        { kARGB_4444_SkColorType,    VK_FORMAT_B4G4R4A4_UNORM_PACK16,    SkColors::kYellow    },
 
-        { kAlpha_8_SkColorType,      VK_FORMAT_R8_UNORM                 },
-        { kGray_8_SkColorType,       VK_FORMAT_R8_UNORM                 },
-        { kRGBA_F32_SkColorType,     VK_FORMAT_R32G32B32A32_SFLOAT      },
+        { kAlpha_8_SkColorType,      VK_FORMAT_R8_UNORM,                 kTransCol            },
+        { kGray_8_SkColorType,       VK_FORMAT_R8_UNORM,                 SkColors::kLtGray    },
+        { kRGBA_F32_SkColorType,     VK_FORMAT_R32G32B32A32_SFLOAT,      SkColors::kRed       },
 
-        { kRGBA_F16Norm_SkColorType, VK_FORMAT_R16G16B16A16_SFLOAT      },
-        { kRGBA_F16_SkColorType,     VK_FORMAT_R16G16B16A16_SFLOAT      },
+        { kRGBA_F16Norm_SkColorType, VK_FORMAT_R16G16B16A16_SFLOAT,      SkColors::kLtGray    },
+        { kRGBA_F16_SkColorType,     VK_FORMAT_R16G16B16A16_SFLOAT,      SkColors::kYellow    },
 
         // These backend formats don't have SkColorType equivalents
-        { kUnknown_SkColorType,      VK_FORMAT_R32G32_SFLOAT            },
-        { kUnknown_SkColorType,      VK_FORMAT_R8G8_UNORM               },
-        { kUnknown_SkColorType,      VK_FORMAT_R16_SFLOAT               },
-        { kUnknown_SkColorType,      VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK  },
+        { kUnknown_SkColorType,      VK_FORMAT_R32G32_SFLOAT,            { 0.7f, 0.7f, 0, 0 } },
+        { kUnknown_SkColorType,      VK_FORMAT_R8G8_UNORM,               { 0.5f, 0.5f, 0, 0 } },
+        { kUnknown_SkColorType,      VK_FORMAT_R16_SFLOAT,               { 1.0f, 0, 0, 0.5f } },
+        { kUnknown_SkColorType,      VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,  SkColors::kRed },
     };
 
     for (auto combo : combinations) {
@@ -328,8 +510,8 @@
 
                 {
                     auto uninitCreateMtd = [format](GrContext* context,
-                                              GrMipMapped mipMapped,
-                                              GrRenderable renderable) {
+                                                    GrMipMapped mipMapped,
+                                                    GrRenderable renderable) {
                         return context->createBackendTexture(32, 32, format,
                                                              mipMapped, renderable);
                     };
@@ -337,6 +519,22 @@
                     test_wrapping(context, reporter, uninitCreateMtd,
                                   combo.fColorType, mipMapped, renderable);
                 }
+
+                // Not implemented for Vulkan yet
+#if 0
+                {
+                    auto createWithColorMtd = [format](GrContext* context,
+                                                       const SkColor4f& color,
+                                                       GrMipMapped mipMapped,
+                                                       GrRenderable renderable) {
+                        return context->priv().createBackendTexture(32, 32, format, color,
+                                                                    mipMapped, renderable);
+                    };
+
+                    test_color_init(context, reporter, createWithColorMtd,
+                                    combo.fColorType, combo.fColor, mipMapped, renderable);
+                }
+#endif
             }
         }
     }
diff --git a/tests/MtlBackendAllocationTest.mm b/tests/MtlBackendAllocationTest.mm
index 6099697..0254d0f 100644
--- a/tests/MtlBackendAllocationTest.mm
+++ b/tests/MtlBackendAllocationTest.mm
@@ -14,49 +14,80 @@
 
 // In BackendAllocationTest.cpp
 void test_wrapping(GrContext* context, skiatest::Reporter* reporter,
-                   std::function<GrBackendTexture (GrContext*, GrMipMapped, GrRenderable)> create,
+                   std::function<GrBackendTexture (GrContext*,
+                                                   GrMipMapped,
+                                                   GrRenderable)> create,
                    SkColorType colorType, GrMipMapped mipMapped, GrRenderable renderable);
 
+void test_color_init(GrContext* context, skiatest::Reporter* reporter,
+                     std::function<GrBackendTexture (GrContext*,
+                                                     const SkColor4f&,
+                                                     GrMipMapped,
+                                                     GrRenderable)> create,
+                     SkColorType colorType, const SkColor4f& color,
+                     GrMipMapped mipMapped, GrRenderable renderable);
+
 DEF_GPUTEST_FOR_METAL_CONTEXT(MtlBackendAllocationTest, reporter, ctxInfo) {
     GrContext* context = ctxInfo.grContext();
     const GrMtlCaps* mtlCaps = static_cast<const GrMtlCaps*>(context->priv().caps());
 
+    constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
+
     struct {
         SkColorType      fColorType;
         GrMTLPixelFormat fFormat;
         // TODO: remove 'fConfig' and directly use 'fFormat' in GrMtlCaps::isFormatTexturable
         GrPixelConfig    fConfig;
+        SkColor4f        fColor;
     } combinations[] = {
-        { kRGBA_8888_SkColorType,    MTLPixelFormatRGBA8Unorm,      kRGBA_8888_GrPixelConfig      },
-        { kRGBA_8888_SkColorType,    MTLPixelFormatRGBA8Unorm_sRGB, kSRGBA_8888_GrPixelConfig     },
+        { kRGBA_8888_SkColorType,          MTLPixelFormatRGBA8Unorm,
+          kRGBA_8888_GrPixelConfig,        SkColors::kRed       },
+        { kRGBA_8888_SkColorType,          MTLPixelFormatRGBA8Unorm_sRGB,
+          kSRGBA_8888_GrPixelConfig,       SkColors::kRed       },
 
-        { kRGB_888x_SkColorType,     MTLPixelFormatRGBA8Unorm,      kRGBA_8888_GrPixelConfig      },
+        { kRGB_888x_SkColorType,           MTLPixelFormatRGBA8Unorm,
+          kRGBA_8888_GrPixelConfig,        { 1, 1, 0, 0.5f }    },
 
-        { kBGRA_8888_SkColorType,    MTLPixelFormatBGRA8Unorm,      kBGRA_8888_GrPixelConfig      },
-        { kBGRA_8888_SkColorType,    MTLPixelFormatBGRA8Unorm_sRGB, kSBGRA_8888_GrPixelConfig     },
+        { kBGRA_8888_SkColorType,          MTLPixelFormatBGRA8Unorm,
+          kBGRA_8888_GrPixelConfig,        SkColors::kBlue      },
+        { kBGRA_8888_SkColorType,          MTLPixelFormatBGRA8Unorm_sRGB,
+          kSBGRA_8888_GrPixelConfig,       SkColors::kCyan      },
 
-        { kRGBA_1010102_SkColorType, MTLPixelFormatRGB10A2Unorm,    kRGBA_1010102_GrPixelConfig    },
+        { kRGBA_1010102_SkColorType,       MTLPixelFormatRGB10A2Unorm,
+          kRGBA_1010102_GrPixelConfig,     { 0.5f, 0, 0, 1.0f } },
 #ifdef SK_BUILD_FOR_IOS
-        { kRGB_565_SkColorType,      MTLPixelFormatB5G6R5Unorm,     kRGB_565_GrPixelConfig        },
-        { kARGB_4444_SkColorType,    MTLPixelFormatABGR4Unorm,      kRGBA_4444_GrPixelConfig      },
+        { kRGB_565_SkColorType,             MTLPixelFormatB5G6R5Unorm,
+          kRGB_565_GrPixelConfig,           SkColors::kRed      },
+        { kARGB_4444_SkColorType,           MTLPixelFormatABGR4Unorm,
+          kRGBA_4444_GrPixelConfig,         SkColors::kGreen    },
 #endif
 
-        { kAlpha_8_SkColorType,      MTLPixelFormatA8Unorm,         kAlpha_8_as_Alpha_GrPixelConfig },
-        { kAlpha_8_SkColorType,      MTLPixelFormatR8Unorm,         kAlpha_8_as_Red_GrPixelConfig },
+        { kAlpha_8_SkColorType,             MTLPixelFormatA8Unorm,
+          kAlpha_8_as_Alpha_GrPixelConfig,  kTransCol           },
+        { kAlpha_8_SkColorType,             MTLPixelFormatR8Unorm,
+          kAlpha_8_as_Red_GrPixelConfig,    kTransCol           },
 
-        { kGray_8_SkColorType,       MTLPixelFormatR8Unorm,         kGray_8_as_Red_GrPixelConfig  },
+        { kGray_8_SkColorType,              MTLPixelFormatR8Unorm,
+          kGray_8_as_Red_GrPixelConfig,     SkColors::kDkGray   },
 
-        { kRGBA_F32_SkColorType,     MTLPixelFormatRGBA32Float,     kRGBA_float_GrPixelConfig     },
+        { kRGBA_F32_SkColorType,            MTLPixelFormatRGBA32Float,
+          kRGBA_float_GrPixelConfig,        SkColors::kRed      },
 
-        { kRGBA_F16Norm_SkColorType, MTLPixelFormatRGBA16Float,     kRGBA_half_Clamped_GrPixelConfig },
-        { kRGBA_F16_SkColorType,     MTLPixelFormatRGBA16Float,     kRGBA_half_GrPixelConfig      },
+        { kRGBA_F16Norm_SkColorType,        MTLPixelFormatRGBA16Float,
+          kRGBA_half_Clamped_GrPixelConfig, SkColors::kLtGray   },
+        { kRGBA_F16_SkColorType,            MTLPixelFormatRGBA16Float,
+          kRGBA_half_GrPixelConfig,         SkColors::kYellow   },
 
         // These backend formats don't have SkColorType equivalents
-        { kUnknown_SkColorType,     MTLPixelFormatRG32Float,        kRG_float_GrPixelConfig       },
-        { kUnknown_SkColorType,     MTLPixelFormatRG8Unorm,         kRG_88_GrPixelConfig          },
-        { kUnknown_SkColorType,     MTLPixelFormatR16Float,         kAlpha_half_as_Red_GrPixelConfig },
+        { kUnknown_SkColorType,             MTLPixelFormatRG32Float,
+          kRG_float_GrPixelConfig,          { 0.7f, 0.7f, 0, 0 }},
+        { kUnknown_SkColorType,             MTLPixelFormatRG8Unorm,
+          kRG_88_GrPixelConfig,             { 0.5f, 0.5f, 0, 0 }},
+        { kUnknown_SkColorType,             MTLPixelFormatR16Float,
+          kAlpha_half_as_Red_GrPixelConfig, { 1.0f, 0, 0, 0.5f }},
 #ifdef SK_BUILD_FOR_IOS
-        { kUnknown_SkColorType,     MTLPixelFormatETC2_RGB8,        kRGB_ETC1_GrPixelConfig       }
+        { kUnknown_SkColorType,              MTLPixelFormatETC2_RGB8,
+          kRGB_ETC1_GrPixelConfig,           SkColors::kRed     }
 #endif
     };
 
@@ -100,6 +131,22 @@
                     test_wrapping(context, reporter, uninitCreateMtd,
                                   combo.fColorType, mipMapped, renderable);
                 }
+
+                // Not implemented for Metal yet
+#if 0
+                {
+                    auto createWithColorMtd = [format](GrContext* context,
+                                                       const SkColor4f& color,
+                                                       GrMipMapped mipMapped,
+                                                       GrRenderable renderable) {
+                        return context->priv().createBackendTexture(32, 32, format, color,
+                                                                    mipMapped, renderable);
+                    };
+
+                    test_color_init(context, reporter, createWithColorMtd,
+                                    combo.fColorType, combo.fColor, mipMapped, renderable);
+                }
+#endif
             }
         }
     }