Support luminance-alpha GL format for YUVA planes

Bug: skia:10632
Change-Id: Ic91510b55644c15ee4eb5f96e7c35193b5ce49df
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/344761
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt
index 96e2c31..6021ad4 100644
--- a/RELEASE_NOTES.txt
+++ b/RELEASE_NOTES.txt
@@ -10,6 +10,10 @@
     a vector pointing towards the light, and light radius is blur radius at elevation 1.
     https://review.skia.org/321792
 
+  * Support GL_LUMINANCE8_ALPHA8 textures. These can be used with GrBackendTexture APIs
+    on GrDirectContext and as planes of YUVA images via GrYUVABackendTextures.
+    https://review.skia.org/344761
+
   * Removed previously deprecated SkImage::MakeFromYUVATexturesCopyToExternal.
     https://review.skia.org/342077
 
diff --git a/include/core/SkColor.h b/include/core/SkColor.h
index bdd097d..9cba771 100644
--- a/include/core/SkColor.h
+++ b/include/core/SkColor.h
@@ -240,9 +240,10 @@
     kAlpha_SkColorChannelFlag  = 1 << static_cast<uint32_t>(SkColorChannel::kA),
     kGray_SkColorChannelFlag   = 0x10,
     // Convenience values
-    kRG_SkColorChannelFlags    = kRed_SkColorChannelFlag | kGreen_SkColorChannelFlag,
-    kRGB_SkColorChannelFlags   = kRG_SkColorChannelFlags | kBlue_SkColorChannelFlag,
-    kRGBA_SkColorChannelFlags  = kRGB_SkColorChannelFlags | kAlpha_SkColorChannelFlag,
+    kGrayAlpha_SkColorChannelFlags = kGray_SkColorChannelFlag | kAlpha_SkColorChannelFlag,
+    kRG_SkColorChannelFlags        = kRed_SkColorChannelFlag | kGreen_SkColorChannelFlag,
+    kRGB_SkColorChannelFlags       = kRG_SkColorChannelFlags | kBlue_SkColorChannelFlag,
+    kRGBA_SkColorChannelFlags      = kRGB_SkColorChannelFlags | kAlpha_SkColorChannelFlag,
 };
 static_assert(0 == (kGray_SkColorChannelFlag & kRGBA_SkColorChannelFlags), "bitfield conflict");
 
diff --git a/include/gpu/gl/GrGLTypes.h b/include/gpu/gl/GrGLTypes.h
index 6cfeef2..7a3c57f 100644
--- a/include/gpu/gl/GrGLTypes.h
+++ b/include/gpu/gl/GrGLTypes.h
@@ -62,6 +62,7 @@
     kR8,
     kALPHA8,
     kLUMINANCE8,
+    kLUMINANCE8_ALPHA8,
     kBGRA8,
     kRGB565,
     kRGBA16F,
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index a0972d7..ef57711 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -816,6 +816,7 @@
     kRGBA_1010102,
     kBGRA_1010102,
     kGray_8,
+    kGrayAlpha_88,
     kAlpha_F16,
     kRGBA_F16,
     kRGBA_F16_Clamped,
@@ -863,6 +864,7 @@
         case GrColorType::kRGBA_1010102:     return kRGBA_1010102_SkColorType;
         case GrColorType::kBGRA_1010102:     return kBGRA_1010102_SkColorType;
         case GrColorType::kGray_8:           return kGray_8_SkColorType;
+        case GrColorType::kGrayAlpha_88:     return kUnknown_SkColorType;
         case GrColorType::kAlpha_F16:        return kA16_float_SkColorType;
         case GrColorType::kRGBA_F16:         return kRGBA_F16_SkColorType;
         case GrColorType::kRGBA_F16_Clamped: return kRGBA_F16Norm_SkColorType;
@@ -932,6 +934,7 @@
         case GrColorType::kRGBA_1010102:     return kRGBA_SkColorChannelFlags;
         case GrColorType::kBGRA_1010102:     return kRGBA_SkColorChannelFlags;
         case GrColorType::kGray_8:           return kGray_SkColorChannelFlag;
+        case GrColorType::kGrayAlpha_88:     return kGrayAlpha_SkColorChannelFlags;
         case GrColorType::kAlpha_F16:        return kAlpha_SkColorChannelFlag;
         case GrColorType::kRGBA_F16:         return kRGBA_SkColorChannelFlags;
         case GrColorType::kRGBA_F16_Clamped: return kRGBA_SkColorChannelFlags;
@@ -1005,6 +1008,10 @@
         return {0, 0, 0, 0, grayBits, e};
     }
 
+    static constexpr GrColorTypeDesc MakeGrayAlpha(int grayAlpha, GrColorTypeEncoding e) {
+        return {0, 0, 0, 0, grayAlpha, e};
+    }
+
     static constexpr GrColorTypeDesc MakeInvalid() { return {}; }
 
     constexpr int r() const { return fRBits; }
@@ -1069,6 +1076,8 @@
             return GrColorTypeDesc::MakeRGBA(10, 2, GrColorTypeEncoding::kUnorm);
         case GrColorType::kGray_8:
             return GrColorTypeDesc::MakeGray(8, GrColorTypeEncoding::kUnorm);
+        case GrColorType::kGrayAlpha_88:
+            return GrColorTypeDesc::MakeGrayAlpha(8, GrColorTypeEncoding::kUnorm);
         case GrColorType::kAlpha_F16:
             return GrColorTypeDesc::MakeAlpha(16, GrColorTypeEncoding::kFloat);
         case GrColorType::kRGBA_F16:
@@ -1151,6 +1160,7 @@
         case GrColorType::kRGBA_1010102:     return 4;
         case GrColorType::kBGRA_1010102:     return 4;
         case GrColorType::kGray_8:           return 1;
+        case GrColorType::kGrayAlpha_88:     return 2;
         case GrColorType::kAlpha_F16:        return 2;
         case GrColorType::kRGBA_F16:         return 8;
         case GrColorType::kRGBA_F16_Clamped: return 8;
@@ -1289,6 +1299,7 @@
         case GrColorType::kRGBA_1010102:     return "kRGBA_1010102";
         case GrColorType::kBGRA_1010102:     return "kBGRA_1010102";
         case GrColorType::kGray_8:           return "kGray_8";
+        case GrColorType::kGrayAlpha_88:     return "kGrayAlpha_88";
         case GrColorType::kAlpha_F16:        return "kAlpha_F16";
         case GrColorType::kRGBA_F16:         return "kRGBA_F16";
         case GrColorType::kRGBA_F16_Clamped: return "kRGBA_F16_Clamped";
diff --git a/src/core/SkRasterPipeline.h b/src/core/SkRasterPipeline.h
index ca55c34..008f6d4 100644
--- a/src/core/SkRasterPipeline.h
+++ b/src/core/SkRasterPipeline.h
@@ -60,7 +60,8 @@
     M(load_rg1616) M(load_rg1616_dst) M(store_rg1616) M(gather_rg1616) \
     M(load_16161616) M(load_16161616_dst) M(store_16161616) M(gather_16161616) \
     M(load_1010102) M(load_1010102_dst) M(store_1010102) M(gather_1010102) \
-    M(alpha_to_gray) M(alpha_to_gray_dst) M(bt709_luminance_or_luma_to_alpha)         \
+    M(alpha_to_gray) M(alpha_to_gray_dst)                          \
+    M(bt709_luminance_or_luma_to_alpha) M(bt709_luminance_or_luma_to_rgb) \
     M(bilerp_clamp_8888) M(bicubic_clamp_8888)                     \
     M(store_u16_be)                                                \
     M(load_src) M(store_src) M(store_src_a) M(load_dst) M(store_dst) \
diff --git a/src/core/SkYUVAInfo.cpp b/src/core/SkYUVAInfo.cpp
index 2cce7b9..4769934 100644
--- a/src/core/SkYUVAInfo.cpp
+++ b/src/core/SkYUVAInfo.cpp
@@ -101,6 +101,13 @@
                 return true;
             }
             return false;
+        case kGrayAlpha_SkColorChannelFlags:
+            switch (channelIdx) {
+                case 0: *channel = SkColorChannel::kR; return true;
+                case 1: *channel = SkColorChannel::kA; return true;
+
+                default: return false;
+            }
         case kAlpha_SkColorChannelFlag:
             if (channelIdx == 0) {
                 *channel = SkColorChannel::kA;
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index 9aebc93..11a4124 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -388,6 +388,9 @@
         case GrColorType::kGray_8:           *load = SkRasterPipeline::load_a8;
                                              swizzle = GrSwizzle("aaa1");
                                              break;
+        case GrColorType::kGrayAlpha_88:    *load = SkRasterPipeline::load_rg88;
+                                             swizzle = GrSwizzle("rrrg");
+                                             break;
         case GrColorType::kBGRA_8888:        *load = SkRasterPipeline::load_8888;
                                              swizzle = GrSwizzle("bgra");
                                              break;
@@ -407,12 +410,18 @@
     return swizzle;
 }
 
+enum class LumMode {
+    kNone,
+    kToRGB,
+    kToAlpha
+};
+
 static GrSwizzle get_dst_swizzle_and_store(GrColorType ct, SkRasterPipeline::StockStage* store,
-                                           bool* doLumToAlpha, bool* isNormalized, bool* isSRGB) {
+                                           LumMode* lumMode, bool* isNormalized, bool* isSRGB) {
     GrSwizzle swizzle("rgba");
     *isNormalized = true;
     *isSRGB = false;
-    *doLumToAlpha = false;
+    *lumMode = LumMode::kNone;
     switch (ct) {
         case GrColorType::kAlpha_8:          *store = SkRasterPipeline::store_a8;       break;
         case GrColorType::kAlpha_16:         *store = SkRasterPipeline::store_a16;      break;
@@ -468,15 +477,19 @@
         case GrColorType::kR_F16:            swizzle = GrSwizzle("agbr");
                                              *store = SkRasterPipeline::store_af16;
                                              break;
-        case GrColorType::kGray_F16:         *doLumToAlpha = true;
+        case GrColorType::kGray_F16:         *lumMode = LumMode::kToAlpha;
                                              *store = SkRasterPipeline::store_af16;
                                              break;
-        case GrColorType::kGray_8:           *doLumToAlpha = true;
+        case GrColorType::kGray_8:           *lumMode = LumMode::kToAlpha;
                                              *store = SkRasterPipeline::store_a8;
                                              break;
-        case GrColorType::kGray_8xxx:        *doLumToAlpha = true;
+        case GrColorType::kGrayAlpha_88:     *lumMode = LumMode::kToRGB;
+                                             swizzle = GrSwizzle("ragb");
+                                             *store = SkRasterPipeline::store_rg88;
+                                             break;
+        case GrColorType::kGray_8xxx:        *lumMode = LumMode::kToRGB;
                                              *store = SkRasterPipeline::store_8888;
-                                             swizzle = GrSwizzle("a000");
+                                             swizzle = GrSwizzle("r000");
                                              break;
 
         // These are color types we don't expect to ever have to store.
@@ -571,10 +584,10 @@
             get_load_and_src_swizzle(srcInfo.colorType(), &load, &srcIsNormalized, &srcIsSRGB);
 
     SkRasterPipeline::StockStage store;
-    bool doLumToAlpha;
+    LumMode lumMode;
     bool dstIsNormalized;
     bool dstIsSRGB;
-    auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &doLumToAlpha,
+    auto storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &lumMode,
                                                   &dstIsNormalized, &dstIsSRGB);
 
     bool clampGamut;
@@ -606,7 +619,7 @@
         std::swap(cnt, height);
     }
 
-    bool hasConversion = alphaOrCSConversion || clampGamut || doLumToAlpha;
+    bool hasConversion = alphaOrCSConversion || clampGamut || lumMode != LumMode::kNone;
 
     if (srcIsSRGB && dstIsSRGB && !hasConversion) {
         // No need to convert from srgb if we are just going to immediately convert it back.
@@ -629,14 +642,20 @@
             if (clampGamut) {
                 append_clamp_gamut(&pipeline);
             }
-            if (doLumToAlpha) {
-                pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
-                // If we ever needed to convert from linear-encoded gray to sRGB-encoded
-                // gray we'd have a problem here because the subsequent transfer function stage
-                // ignores the alpha channel (where we just stashed the gray). There are
-                // several ways that could be fixed but given our current set of color types
-                // this should never happen.
-                SkASSERT(!dstIsSRGB);
+            switch (lumMode) {
+                case LumMode::kNone:
+                    break;
+                case LumMode::kToRGB:
+                    pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_rgb);
+                    break;
+                case LumMode::kToAlpha:
+                    pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
+                    // If we ever need to store srgb-encoded gray (e.g. GL_SLUMINANCE8) then we
+                    // should use ToRGB and then a swizzle stage rather than ToAlpha. The subsequent
+                    // transfer function stage ignores the alpha channel (where we just stashed the
+                    // gray).
+                    SkASSERT(!dstIsSRGB);
+                    break;
             }
             if (dstIsSRGB) {
                 pipeline.append_transfer_function(*skcms_sRGB_Inverse_TransferFunction());
@@ -677,24 +696,29 @@
         return true;
     }
 
-    bool doLumToAlpha;
+    LumMode lumMode;
     bool isNormalized;
     bool dstIsSRGB;
     SkRasterPipeline::StockStage store;
-    GrSwizzle storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &doLumToAlpha,
+    GrSwizzle storeSwizzle = get_dst_swizzle_and_store(dstInfo.colorType(), &store, &lumMode,
                                                        &isNormalized, &dstIsSRGB);
     char block[64];
     SkArenaAlloc alloc(block, sizeof(block), 1024);
     SkRasterPipeline_<256> pipeline;
     pipeline.append_constant_color(&alloc, color);
-    if (doLumToAlpha) {
-        pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
-        // If we ever needed to convert from linear-encoded gray to sRGB-encoded
-        // gray we'd have a problem here because the subsequent transfer function stage
-        // ignores the alpha channel (where we just stashed the gray). There are
-        // several ways that could be fixed but given our current set of color types
-        // this should never happen.
-        SkASSERT(!dstIsSRGB);
+    switch (lumMode) {
+        case LumMode::kNone:
+            break;
+        case LumMode::kToRGB:
+            pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_rgb);
+            break;
+        case LumMode::kToAlpha:
+            pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha);
+            // If we ever need to store srgb-encoded gray (e.g. GL_SLUMINANCE8) then we should use
+            // ToRGB and then a swizzle stage rather than ToAlpha. The subsequent transfer function
+            // stage ignores the alpha channel (where we just stashed the gray).
+            SkASSERT(!dstIsSRGB);
+            break;
     }
     if (dstIsSRGB) {
         pipeline.append_transfer_function(*skcms_sRGB_Inverse_TransferFunction());
diff --git a/src/gpu/GrYUVABackendTextures.cpp b/src/gpu/GrYUVABackendTextures.cpp
index cdd04be..a29e700 100644
--- a/src/gpu/GrYUVABackendTextures.cpp
+++ b/src/gpu/GrYUVABackendTextures.cpp
@@ -9,13 +9,14 @@
 
 static int num_channels(const GrBackendFormat& format) {
     switch (format.channelMask()) {
-        case kRed_SkColorChannelFlag  : return 1;
-        case kAlpha_SkColorChannelFlag: return 1;
-        case kGray_SkColorChannelFlag : return 1;
-        case kRG_SkColorChannelFlags  : return 2;
-        case kRGB_SkColorChannelFlags : return 3;
-        case kRGBA_SkColorChannelFlags: return 4;
-        default                       : return 0;
+        case kRed_SkColorChannelFlag        : return 1;
+        case kAlpha_SkColorChannelFlag      : return 1;
+        case kGray_SkColorChannelFlag       : return 1;
+        case kGrayAlpha_SkColorChannelFlags : return 2;
+        case kRG_SkColorChannelFlags        : return 2;
+        case kRGB_SkColorChannelFlags       : return 3;
+        case kRGBA_SkColorChannelFlags      : return 4;
+        default                             : return 0;
     }
 }
 
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index d08b4f0..39e4c48 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -176,6 +176,7 @@
         case GrColorType::kAlpha_8:
         case GrColorType::kAlpha_8xxx:
         case GrColorType::kGray_8:
+        case GrColorType::kGrayAlpha_88:
         case GrColorType::kGray_8xxx:
         case GrColorType::kR_8:
         case GrColorType::kRG_88:
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index a71d452..4efaec2 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1801,6 +1801,79 @@
         }
     }
 
+    // Format: LUMINANCE8_ALPHA8
+    {
+        FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8_ALPHA8);
+        info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE8_ALPHA8;
+        info.fDefaultExternalFormat = GR_GL_LUMINANCE_ALPHA;
+        info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
+        info.fDefaultColorType = GrColorType::kGrayAlpha_88;
+        bool la8Supported = false;
+        bool la8SizedFormatSupported = false;
+        if (GR_IS_GR_GL(standard) && !fIsCoreProfile) {
+            la8Supported = true;
+            la8SizedFormatSupported = true;
+        } else if (GR_IS_GR_GL_ES(standard)) {
+            la8Supported = true;
+            // Even on ES3 this extension is required to define LUMINANCE8_ALPHA8.
+            la8SizedFormatSupported = ctxInfo.hasExtension("GL_EXT_texture_storage");
+        } else if (GR_IS_GR_WEBGL(standard)) {
+            la8Supported = true;
+        }
+        if (la8Supported) {
+            info.fFlags = FormatInfo::kTexturable_Flag;
+        }
+        if (texStorageSupported && la8SizedFormatSupported) {
+            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
+            info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8_ALPHA8;
+        } else if (texImageSupportsSizedInternalFormat && la8SizedFormatSupported) {
+            info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8_ALPHA8;
+        } else {
+            info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE_ALPHA;
+        }
+        // See note in LUMINANCE8 section about not attaching to framebuffers.
+
+        if (la8Supported) {
+            info.fColorTypeInfoCount = 1;
+            info.fColorTypeInfos = std::make_unique<ColorTypeInfo[]>(info.fColorTypeInfoCount);
+            int ctIdx = 0;
+            // Format: LUMINANCE8_ALPHA8, Surface: kGrayAlpha_88
+            {
+                auto& ctInfo = info.fColorTypeInfos[ctIdx++];
+                ctInfo.fColorType = GrColorType::kGrayAlpha_88;
+                ctInfo.fFlags = ColorTypeInfo::kUploadData_Flag;
+                int idx = static_cast<int>(GrColorType::kGrayAlpha_88);
+                if (fColorTypeToFormatTable[idx] == GrGLFormat::kUnknown) {
+                    this->setColorTypeFormat(GrColorType::kGrayAlpha_88,
+                                             GrGLFormat::kLUMINANCE8_ALPHA8);
+                }
+
+                // External IO ColorTypes:
+                ctInfo.fExternalIOFormatCount = 2;
+                ctInfo.fExternalIOFormats = std::make_unique<ColorTypeInfo::ExternalIOFormats[]>(
+                        ctInfo.fExternalIOFormatCount);
+                int ioIdx = 0;
+                // Format: LUMINANCE8, Surface: kGrayAlpha_88, Data: kGrayAlpha_88
+                {
+                    auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
+                    ioFormat.fColorType = GrColorType::kGrayAlpha_88;
+                    ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
+                    ioFormat.fExternalTexImageFormat = GR_GL_LUMINANCE_ALPHA;
+                    ioFormat.fExternalReadFormat = 0;
+                }
+
+                // Format: LUMINANCE8, Surface: kGrayAlpha_88, Data: kRGBA_8888
+                {
+                    auto& ioFormat = ctInfo.fExternalIOFormats[ioIdx++];
+                    ioFormat.fColorType = GrColorType::kRGBA_8888;
+                    ioFormat.fExternalType = GR_GL_UNSIGNED_BYTE;
+                    ioFormat.fExternalTexImageFormat = 0;
+                    ioFormat.fExternalReadFormat = GR_GL_RGBA;
+                }
+            }
+        }
+    }
     // Format: BGRA8
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kBGRA8);
@@ -3220,17 +3293,16 @@
             // The formats don't represent color channels (i.e. may be depth stencil)
             return false;
         }
-        // The dst channels have to be a subset of the srcChannels, unless the dst is going to
-        // gray.
+        // The dst channels have to be a subset of the srcChannels, except R, RG, or RGB, channels
+        // can go to LUM. (See expansion of Table 3.9 in EXT_texture_rg).
         if ((dstChannels & srcChannels) != srcChannels) {
-            if (dstChannels == kGray_SkColorChannelFlag) {
-                // We can't copy Alpha into a Luminance channel
-                if (srcChannels == kAlpha_8_SkColorType) {
+            if (dstChannels == kGray_SkColorChannelFlag ||
+                dstChannels == kGrayAlpha_SkColorChannelFlags) {
+                // The dst can't have gray if the src is alpha-only.
+                if (srcChannels == kAlpha_SkColorChannelFlag) {
                     return false;
                 }
             } else {
-                // Currently we don't support any LA formats
-                SkASSERT((dstChannels & kGray_SkColorChannelFlag) == 0);
                 return false;
             }
         }
@@ -4528,6 +4600,8 @@
           GrBackendFormat::MakeGL(GR_GL_LUMINANCE8, GR_GL_TEXTURE_2D) },
         { GrColorType::kGray_8,
           GrBackendFormat::MakeGL(GR_GL_R8, GR_GL_TEXTURE_2D) },
+        { GrColorType::kGrayAlpha_88,
+          GrBackendFormat::MakeGL(GR_GL_LUMINANCE8_ALPHA8, GR_GL_TEXTURE_2D) },
         { GrColorType::kAlpha_F16,
           GrBackendFormat::MakeGL(GR_GL_R16F, GR_GL_TEXTURE_2D) },
         { GrColorType::kAlpha_F16,
diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h
index 8fde6be..76c785a 100644
--- a/src/gpu/gl/GrGLDefines.h
+++ b/src/gpu/gl/GrGLDefines.h
@@ -467,6 +467,7 @@
 
 /* Luminance sized formats */
 #define GR_GL_LUMINANCE8                     0x8040
+#define GR_GL_LUMINANCE8_ALPHA8              0x8045
 #define GR_GL_LUMINANCE16F                   0x881E
 
 /* Alpha sized formats */
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 3340ee9..73387ba 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -629,6 +629,7 @@
         case GrGLFormat::kR8:
         case GrGLFormat::kALPHA8:
         case GrGLFormat::kLUMINANCE8:
+        case GrGLFormat::kLUMINANCE8_ALPHA8:
         case GrGLFormat::kBGRA8:
         case GrGLFormat::kRGB565:
         case GrGLFormat::kRGBA16F:
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index 760847d..c423e44 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -45,6 +45,7 @@
         case GrGLFormat::kR8:                    return kRed_SkColorChannelFlag;
         case GrGLFormat::kALPHA8:                return kAlpha_SkColorChannelFlag;
         case GrGLFormat::kLUMINANCE8:            return kGray_SkColorChannelFlag;
+        case GrGLFormat::kLUMINANCE8_ALPHA8:     return kGrayAlpha_SkColorChannelFlags;
         case GrGLFormat::kBGRA8:                 return kRGBA_SkColorChannelFlags;
         case GrGLFormat::kRGB565:                return kRGB_SkColorChannelFlags;
         case GrGLFormat::kRGBA16F:               return kRGBA_SkColorChannelFlags;
@@ -327,6 +328,7 @@
         case GR_GL_R8:                   return GrGLFormat::kR8;
         case GR_GL_ALPHA8:               return GrGLFormat::kALPHA8;
         case GR_GL_LUMINANCE8:           return GrGLFormat::kLUMINANCE8;
+        case GR_GL_LUMINANCE8_ALPHA8:    return GrGLFormat::kLUMINANCE8_ALPHA8;
         case GR_GL_BGRA8:                return GrGLFormat::kBGRA8;
         case GR_GL_RGB565:               return GrGLFormat::kRGB565;
         case GR_GL_RGBA16F:              return GrGLFormat::kRGBA16F;
@@ -361,6 +363,7 @@
         case GrGLFormat::kR8:                   return GR_GL_R8;
         case GrGLFormat::kALPHA8:               return GR_GL_ALPHA8;
         case GrGLFormat::kLUMINANCE8:           return GR_GL_LUMINANCE8;
+        case GrGLFormat::kLUMINANCE8_ALPHA8:    return GR_GL_LUMINANCE8_ALPHA8;
         case GrGLFormat::kBGRA8:                return GR_GL_BGRA8;
         case GrGLFormat::kRGB565:               return GR_GL_RGB565;
         case GrGLFormat::kRGBA16F:              return GR_GL_RGBA16F;
@@ -393,6 +396,7 @@
         case GrGLFormat::kR8:                   return 1;
         case GrGLFormat::kALPHA8:               return 1;
         case GrGLFormat::kLUMINANCE8:           return 1;
+        case GrGLFormat::kLUMINANCE8_ALPHA8:    return 2;
         case GrGLFormat::kBGRA8:                return 4;
         case GrGLFormat::kRGB565:               return 2;
         case GrGLFormat::kRGBA16F:              return 8;
@@ -436,6 +440,7 @@
         case GrGLFormat::kR8:
         case GrGLFormat::kALPHA8:
         case GrGLFormat::kLUMINANCE8:
+        case GrGLFormat::kLUMINANCE8_ALPHA8:
         case GrGLFormat::kBGRA8:
         case GrGLFormat::kRGB565:
         case GrGLFormat::kRGBA16F:
@@ -468,6 +473,7 @@
         case GrGLFormat::kR8:
         case GrGLFormat::kALPHA8:
         case GrGLFormat::kLUMINANCE8:
+        case GrGLFormat::kLUMINANCE8_ALPHA8:
         case GrGLFormat::kBGRA8:
         case GrGLFormat::kRGB565:
         case GrGLFormat::kRGBA16F:
@@ -502,6 +508,7 @@
     case GrGLFormat::kR8:
     case GrGLFormat::kALPHA8:
     case GrGLFormat::kLUMINANCE8:
+    case GrGLFormat::kLUMINANCE8_ALPHA8:
     case GrGLFormat::kBGRA8:
     case GrGLFormat::kRGB565:
     case GrGLFormat::kRGBA16F:
@@ -531,6 +538,7 @@
         case GR_GL_R8:                   return "R8";
         case GR_GL_ALPHA8:               return "ALPHA8";
         case GR_GL_LUMINANCE8:           return "LUMINANCE8";
+        case GR_GL_LUMINANCE8_ALPHA8:    return "LUMINANCE8_ALPHA8";
         case GR_GL_BGRA8:                return "BGRA8";
         case GR_GL_RGB565:               return "RGB565";
         case GR_GL_RGBA16F:              return "RGBA16F";
diff --git a/src/opts/SkRasterPipeline_opts.h b/src/opts/SkRasterPipeline_opts.h
index 680b335..0e7635f 100644
--- a/src/opts/SkRasterPipeline_opts.h
+++ b/src/opts/SkRasterPipeline_opts.h
@@ -2334,6 +2334,9 @@
     a = r*0.2126f + g*0.7152f + b*0.0722f;
     r = g = b = 0;
 }
+STAGE(bt709_luminance_or_luma_to_rgb, Ctx::None) {
+    r = g = b = r*0.2126f + g*0.7152f + b*0.0722f;
+}
 
 STAGE(matrix_translate, const float* m) {
     r += m[0];
@@ -3722,6 +3725,9 @@
     a = (r*54 + g*183 + b*19)/256;  // 0.2126, 0.7152, 0.0722 with 256 denominator.
     r = g = b = 0;
 }
+STAGE_PP(bt709_luminance_or_luma_to_rgb, Ctx::None) {
+    r = g = b =(r*54 + g*183 + b*19)/256;  // 0.2126, 0.7152, 0.0722 with 256 denominator.
+}
 
 // ~~~~~~ Coverage scales / lerps ~~~~~~ //
 
diff --git a/tests/BackendAllocationTest.cpp b/tests/BackendAllocationTest.cpp
index 73f91ed..98cd4d2 100644
--- a/tests/BackendAllocationTest.cpp
+++ b/tests/BackendAllocationTest.cpp
@@ -301,16 +301,16 @@
                                                                 GrRenderable)> create,
                      GrColorType colorType,
                      const SkColor4f& color,
-                     GrMipmapped mipMapped,
+                     GrMipmapped mipmapped,
                      GrRenderable renderable) {
-    sk_sp<ManagedBackendTexture> mbet = create(dContext, color, mipMapped, renderable);
+    sk_sp<ManagedBackendTexture> mbet = create(dContext, color, mipmapped, renderable);
     if (!mbet) {
         // errors here should be reported by the test_wrapping test
         return;
     }
 
     auto checkBackendTexture = [&](const SkColor4f& testColor) {
-        if (mipMapped == GrMipmapped::kYes) {
+        if (mipmapped == GrMipmapped::kYes) {
             SkColor4f expectedColor = get_expected_color(testColor, colorType);
             SkColor4f expectedColors[6] = {expectedColor, expectedColor, expectedColor,
                                            expectedColor, expectedColor, expectedColor};
@@ -732,8 +732,9 @@
     auto context = ctxInfo.directContext();
     const GrGLCaps* glCaps = static_cast<const GrGLCaps*>(context->priv().caps());
 
-    constexpr SkColor4f kTransCol { 0, 0.25f, 0.75f, 0.5f };
-    constexpr SkColor4f kGrayCol { 0.75f, 0.75f, 0.75f, 0.75f };
+    constexpr SkColor4f kTransCol     { 0,     0.25f, 0.75f, 0.5f };
+    constexpr SkColor4f kGrayCol      { 0.75f, 0.75f, 0.75f, 1.f  };
+    constexpr SkColor4f kTransGrayCol { 0.5f,  0.5f,  0.5f,  .8f  };
 
     struct {
         GrColorType   fColorType;
@@ -760,6 +761,8 @@
         { GrColorType::kGray_8,           GR_GL_LUMINANCE8,           kGrayCol             },
         { GrColorType::kGray_8,           GR_GL_R8,                   kGrayCol             },
 
+        { GrColorType::kGrayAlpha_88,     GR_GL_LUMINANCE8_ALPHA8,    kTransGrayCol        },
+
         { GrColorType::kRGBA_F32,         GR_GL_RGBA32F,              SkColors::kRed       },
 
         { GrColorType::kRGBA_F16_Clamped, GR_GL_RGBA16F,              SkColors::kLtGray    },