Add a class representing texture swizzle.

Store config swizzle GrGLCaps and shader swizzles in GrGLSLCaps.

Remove GrTextureAccess's swizzle and update users of it to swizzle in their shader code.
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1567733005

Committed: https://skia.googlesource.com/skia/+/1a1efeacf7cc94a8c2977114dfe230fed3efc105

Review URL: https://codereview.chromium.org/1567733005
diff --git a/src/effects/SkColorCubeFilter.cpp b/src/effects/SkColorCubeFilter.cpp
index 7f1f596..5f1f10d 100644
--- a/src/effects/SkColorCubeFilter.cpp
+++ b/src/effects/SkColorCubeFilter.cpp
@@ -212,7 +212,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrColorCubeEffect::GrColorCubeEffect(GrTexture* colorCube)
-    : fColorCubeAccess(colorCube, "bgra", GrTextureParams::kBilerp_FilterMode) {
+    : fColorCubeAccess(colorCube, GrTextureParams::kBilerp_FilterMode) {
     this->initClassID<GrColorCubeEffect>();
     this->addTextureAccess(&fColorCubeAccess);
 }
@@ -287,11 +287,11 @@
     // Apply the cube.
     fragBuilder->codeAppendf("%s = vec4(mix(", args.fOutputColor);
     fragBuilder->appendTextureLookup(args.fSamplers[0], cCoords1);
-    fragBuilder->codeAppend(".rgb, ");
+    fragBuilder->codeAppend(".bgr, ");
     fragBuilder->appendTextureLookup(args.fSamplers[0], cCoords2);
 
     // Premultiply color by alpha. Note that the input alpha is not modified by this shader.
-    fragBuilder->codeAppendf(".rgb, fract(%s.b)) * vec3(%s), %s.a);\n",
+    fragBuilder->codeAppendf(".bgr, fract(%s.b)) * vec3(%s), %s.a);\n",
                              cubeIdx, nonZeroAlpha, args.fInputColor);
 }
 
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 32617cd..d9c07e2 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -442,22 +442,22 @@
     fragBuilder->codeAppendf("\t\t%s.a = ", args.fOutputColor);
     coord.printf("vec2(coord.a, %s.a)", yoffsets);
     fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
-    fragBuilder->codeAppend(";\n");
+    fragBuilder->codeAppend(".a;\n");
 
     fragBuilder->codeAppendf("\t\t%s.r = ", args.fOutputColor);
     coord.printf("vec2(coord.r, %s.r)", yoffsets);
     fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
-    fragBuilder->codeAppend(";\n");
+    fragBuilder->codeAppend(".a;\n");
 
     fragBuilder->codeAppendf("\t\t%s.g = ", args.fOutputColor);
     coord.printf("vec2(coord.g, %s.g)", yoffsets);
     fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
-    fragBuilder->codeAppend(";\n");
+    fragBuilder->codeAppend(".a;\n");
 
     fragBuilder->codeAppendf("\t\t%s.b = ", args.fOutputColor);
     coord.printf("vec2(coord.b, %s.b)", yoffsets);
     fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
-    fragBuilder->codeAppend(";\n");
+    fragBuilder->codeAppend(".a;\n");
 
     fragBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor);
 }
@@ -487,7 +487,7 @@
 
 ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
                                    unsigned flags)
-    : fTextureAccess(texture, "a")
+    : fTextureAccess(texture)
     , fFlags(flags)
     , fAtlas(atlas)
     , fRow(row) {
diff --git a/src/gpu/GrSwizzle.h b/src/gpu/GrSwizzle.h
new file mode 100644
index 0000000..87ea953
--- /dev/null
+++ b/src/gpu/GrSwizzle.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrSwizzle_DEFINED
+#define GrSwizzle_DEFINED
+
+#include "GrTypes.h"
+
+/** Represents a rgba swizzle. It can be converted either into a string or a eight bit int.
+    Currently there is no way to specify an arbitrary swizzle, just some static swizzles and an
+    assignment operator. That could be relaxed. */
+class GrSwizzle {
+public:
+    GrSwizzle() { *this = RGBA(); }
+
+    GrSwizzle& operator=(const GrSwizzle& that) {
+        memcpy(this, &that, sizeof(GrSwizzle));
+        return *this;
+    }
+
+    bool operator==(const GrSwizzle& that) const { return this->asUInt() == that.asUInt(); }
+
+    bool operator!=(const GrSwizzle& that) const { return !(*this == that); }
+
+    /** Compact representation of the swizzle suitable for a key. */
+    uint8_t asKey() const { return fKey; }
+
+    /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a'. */
+    const char* c_str() const { return fSwiz; }
+
+    static const GrSwizzle& RGBA() {
+        static GrSwizzle gRGBA("rgba");
+        return gRGBA;
+    }
+
+    static const GrSwizzle& AAAA() {
+        static GrSwizzle gAAAA("aaaa");
+        return gAAAA;
+    }
+
+    static const GrSwizzle& RRRR() {
+        static GrSwizzle gRRRR("rrrr");
+        return gRRRR;
+    }
+
+    static const GrSwizzle& BGRA() {
+        static GrSwizzle gBGRA("bgra");
+        return gBGRA;
+    }
+
+private:
+    char fSwiz[5];
+    uint8_t fKey;
+
+    static int CharToIdx(char c) {
+        switch (c) {
+            case 'r':
+                return 0;
+            case 'g':
+                return 1;
+            case 'b':
+                return 2;
+            case 'a':
+                return 3;
+            default:
+                SkFAIL("Invalid swizzle char");
+                return 0;
+        }
+    }
+
+    explicit GrSwizzle(const char* str) {
+        SkASSERT(strlen(str) == 4);
+        fSwiz[0] = str[0];
+        fSwiz[1] = str[1];
+        fSwiz[2] = str[2];
+        fSwiz[3] = str[3];
+        fSwiz[4] = 0;
+        fKey = SkToU8(CharToIdx(fSwiz[0]) | (CharToIdx(fSwiz[1]) << 2) |
+                      (CharToIdx(fSwiz[2]) << 4) | (CharToIdx(fSwiz[3]) << 6));
+    }
+
+    uint32_t* asUIntPtr() { return SkTCast<uint32_t*>(fSwiz); }
+    uint32_t asUInt() const { return *SkTCast<const uint32_t*>(fSwiz); }
+
+    GR_STATIC_ASSERT(sizeof(char[4]) == sizeof(uint32_t));
+};
+
+#endif
diff --git a/src/gpu/GrTextureAccess.cpp b/src/gpu/GrTextureAccess.cpp
index 7e1eda6..277c0e3 100644
--- a/src/gpu/GrTextureAccess.cpp
+++ b/src/gpu/GrTextureAccess.cpp
@@ -9,12 +9,7 @@
 #include "GrColor.h"
 #include "GrTexture.h"
 
-GrTextureAccess::GrTextureAccess() {
-#ifdef SK_DEBUG
-    memcpy(fSwizzle, "void", 5);
-    fSwizzleMask = 0xbeeffeed;
-#endif
-}
+GrTextureAccess::GrTextureAccess() {}
 
 GrTextureAccess::GrTextureAccess(GrTexture* texture, const GrTextureParams& params) {
     this->reset(texture, params);
@@ -26,49 +21,12 @@
     this->reset(texture, filterMode, tileXAndY);
 }
 
-GrTextureAccess::GrTextureAccess(GrTexture* texture,
-                                 const char* swizzle,
-                                 const GrTextureParams& params) {
-    this->reset(texture, swizzle, params);
-}
-
-GrTextureAccess::GrTextureAccess(GrTexture* texture,
-                                 const char* swizzle,
-                                 GrTextureParams::FilterMode filterMode,
-                                 SkShader::TileMode tileXAndY) {
-    this->reset(texture, swizzle, filterMode, tileXAndY);
-}
-
-void GrTextureAccess::reset(GrTexture* texture,
-                            const char* swizzle,
-                            const GrTextureParams& params) {
-    SkASSERT(texture);
-    SkASSERT(strlen(swizzle) >= 1 && strlen(swizzle) <= 4);
-
-    fParams = params;
-    fTexture.set(SkRef(texture), kRead_GrIOType);
-    this->setSwizzle(swizzle);
-}
-
-void GrTextureAccess::reset(GrTexture* texture,
-                            const char* swizzle,
-                            GrTextureParams::FilterMode filterMode,
-                            SkShader::TileMode tileXAndY) {
-    SkASSERT(texture);
-    SkASSERT(strlen(swizzle) >= 1 && strlen(swizzle) <= 4);
-
-    fParams.reset(tileXAndY, filterMode);
-    fTexture.set(SkRef(texture), kRead_GrIOType);
-    this->setSwizzle(swizzle);
-}
 
 void GrTextureAccess::reset(GrTexture* texture,
                             const GrTextureParams& params) {
     SkASSERT(texture);
     fTexture.set(SkRef(texture), kRead_GrIOType);
     fParams = params;
-    memcpy(fSwizzle, "rgba", 5);
-    fSwizzleMask = kRGBA_GrColorComponentFlags;
 }
 
 void GrTextureAccess::reset(GrTexture* texture,
@@ -77,31 +35,4 @@
     SkASSERT(texture);
     fTexture.set(SkRef(texture), kRead_GrIOType);
     fParams.reset(tileXAndY, filterMode);
-    memcpy(fSwizzle, "rgba", 5);
-    fSwizzleMask = kRGBA_GrColorComponentFlags;
-}
-
-void GrTextureAccess::setSwizzle(const char* swizzle) {
-    fSwizzleMask = 0;
-    memset(fSwizzle, '\0', 5);
-    for (int i = 0; i < 4 && '\0' != swizzle[i]; ++i) {
-        fSwizzle[i] = swizzle[i];
-        switch (swizzle[i]) {
-            case 'r':
-                fSwizzleMask |= kR_GrColorComponentFlag;
-                break;
-            case 'g':
-                fSwizzleMask |= kG_GrColorComponentFlag;
-                break;
-            case 'b':
-                fSwizzleMask |= kB_GrColorComponentFlag;
-                break;
-            case 'a':
-                fSwizzleMask |= kA_GrColorComponentFlag;
-                break;
-            default:
-                SkFAIL("Unexpected swizzle string character.");
-                break;
-        }
-    }
 }
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 923c392..99ed042 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -42,6 +42,7 @@
     fIsCoreProfile = false;
     fBindFragDataLocationSupport = false;
     fExternalTextureSupport = false;
+    fTextureSwizzleSupport = false;
     fSRGBWriteControl = false;
     fRGBA8888PixelsOpsAreSlow = false;
     fPartialFBOReadIsSlow = false;
@@ -218,6 +219,16 @@
         }
     }
 
+    if (kGL_GrGLStandard == standard) {
+        if (version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_texture_swizzle")) {
+            fTextureSwizzleSupport = true;
+        }
+    } else {
+        if (version >= GR_GL_VER(3,0)) {
+            fTextureSwizzleSupport = true;
+        }
+    }
+
 #ifdef SK_BUILD_FOR_WIN
     // We're assuming that on Windows Chromium we're using ANGLE.
     bool isANGLE = kANGLE_GrGLDriver == ctxInfo.driver() ||
@@ -437,11 +448,14 @@
     }
 
     this->initShaderPrecisionTable(ctxInfo, gli, glslCaps);
-    // Requires fTexutreSwizzleSupport and fTextureRedSupport to be set before this point.
-    this->initConfigSwizzleTable(ctxInfo, glslCaps);
-    // Requires various members are already correctly initialized (e.g. fTextureRedSupport,
-    // msaa support).
-    this->initConfigTable(ctxInfo, gli);
+
+    if (contextOptions.fUseShaderSwizzling) {
+        fTextureSwizzleSupport = false;
+    }
+
+    // Requires fTextureRedSupport, fTextureSwizzleSupport, msaa support, ES compatibility have
+    // already been detected.
+    this->initConfigTable(ctxInfo, gli, glslCaps);
 
     this->applyOptionsOverrides(contextOptions);
     glslCaps->applyOptionsOverrides(contextOptions);
@@ -866,6 +880,8 @@
     r.appendf("RGBA 8888 pixel ops are slow: %s\n", (fRGBA8888PixelsOpsAreSlow ? "YES" : "NO"));
     r.appendf("Partial FBO read is slow: %s\n", (fPartialFBOReadIsSlow ? "YES" : "NO"));
     r.appendf("Bind uniform location support: %s\n", (fBindUniformLocationSupport ? "YES" : "NO"));
+    r.appendf("External texture support: %s\n", (fExternalTextureSupport ? "YES" : "NO"));
+    r.appendf("Texture swizzle support: %s\n", (fTextureSwizzleSupport ? "YES" : "NO"));
 
     r.append("Configs\n-------\n");
     for (int i = 0; i < kGrPixelConfigCnt; ++i) {
@@ -968,49 +984,12 @@
     }
 }
 
-void GrGLCaps::initConfigSwizzleTable(const GrGLContextInfo& ctxInfo, GrGLSLCaps* glslCaps) {
-    GrGLStandard standard = ctxInfo.standard();
-    GrGLVersion version = ctxInfo.version();
-
-    glslCaps->fMustSwizzleInShader = true;
-    if (kGL_GrGLStandard == standard) {
-        if (version >= GR_GL_VER(3,3) || ctxInfo.hasExtension("GL_ARB_texture_swizzle")) {
-            glslCaps->fMustSwizzleInShader = false;
-        }
-    } else {
-        if (version >= GR_GL_VER(3,0)) {
-            glslCaps->fMustSwizzleInShader = false;
-        }
-    }
-
-    glslCaps->fConfigSwizzle[kUnknown_GrPixelConfig] = nullptr;
-    if (fTextureRedSupport) {
-        glslCaps->fConfigSwizzle[kAlpha_8_GrPixelConfig] = "rrrr";
-        glslCaps->fConfigSwizzle[kAlpha_half_GrPixelConfig] = "rrrr";
-    } else {
-        glslCaps->fConfigSwizzle[kAlpha_8_GrPixelConfig] = "aaaa";
-        glslCaps->fConfigSwizzle[kAlpha_half_GrPixelConfig] = "aaaa";
-    }
-    glslCaps->fConfigSwizzle[kIndex_8_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kRGB_565_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kRGBA_4444_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kRGBA_8888_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kBGRA_8888_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kSRGBA_8888_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kETC1_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kLATC_GrPixelConfig] = "rrrr";
-    glslCaps->fConfigSwizzle[kR11_EAC_GrPixelConfig] = "rrrr";
-    glslCaps->fConfigSwizzle[kASTC_12x12_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kRGBA_float_GrPixelConfig] = "rgba";
-    glslCaps->fConfigSwizzle[kRGBA_half_GrPixelConfig] = "rgba";
-
-}
-
 bool GrGLCaps::bgraIsInternalFormat() const {
     return fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fBaseInternalFormat == GR_GL_BGRA;
 }
 
-void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli) {
+void GrGLCaps::initConfigTable(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli,
+                               GrGLSLCaps* glslCaps) {
     /*
         Comments on renderability of configs on various GL versions.
           OpenGL < 3.0:
@@ -1093,6 +1072,7 @@
     fConfigTable[kUnknown_GrPixelConfig].fFormats.fExternalFormat = 0;
     fConfigTable[kUnknown_GrPixelConfig].fFormats.fExternalType = 0;
     fConfigTable[kUnknown_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType;
+    fConfigTable[kUnknown_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     fConfigTable[kRGBA_8888_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA;
     fConfigTable[kRGBA_8888_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA8;
@@ -1109,6 +1089,7 @@
             fConfigTable[kRGBA_8888_GrPixelConfig].fFlags |= allRenderFlags;
         }
     }
+    fConfigTable[kRGBA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fExternalFormat= GR_GL_BGRA;
     fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fExternalType  = GR_GL_UNSIGNED_BYTE;
@@ -1144,6 +1125,7 @@
             }
         }
     }
+    fConfigTable[kBGRA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     // We only enable srgb support if both textures and FBOs support srgb.
     bool srgbSupport = false;
@@ -1177,6 +1159,7 @@
         fConfigTable[kSRGBA_8888_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag |
                                                          allRenderFlags;
     }
+    fConfigTable[kSRGBA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     fConfigTable[kRGB_565_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGB;
     if (this->ES2CompatibilitySupport()) {
@@ -1195,6 +1178,7 @@
     } else {
         fConfigTable[kRGB_565_GrPixelConfig].fFlags |= allRenderFlags;
     }
+    fConfigTable[kRGB_565_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     fConfigTable[kRGBA_4444_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGBA;
     fConfigTable[kRGBA_4444_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA4;
@@ -1209,15 +1193,18 @@
     } else {
         fConfigTable[kRGBA_4444_GrPixelConfig].fFlags |= allRenderFlags;
     }
+    fConfigTable[kRGBA_4444_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     if (this->textureRedSupport()) {
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED;
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_R8;
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalFormat = GR_GL_RED;
+        fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::RRRR();
     } else {
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA;
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA8;
         fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalFormat = GR_GL_ALPHA;
+        fConfigTable[kAlpha_8_GrPixelConfig].fSwizzle = GrSwizzle::AAAA();
     }
     fConfigTable[kAlpha_8_GrPixelConfig].fFormats.fExternalType = GR_GL_UNSIGNED_BYTE;
     fConfigTable[kAlpha_8_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType;
@@ -1273,15 +1260,18 @@
             fConfigTable[kRGBA_float_GrPixelConfig].fFlags |= fpRenderFlags;
         }
     }
+    fConfigTable[kRGBA_float_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     if (this->textureRedSupport()) {
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RED;
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_R16F;
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalFormat = GR_GL_RED;
+        fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::RRRR();
     } else {
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_ALPHA;
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_ALPHA16F;
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalFormat = GR_GL_ALPHA;
+        fConfigTable[kAlpha_half_GrPixelConfig].fSwizzle = GrSwizzle::AAAA();
     }
     if (kGL_GrGLStandard == ctxInfo.standard() || ctxInfo.version() >= GR_GL_VER(3, 0)) {
         fConfigTable[kAlpha_half_GrPixelConfig].fFormats.fExternalType = GR_GL_HALF_FLOAT;
@@ -1317,6 +1307,7 @@
             fConfigTable[kRGBA_half_GrPixelConfig].fFlags |= fpRenderFlags;
         }
     }
+    fConfigTable[kRGBA_half_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     // Compressed texture support
 
@@ -1350,6 +1341,7 @@
             }
         }
     }
+    fConfigTable[kIndex_8_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     // May change the internal format based on extensions.
     fConfigTable[kLATC_GrPixelConfig].fFormats.fBaseInternalFormat =
@@ -1378,6 +1370,7 @@
     fConfigTable[kLATC_GrPixelConfig].fFormats.fExternalFormat = 0;
     fConfigTable[kLATC_GrPixelConfig].fFormats.fExternalType = 0;
     fConfigTable[kLATC_GrPixelConfig].fFormatType = kNormalizedFixedPoint_FormatType;
+    fConfigTable[kLATC_GrPixelConfig].fSwizzle = GrSwizzle::RRRR();
 
     fConfigTable[kETC1_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8;
     fConfigTable[kETC1_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_COMPRESSED_ETC1_RGB8;
@@ -1397,6 +1390,7 @@
             fConfigTable[kETC1_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag;
         }
     }
+    fConfigTable[kETC1_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_COMPRESSED_R11_EAC;
     fConfigTable[kR11_EAC_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_COMPRESSED_R11_EAC;
@@ -1408,6 +1402,7 @@
     if (kGLES_GrGLStandard == standard && version >= GR_GL_VER(3,0)) {
         fConfigTable[kR11_EAC_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag;
     }
+    fConfigTable[kR11_EAC_GrPixelConfig].fSwizzle = GrSwizzle::RRRR();
 
     fConfigTable[kASTC_12x12_GrPixelConfig].fFormats.fBaseInternalFormat =
         GR_GL_COMPRESSED_RGBA_ASTC_12x12;
@@ -1421,6 +1416,7 @@
         ctxInfo.hasExtension("GL_OES_texture_compression_astc")) {
         fConfigTable[kASTC_12x12_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag;
     }
+    fConfigTable[kASTC_12x12_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
     // Bulk populate the texture internal/external formats here and then deal with exceptions below.
 
@@ -1458,6 +1454,14 @@
         fConfigTable[kBGRA_8888_GrPixelConfig].fFormats.fInternalFormatTexImage = GR_GL_BGRA;
     }
 
+    // If we don't have texture swizzle support then the shader generator must insert the
+    // swizzle into shader code.
+    if (!this->textureSwizzleSupport()) {
+        for (int i = 0; i < kGrPixelConfigCnt; ++i) {
+            glslCaps->fConfigTextureSwizzle[i] = fConfigTable[i].fSwizzle;
+        }
+    }
+
 #ifdef SK_DEBUG
     // Make sure we initialized everything.
     ConfigFormats defaultEntry;
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index a650348..db60ad2 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -9,9 +9,10 @@
 #ifndef GrGLCaps_DEFINED
 #define GrGLCaps_DEFINED
 
-#include "GrCaps.h"
 #include "glsl/GrGLSL.h"
+#include "GrCaps.h"
 #include "GrGLStencilAttachment.h"
+#include "GrSwizzle.h"
 #include "SkChecksum.h"
 #include "SkTHash.h"
 #include "SkTArray.h"
@@ -142,6 +143,11 @@
         return fConfigTable[config].fFormats;
     }
 
+    /** Returns the mapping between GrPixelConfig components and GL internal format components. */
+    const GrSwizzle& configSwizzle(GrPixelConfig config) const {
+        return fConfigTable[config].fSwizzle;
+    }
+
     /**
     * Gets an array of legal stencil formats. These formats are not guaranteed
     * to be supported by the driver but are legal GLenum names given the GL
@@ -307,6 +313,9 @@
     /// Are textures with GL_TEXTURE_EXTERNAL_OES type supported.
     bool externalTextureSupport() const { return fExternalTextureSupport; }
 
+    /// GL_ARB_texture_swizzle
+    bool textureSwizzleSupport() const { return fTextureSwizzleSupport; }
+
     /**
      * Is there support for enabling/disabling sRGB writes for sRGB-capable color attachments?
      * If false this does not mean sRGB is not supported but rather that if it is supported
@@ -335,15 +344,12 @@
     void initBlendEqationSupport(const GrGLContextInfo&);
     void initStencilFormats(const GrGLContextInfo&);
     // This must be called after initFSAASupport().
-    void initConfigTable(const GrGLContextInfo&, const GrGLInterface* gli);
+    void initConfigTable(const GrGLContextInfo&, const GrGLInterface* gli, GrGLSLCaps* glslCaps);
 
     void initShaderPrecisionTable(const GrGLContextInfo& ctxInfo,
                                   const GrGLInterface* intf,
                                   GrGLSLCaps* glslCaps);
 
-    void initConfigSwizzleTable(const GrGLContextInfo& ctxInfo, GrGLSLCaps* glslCaps);
-
-
     SkTArray<StencilFormat, true> fStencilFormats;
 
     int fMaxFragmentUniformVectors;
@@ -376,6 +382,7 @@
     bool fPartialFBOReadIsSlow : 1;
     bool fBindUniformLocationSupport : 1;
     bool fExternalTextureSupport : 1;
+    bool fTextureSwizzleSupport : 1;
 
     /** Number type of the components (with out considering number of bits.) */
     enum FormatType {
@@ -418,6 +425,8 @@
             kRenderableWithMSAA_Flag      = 0x8,
         };
         uint32_t fFlags;
+
+        GrSwizzle fSwizzle;
     };
 
     ConfigInfo fConfigTable[kGrPixelConfigCnt];
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 49b8f3a..e0b7d4a 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2485,11 +2485,11 @@
 /** If texture swizzling is available using tex parameters then it is preferred over mangling
   the generated shader code. This potentially allows greater reuse of cached shaders. */
 static void get_tex_param_swizzle(GrPixelConfig config,
-                                  const GrGLSLCaps& caps,
+                                  const GrGLCaps& caps,
                                   GrGLenum* glSwizzle) {
-    const char* swizzle = caps.getSwizzleMap(config);
+    const GrSwizzle& swizzle = caps.configSwizzle(config);
     for (int i = 0; i < 4; ++i) {
-        glSwizzle[i] = get_component_enum_from_char(swizzle[i]);
+        glSwizzle[i] = get_component_enum_from_char(swizzle.c_str()[i]);
     }
 }
 
@@ -2558,7 +2558,7 @@
 
     newTexParams.fWrapS = tile_to_gl_wrap(params.getTileModeX());
     newTexParams.fWrapT = tile_to_gl_wrap(params.getTileModeY());
-    get_tex_param_swizzle(texture->config(), *this->glCaps().glslCaps(), newTexParams.fSwizzleRGBA);
+    get_tex_param_swizzle(texture->config(), this->glCaps(), newTexParams.fSwizzleRGBA);
     if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
         this->setTextureUnit(unitIdx);
         GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter));
@@ -2575,7 +2575,7 @@
         this->setTextureUnit(unitIdx);
         GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT));
     }
-    if (!this->glCaps().glslCaps()->mustSwizzleInShader() &&
+    if (this->glCaps().textureSwizzleSupport() &&
         (setAll || memcmp(newTexParams.fSwizzleRGBA,
                           oldTexParams.fSwizzleRGBA,
                           sizeof(newTexParams.fSwizzleRGBA)))) {
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 81f92eb..0325625 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -13,36 +13,23 @@
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 
-/**
- * Do we need to either map r,g,b->a or a->r. configComponentMask indicates which channels are
- * present in the texture's config. swizzleComponentMask indicates the channels present in the
- * shader swizzle.
- */
-static bool swizzle_requires_alpha_remapping(const GrGLSLCaps& caps, GrPixelConfig config) {
-    if (!caps.mustSwizzleInShader()) {
-        // Any remapping is handled using texture swizzling not shader modifications.
-        return false;
-    }
-    const char* swizzleMap = caps.getSwizzleMap(config);
-    
-    return SkToBool(memcmp(swizzleMap, "rgba", 4));
-}
 
-static uint32_t gen_texture_key(const GrProcessor& proc, const GrGLCaps& caps) {
-    uint32_t key = 0;
+static void add_texture_key(GrProcessorKeyBuilder* b, const GrProcessor& proc,
+                            const GrGLSLCaps& caps) {
     int numTextures = proc.numTextures();
-    int shift = 0;
-    for (int t = 0; t < numTextures; ++t) {
-        const GrTextureAccess& access = proc.textureAccess(t);
-        if (swizzle_requires_alpha_remapping(*caps.glslCaps(), access.getTexture()->config())) {
-            key |= 1 << shift;
-        }
-        if (GR_GL_TEXTURE_EXTERNAL == static_cast<GrGLTexture*>(access.getTexture())->target()) {
-            key |= 2 << shift;
-        }
-        shift += 2;
+    // Need two bytes per key (swizzle and target).
+    int word32Count = (proc.numTextures() + 1) / 2;
+    if (0 == word32Count) {
+        return;
     }
-    return key;
+    uint16_t* k16 = SkTCast<uint16_t*>(b->add32n(word32Count));
+    for (int i = 0; i < numTextures; ++i) {
+        const GrTextureAccess& access = proc.textureAccess(i);
+        bool isExternal = (GR_GL_TEXTURE_EXTERNAL ==
+                           static_cast<GrGLTexture*>(access.getTexture())->target());
+        k16[i] = caps.configTextureSwizzle(access.getTexture()->config()).asKey() |
+                 (isExternal ? 0xFF00 : 0x0000);
+    }
 }
 
 /**
@@ -51,15 +38,14 @@
  * in its key (e.g. the pixel format of textures used). So we create a meta-key for
  * every effect using this function. It is also responsible for inserting the effect's class ID
  * which must be different for every GrProcessor subclass. It can fail if an effect uses too many
- * textures, transforms, etc, for the space allotted in the meta-key.  NOTE, both FPs and GPs share
- * this function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
+ * transforms, etc, for the space allotted in the meta-key.  NOTE, both FPs and GPs share this
+ * function because it is hairy, though FPs do not have attribs, and GPs do not have transforms
  */
 static bool gen_meta_key(const GrProcessor& proc,
                          const GrGLCaps& caps,
                          uint32_t transformKey,
                          GrProcessorKeyBuilder* b) {
     size_t processorKeySize = b->size();
-    uint32_t textureKey = gen_texture_key(proc, caps);
     uint32_t classID = proc.classID();
 
     // Currently we allow 16 bits for the class id and the overall processor key size.
@@ -68,10 +54,11 @@
         return false;
     }
 
-    uint32_t* key = b->add32n(3);
+    add_texture_key(b, proc, *caps.glslCaps());
+
+    uint32_t* key = b->add32n(2);
     key[0] = (classID << 16) | SkToU32(processorKeySize);
-    key[1] = textureKey;
-    key[2] = transformKey;
+    key[1] = transformKey;
     return true;
 }
 
diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp
index cf41f8e..c82d833 100755
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -31,9 +31,6 @@
     fFBFetchColorName = nullptr;
     fFBFetchExtensionString = nullptr;
     fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction;
-
-    fMustSwizzleInShader = false;
-    memset(fConfigSwizzle, 0, sizeof(fConfigSwizzle));
 }
 
 SkString GrGLSLCaps::dump() const {
@@ -67,8 +64,5 @@
 }
 
 void GrGLSLCaps::onApplyOptionsOverrides(const GrContextOptions& options) {
-    if (options.fUseShaderSwizzling) {
-        fMustSwizzleInShader = true;
-    }
 }
 
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index 21c59e7..eba9602 100755
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -11,6 +11,7 @@
 
 #include "GrCaps.h"
 #include "GrGLSL.h"
+#include "GrSwizzle.h"
 
 class GrGLSLCaps : public GrShaderCaps {
 public:
@@ -104,14 +105,14 @@
         return fExternalTextureExtensionString;
     }
 
-    bool mustSwizzleInShader() const { return fMustSwizzleInShader; }
-
     /**
-     * Returns a string which represents how to map from an internal GLFormat to a given
-     * GrPixelConfig. The function mustSwizzleInShader determines whether this swizzle is applied
-     * in the generated shader code or using sample state in the 3D API.
+     * Given a texture's config, this determines what swizzle must be appended to accesses to the
+     * texture in generated shader code. Swizzling may be implemented in texture parameters or a
+     * sampler rather than in the shader. In this case the shader swizzle will always be "rgba".
      */
-    const char* getSwizzleMap(GrPixelConfig config) const { return fConfigSwizzle[config]; }
+    const GrSwizzle& configTextureSwizzle(GrPixelConfig config) const {
+        return fConfigTextureSwizzle[config];
+    }
 
     GrGLSLGeneration generation() const { return fGLSLGeneration; }
 
@@ -148,13 +149,11 @@
 
     AdvBlendEqInteraction fAdvBlendEqInteraction;
 
-    bool        fMustSwizzleInShader;
-    const char* fConfigSwizzle[kGrPixelConfigCnt];
+    GrSwizzle fConfigTextureSwizzle[kGrPixelConfigCnt];
 
     friend class GrGLCaps;  // For initialization.
 
     typedef GrShaderCaps INHERITED;
 };
 
-
 #endif
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
index 5716c0b..2d2ff87 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
@@ -5,70 +5,13 @@
  * found in the LICENSE file.
  */
 
+#include "GrSwizzle.h"
 #include "glsl/GrGLSLShaderBuilder.h"
 #include "glsl/GrGLSLCaps.h"
 #include "glsl/GrGLSLShaderVar.h"
 #include "glsl/GrGLSLTextureSampler.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 
-static void map_swizzle(const char* swizzleMap, const char* swizzle, char* mangledSwizzle) {
-    int i;
-    for (i = 0; '\0' != swizzle[i]; ++i) {
-        switch (swizzle[i]) {
-            case 'r':
-                mangledSwizzle[i] = swizzleMap[0];
-                break;
-            case 'g':
-                mangledSwizzle[i] = swizzleMap[1];
-                break;
-            case 'b':
-                mangledSwizzle[i] = swizzleMap[2];
-                break;
-            case 'a':
-                mangledSwizzle[i] = swizzleMap[3];
-                break;
-            default:
-                SkFAIL("Unsupported swizzle");
-        }
-    }
-    mangledSwizzle[i] ='\0';
-}
-
-static void append_texture_lookup(SkString* out,
-                                  const GrGLSLCaps* glslCaps,
-                                  const char* samplerName,
-                                  const char* coordName,
-                                  GrPixelConfig config,
-                                  const char* swizzle,
-                                  GrSLType varyingType = kVec2f_GrSLType) {
-    SkASSERT(coordName);
-
-    out->appendf("%s(%s, %s)",
-                 GrGLSLTexture2DFunctionName(varyingType, glslCaps->generation()),
-                 samplerName,
-                 coordName);
-
-    char mangledSwizzle[5];
-
-    // This refers to any swizzling we may need to get from some backend internal format to the
-    // format used in GrPixelConfig. Some backends will automatically do the sizzling for us.
-    if (glslCaps->mustSwizzleInShader()) {
-        const char* swizzleMap = glslCaps->getSwizzleMap(config);
-        // if the map is simply 'rgba' then we don't need to do any manual swizzling to get us to
-        // a GrPixelConfig format.
-        if (memcmp(swizzleMap, "rgba", 4)) {
-            // Manually 'swizzle' the swizzle using our mapping
-            map_swizzle(swizzleMap, swizzle, mangledSwizzle);
-            swizzle = mangledSwizzle;
-        }
-    }
-
-    // For shader prettiness we omit the swizzle rather than appending ".rgba".
-    if (memcmp(swizzle, "rgba", 4)) {
-        out->appendf(".%s", swizzle);
-    }
-}
-
 GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program)
     : fProgramBuilder(program)
     , fInputs(GrGLSLProgramBuilder::kVarsPerBlock)
@@ -117,14 +60,21 @@
                                               const GrGLSLTextureSampler& sampler,
                                               const char* coordName,
                                               GrSLType varyingType) const {
+    const GrGLSLCaps* glslCaps = fProgramBuilder->glslCaps();
     GrGLSLUniformHandler* uniformHandler = fProgramBuilder->uniformHandler();
-    append_texture_lookup(out,
-                          fProgramBuilder->glslCaps(),
-                          uniformHandler->getUniformCStr(sampler.fSamplerUniform),
-                          coordName,
-                          sampler.config(),
-                          sampler.swizzle(),
-                          varyingType);
+    out->appendf("%s(%s, %s)",
+                 GrGLSLTexture2DFunctionName(varyingType, glslCaps->generation()),
+                 uniformHandler->getUniformCStr(sampler.fSamplerUniform),
+                 coordName);
+
+    // This refers to any swizzling we may need to get from some backend internal format to the
+    // format used in GrPixelConfig. If this is implemented by the GrGpu object, then swizzle will
+    // be rgba. For shader prettiness we omit the swizzle rather than appending ".rgba".
+    const GrSwizzle& configSwizzle = glslCaps->configTextureSwizzle(sampler.config());
+
+    if (configSwizzle != GrSwizzle::RGBA()) {
+        out->appendf(".%s", configSwizzle.c_str());
+    }
 }
 
 void GrGLSLShaderBuilder::appendTextureLookup(const GrGLSLTextureSampler& sampler,
diff --git a/src/gpu/glsl/GrGLSLTextureSampler.h b/src/gpu/glsl/GrGLSLTextureSampler.h
index a4fbf55..fd8bcb2 100644
--- a/src/gpu/glsl/GrGLSLTextureSampler.h
+++ b/src/gpu/glsl/GrGLSLTextureSampler.h
@@ -21,17 +21,13 @@
         : fSamplerUniform(uniform)
         , fConfig(access.getTexture()->config()) {
         SkASSERT(kUnknown_GrPixelConfig != fConfig);
-        memcpy(fSwizzle, access.getSwizzle(), 5);
     }
 
     GrPixelConfig config() const { return fConfig; }
-    // this is .abcd
-    const char* swizzle() const { return fSwizzle; }
 
 private:
     UniformHandle fSamplerUniform;
     GrPixelConfig fConfig;
-    char          fSwizzle[5];
 
     friend class GrGLSLShaderBuilder;
 };