Add integer texture support.

This allows us to create integer textures and sample them from a GrProcessor's code.

Filtering is limited to NEAREST.

Adds tests for reading/writing pixels, copying, and drawing. These operations are not allowed to convert to fixed/float configs.

Vulkan support is TBD.


GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=4348

Change-Id: If38d89a03285d4bd98d1f14f9638b0320977e43d
Reviewed-on: https://skia-review.googlesource.com/4348
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index 0f77b5a..a41be0e 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -241,22 +241,23 @@
               map_flags_to_string(fMapBufferFlags).c_str());
 
     static const char* kConfigNames[] = {
-        "Unknown",  // kUnknown_GrPixelConfig
-        "Alpha8",   // kAlpha_8_GrPixelConfig,
-        "Index8",   // kIndex_8_GrPixelConfig,
-        "RGB565",   // kRGB_565_GrPixelConfig,
-        "RGBA444",  // kRGBA_4444_GrPixelConfig,
-        "RGBA8888", // kRGBA_8888_GrPixelConfig,
-        "BGRA8888", // kBGRA_8888_GrPixelConfig,
-        "SRGBA8888",// kSRGBA_8888_GrPixelConfig,
-        "SBGRA8888",// kSBGRA_8888_GrPixelConfig,
-        "ETC1",     // kETC1_GrPixelConfig,
-        "LATC",     // kLATC_GrPixelConfig,
-        "R11EAC",   // kR11_EAC_GrPixelConfig,
-        "ASTC12x12",// kASTC_12x12_GrPixelConfig,
-        "RGBAFloat",// kRGBA_float_GrPixelConfig
-        "AlphaHalf",// kAlpha_half_GrPixelConfig
-        "RGBAHalf", // kRGBA_half_GrPixelConfig
+        "Unknown",       // kUnknown_GrPixelConfig
+        "Alpha8",        // kAlpha_8_GrPixelConfig,
+        "Index8",        // kIndex_8_GrPixelConfig,
+        "RGB565",        // kRGB_565_GrPixelConfig,
+        "RGBA444",       // kRGBA_4444_GrPixelConfig,
+        "RGBA8888",      // kRGBA_8888_GrPixelConfig,
+        "BGRA8888",      // kBGRA_8888_GrPixelConfig,
+        "SRGBA8888",     // kSRGBA_8888_GrPixelConfig,
+        "SBGRA8888",     // kSBGRA_8888_GrPixelConfig,
+        "RGBA8888_sint", // kRGBA_8888_sint_GrPixelConfig,
+        "ETC1",          // kETC1_GrPixelConfig,
+        "LATC",          // kLATC_GrPixelConfig,
+        "R11EAC",        // kR11_EAC_GrPixelConfig,
+        "ASTC12x12",     // kASTC_12x12_GrPixelConfig,
+        "RGBAFloat",     // kRGBA_float_GrPixelConfig
+        "AlphaHalf",     // kAlpha_half_GrPixelConfig
+        "RGBAHalf",      // kRGBA_half_GrPixelConfig
     };
     GR_STATIC_ASSERT(0  == kUnknown_GrPixelConfig);
     GR_STATIC_ASSERT(1  == kAlpha_8_GrPixelConfig);
@@ -267,13 +268,14 @@
     GR_STATIC_ASSERT(6  == kBGRA_8888_GrPixelConfig);
     GR_STATIC_ASSERT(7  == kSRGBA_8888_GrPixelConfig);
     GR_STATIC_ASSERT(8  == kSBGRA_8888_GrPixelConfig);
-    GR_STATIC_ASSERT(9  == kETC1_GrPixelConfig);
-    GR_STATIC_ASSERT(10  == kLATC_GrPixelConfig);
-    GR_STATIC_ASSERT(11  == kR11_EAC_GrPixelConfig);
-    GR_STATIC_ASSERT(12 == kASTC_12x12_GrPixelConfig);
-    GR_STATIC_ASSERT(13 == kRGBA_float_GrPixelConfig);
-    GR_STATIC_ASSERT(14 == kAlpha_half_GrPixelConfig);
-    GR_STATIC_ASSERT(15 == kRGBA_half_GrPixelConfig);
+    GR_STATIC_ASSERT(9  == kRGBA_8888_sint_GrPixelConfig);
+    GR_STATIC_ASSERT(10 == kETC1_GrPixelConfig);
+    GR_STATIC_ASSERT(11 == kLATC_GrPixelConfig);
+    GR_STATIC_ASSERT(12 == kR11_EAC_GrPixelConfig);
+    GR_STATIC_ASSERT(13 == kASTC_12x12_GrPixelConfig);
+    GR_STATIC_ASSERT(14 == kRGBA_float_GrPixelConfig);
+    GR_STATIC_ASSERT(15 == kAlpha_half_GrPixelConfig);
+    GR_STATIC_ASSERT(16 == kRGBA_half_GrPixelConfig);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kConfigNames) == kGrPixelConfigCnt);
 
     SkASSERT(!this->isConfigRenderable(kUnknown_GrPixelConfig, false));
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index ff8de9d..71203d6 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -266,11 +266,15 @@
 
     bool applyPremulToSrc = false;
     if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
-        if (!GrPixelConfigIs8888(srcConfig)) {
+        if (!GrPixelConfigIs8888Unorm(srcConfig)) {
             return false;
         }
         applyPremulToSrc = true;
     }
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(srcConfig)) {
+        return false;
+    }
 
     GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
     // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
@@ -411,10 +415,14 @@
     }
 
     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
-    if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
+    if (unpremul && !GrPixelConfigIs8888Unorm(dstConfig)) {
         // The unpremul flag is only allowed for 8888 configs.
         return false;
     }
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(src->config()) != GrPixelConfigIsSint(dstConfig)) {
+        return false;
+    }
 
     GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
     // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
@@ -540,6 +548,11 @@
     ASSERT_OWNED_RESOURCE(src);
     ASSERT_OWNED_RESOURCE(dst);
 
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) {
+        return false;
+    }
+
     if (!dst->asRenderTarget()) {
         SkIRect clippedSrcRect;
         SkIPoint clippedDstPoint;
@@ -683,6 +696,7 @@
         kRGBA_8888_GrPixelConfig,      // kBGRA_8888_GrPixelConfig
         kUnknown_GrPixelConfig,        // kSRGBA_8888_GrPixelConfig
         kSRGBA_8888_GrPixelConfig,     // kSBGRA_8888_GrPixelConfig
+        kUnknown_GrPixelConfig,        // kRGBA_8888_sint_GrPixelConfig
         kUnknown_GrPixelConfig,        // kETC1_GrPixelConfig
         kUnknown_GrPixelConfig,        // kLATC_GrPixelConfig
         kUnknown_GrPixelConfig,        // kR11_EAC_GrPixelConfig
@@ -702,13 +716,14 @@
     GR_STATIC_ASSERT(6  == kBGRA_8888_GrPixelConfig);
     GR_STATIC_ASSERT(7  == kSRGBA_8888_GrPixelConfig);
     GR_STATIC_ASSERT(8  == kSBGRA_8888_GrPixelConfig);
-    GR_STATIC_ASSERT(9  == kETC1_GrPixelConfig);
-    GR_STATIC_ASSERT(10  == kLATC_GrPixelConfig);
-    GR_STATIC_ASSERT(11  == kR11_EAC_GrPixelConfig);
-    GR_STATIC_ASSERT(12 == kASTC_12x12_GrPixelConfig);
-    GR_STATIC_ASSERT(13 == kRGBA_float_GrPixelConfig);
-    GR_STATIC_ASSERT(14 == kAlpha_half_GrPixelConfig);
-    GR_STATIC_ASSERT(15 == kRGBA_half_GrPixelConfig);
+    GR_STATIC_ASSERT(9  == kRGBA_8888_sint_GrPixelConfig);
+    GR_STATIC_ASSERT(10 == kETC1_GrPixelConfig);
+    GR_STATIC_ASSERT(11 == kLATC_GrPixelConfig);
+    GR_STATIC_ASSERT(12 == kR11_EAC_GrPixelConfig);
+    GR_STATIC_ASSERT(13 == kASTC_12x12_GrPixelConfig);
+    GR_STATIC_ASSERT(14 == kRGBA_float_GrPixelConfig);
+    GR_STATIC_ASSERT(15 == kAlpha_half_GrPixelConfig);
+    GR_STATIC_ASSERT(16 == kRGBA_half_GrPixelConfig);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kFallback) == kGrPixelConfigCnt);
 }
 
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 1b9be53..b775cf0 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -104,6 +104,10 @@
         return false;
     }
 
+    if (GrPixelConfigIsSint(desc.fConfig) && texels.count() > 1) {
+        return false;
+    }
+
     *isRT = SkToBool(desc.fFlags & kRenderTarget_GrSurfaceFlag);
     if (*isRT && !caps.isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
         return false;
@@ -262,6 +266,13 @@
                         const SkIPoint& dstPoint) {
     SkASSERT(dst && src);
     this->handleDirtyContext();
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) {
+        return false;
+    }
+    if (GrPixelConfigIsCompressed(dst->config())) {
+        return false;
+    }
     return this->onCopySurface(dst, src, srcRect, dstPoint);
 }
 
@@ -270,8 +281,14 @@
                               ReadPixelTempDrawInfo* tempDrawInfo) {
     SkASSERT(drawPreference);
     SkASSERT(tempDrawInfo);
+    SkASSERT(srcSurface);
     SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
 
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(srcSurface->config()) != GrPixelConfigIsSint(readConfig)) {
+        return false;
+    }
+
     // We currently do not support reading into a compressed buffer
     if (GrPixelConfigIsCompressed(readConfig)) {
         return false;
@@ -305,6 +322,7 @@
                                WritePixelTempDrawInfo* tempDrawInfo) {
     SkASSERT(drawPreference);
     SkASSERT(tempDrawInfo);
+    SkASSERT(dstSurface);
     SkASSERT(kGpuPrefersDraw_DrawPreference != *drawPreference);
 
     if (GrPixelConfigIsCompressed(dstSurface->desc().fConfig) &&
@@ -312,6 +330,11 @@
         return false;
     }
 
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(dstSurface->config()) != GrPixelConfigIsSint(srcConfig)) {
+        return false;
+    }
+
     if (SkToBool(dstSurface->asRenderTarget())) {
         if (this->caps()->useDrawInsteadOfAllRenderTargetWrites()) {
             ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
@@ -343,7 +366,12 @@
                        int left, int top, int width, int height,
                        GrPixelConfig config, void* buffer,
                        size_t rowBytes) {
-    this->handleDirtyContext();
+    SkASSERT(surface);
+
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
+        return false;
+    }
 
     // We cannot read pixels into a compressed buffer
     if (GrPixelConfigIsCompressed(config)) {
@@ -358,6 +386,8 @@
         return false;
     }
 
+    this->handleDirtyContext();
+
     return this->onReadPixels(surface,
                               left, top, width, height,
                               config, buffer,
@@ -367,15 +397,18 @@
 bool GrGpu::writePixels(GrSurface* surface,
                         int left, int top, int width, int height,
                         GrPixelConfig config, const SkTArray<GrMipLevel>& texels) {
-    if (!surface) {
-        return false;
-    }
+    SkASSERT(surface);
     for (int currentMipLevel = 0; currentMipLevel < texels.count(); currentMipLevel++) {
         if (!texels[currentMipLevel].fPixels ) {
             return false;
         }
     }
 
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
+        return false;
+    }
+
     this->handleDirtyContext();
     if (this->onWritePixels(surface, left, top, width, height, config, texels)) {
         SkIRect rect = SkIRect::MakeXYWH(left, top, width, height);
@@ -406,6 +439,11 @@
     SkASSERT(transferBuffer);
     SkASSERT(fence);
 
+    // We don't allow conversion between integer configs and float/fixed configs.
+    if (GrPixelConfigIsSint(surface->config()) != GrPixelConfigIsSint(config)) {
+        return false;
+    }
+
     this->handleDirtyContext();
     if (this->onTransferPixels(surface, left, top, width, height, config,
                                transferBuffer, offset, rowBytes)) {
diff --git a/src/gpu/GrTextureProvider.cpp b/src/gpu/GrTextureProvider.cpp
index dba24b5..b49c2c9 100644
--- a/src/gpu/GrTextureProvider.cpp
+++ b/src/gpu/GrTextureProvider.cpp
@@ -48,7 +48,9 @@
             return nullptr;
         }
     }
-
+    if (mipLevelCount > 1 && GrPixelConfigIsSint(desc.fConfig)) {
+        return nullptr;
+    }
     if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
         !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
         return nullptr;
@@ -84,10 +86,10 @@
     GrMipLevel* texels = nullptr;
     int levelCount = 0;
     if (srcData) {
-      tempTexels.fPixels = srcData;
-      tempTexels.fRowBytes = rowBytes;
-      texels = &tempTexels;
-      levelCount = 1;
+        tempTexels.fPixels = srcData;
+        tempTexels.fRowBytes = rowBytes;
+        texels = &tempTexels;
+        levelCount = 1;
     }
     return this->createMipMappedTexture(desc, budgeted, texels, levelCount);
 }
diff --git a/src/gpu/batches/GrCopySurfaceBatch.cpp b/src/gpu/batches/GrCopySurfaceBatch.cpp
index a59ed38..7246098 100644
--- a/src/gpu/batches/GrCopySurfaceBatch.cpp
+++ b/src/gpu/batches/GrCopySurfaceBatch.cpp
@@ -63,7 +63,12 @@
                                     const SkIPoint& dstPoint) {
     SkASSERT(dst);
     SkASSERT(src);
-
+    if (GrPixelConfigIsSint(dst->config()) != GrPixelConfigIsSint(src->config())) {
+        return nullptr;
+    }
+    if (GrPixelConfigIsCompressed(dst->config())) {
+        return nullptr;
+    }
     SkIRect clippedSrcRect;
     SkIPoint clippedDstPoint;
     // If the rect is outside the src or dst then we've already succeeded.
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index a37d0e0..ed3c381 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -863,6 +863,10 @@
         return false;
     }
 
+    if (GrPixelConfigIsSint(surfaceConfig) != GrPixelConfigIsSint(readConfig)) {
+        return false;
+    }
+
     GrGLenum readFormat;
     GrGLenum readType;
     if (!this->getReadPixelsFormat(surfaceConfig, readConfig, &readFormat, &readType)) {
@@ -874,8 +878,11 @@
         // the manual (https://www.opengl.org/sdk/docs/man/) says only these formats are allowed:
         // GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL, GL_RED, GL_GREEN, GL_BLUE,
         // GL_RGB, GL_BGR, GL_RGBA, and GL_BGRA. We check for the subset that we would use.
+        // The manual does not seem to fully match the spec as the spec allows integer formats
+        // when the bound color buffer is an integer buffer. It doesn't specify which integer
+        // formats are allowed, so perhaps all of them are. We only use GL_RGBA_INTEGER currently.
         if (readFormat != GR_GL_RED && readFormat != GR_GL_RGB && readFormat != GR_GL_RGBA &&
-            readFormat != GR_GL_BGRA) {
+            readFormat != GR_GL_BGRA && readFormat != GR_GL_RGBA_INTEGER) {
             return false;
         }
         // There is also a set of allowed types, but all the types we use are in the set:
@@ -890,16 +897,22 @@
     }
 
     // See Section 16.1.2 in the ES 3.2 specification.
-
-    if (kNormalizedFixedPoint_FormatType == fConfigTable[surfaceConfig].fFormatType) {
-        if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) {
-            return true;
-        }
-    } else {
-        SkASSERT(kFloat_FormatType == fConfigTable[surfaceConfig].fFormatType);
-        if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) {
-            return true;
-        }
+    switch (fConfigTable[surfaceConfig].fFormatType) {
+        case kNormalizedFixedPoint_FormatType:
+            if (GR_GL_RGBA == readFormat && GR_GL_UNSIGNED_BYTE == readType) {
+                return true;
+            }
+            break;
+        case kInteger_FormatType:
+            if (GR_GL_RGBA_INTEGER == readFormat && GR_GL_INT == readType) {
+                return true;
+            }
+            break;
+        case kFloat_FormatType:
+            if (GR_GL_RGBA == readFormat && GR_GL_FLOAT == readType) {
+                return true;
+            }
+            break;
     }
 
     if (0 == fConfigTable[surfaceConfig].fSecondReadPixelsFormat.fFormat) {
@@ -1569,6 +1582,33 @@
     }
     fConfigTable[kSBGRA_8888_GrPixelConfig].fSwizzle = GrSwizzle::RGBA();
 
+    bool hasIntegerTextures;
+    if (standard == kGL_GrGLStandard) {
+        hasIntegerTextures = version >= GR_GL_VER(3, 0) ||
+                             ctxInfo.hasExtension("GL_EXT_texture_integer");
+    } else {
+        hasIntegerTextures = (version >= GR_GL_VER(3, 0));
+    }
+    // We may have limited GLSL to an earlier version that doesn't have integer sampler types.
+    if (ctxInfo.glslGeneration() == k110_GrGLSLGeneration) {
+        hasIntegerTextures = false;
+    }
+    fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fBaseInternalFormat  = GR_GL_RGBA_INTEGER;
+    fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGBA8I;
+    fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fExternalFormat[kOther_ExternalFormatUsage] = GR_GL_RGBA_INTEGER;
+    fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormats.fExternalType = GR_GL_BYTE;
+    fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFormatType = kInteger_FormatType;
+    // We currently only support using integer textures as srcs, not for rendering (even though GL
+    // allows it).
+    if (hasIntegerTextures) {
+        fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFlags = ConfigInfo::kTextureable_Flag |
+                                                             ConfigInfo::kFBOColorAttachment_Flag;
+        if (texStorageSupported) {
+            fConfigTable[kRGBA_8888_sint_GrPixelConfig].fFlags |=
+                ConfigInfo::kCanUseTexStorage_Flag;
+        }
+    }
+
     fConfigTable[kRGB_565_GrPixelConfig].fFormats.fBaseInternalFormat = GR_GL_RGB;
     if (this->ES2CompatibilitySupport()) {
         fConfigTable[kRGB_565_GrPixelConfig].fFormats.fSizedInternalFormat = GR_GL_RGB565;
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index c277323..496635d 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -425,6 +425,7 @@
     enum FormatType {
         kNormalizedFixedPoint_FormatType,
         kFloat_FormatType,
+        kInteger_FormatType,
     };
 
     struct ReadPixelsFormat {
diff --git a/src/gpu/gl/GrGLDefines.h b/src/gpu/gl/GrGLDefines.h
index 8dc7af1..8f739cc 100644
--- a/src/gpu/gl/GrGLDefines.h
+++ b/src/gpu/gl/GrGLDefines.h
@@ -408,24 +408,112 @@
 #define GR_GL_LINE_WIDTH_GRANULARITY         0x0B23
 #define GR_GL_LINE_WIDTH_RANGE               0x0B22
 
-/* PixelFormat */
+/* Unsized formats */
+#define GR_GL_STENCIL_INDEX                  0x1901
 #define GR_GL_DEPTH_COMPONENT                0x1902
+#define GR_GL_DEPTH_STENCIL                  0x84F9
 #define GR_GL_RED                            0x1903
+#define GR_GL_RED_INTEGER                    0x8D94
 #define GR_GL_GREEN                          0x1904
 #define GR_GL_BLUE                           0x1905
 #define GR_GL_ALPHA                          0x1906
-#define GR_GL_RGB                            0x1907
-#define GR_GL_RGBA                           0x1908
-#define GR_GL_BGRA                           0x80E1
 #define GR_GL_LUMINANCE                      0x1909
 #define GR_GL_LUMINANCE_ALPHA                0x190A
-#define GR_GL_PALETTE8_RGBA8                 0x8B96
-#define GR_GL_ALPHA8                         0x803C
+#define GR_GL_RG_INTEGER                     0x8228
+#define GR_GL_RGB                            0x1907
+#define GR_GL_RGB_INTEGER                    0x8D98
+#define GR_GL_SRGB                           0x8C40
+#define GR_GL_RGBA                           0x1908
+#define GR_GL_SRGB_ALPHA                     0x8C42
+#define GR_GL_RGBA_INTEGER                   0x8D99
+#define GR_GL_BGRA                           0x80E1
 
+/* Stencil index sized formats */
+#define GR_GL_STENCIL_INDEX4                 0x8D47
+#define GR_GL_STENCIL_INDEX8                 0x8D48
+#define GR_GL_STENCIL_INDEX16                0x8D49
+
+/* Depth component sized formats */
+#define GR_GL_DEPTH_COMPONENT16              0x81A5
+
+/* Depth stencil sized formats */
+#define GR_GL_DEPTH24_STENCIL8               0x88F0
+
+/* Red sized formats */
 #define GR_GL_R8                             0x8229
+#define GR_GL_R16                            0x822A
 #define GR_GL_R16F                           0x822D
-#define GR_GL_RGBA16F                        0x881A
+#define GR_GL_R32F                           0x822E
+
+/* Red integer sized formats */
+#define GR_GL_R8I                            0x8231
+#define GR_GL_R8UI                           0x8232
+#define GR_GL_R16I                           0x8233
+#define GR_GL_R16UI                          0x8234
+#define GR_GL_R32I                           0x8235
+#define GR_GL_R32UI                          0x8236
+
+/* Alpha sized formats */
+#define GR_GL_ALPHA8                         0x803C
+#define GR_GL_ALPHA16                        0x803E
 #define GR_GL_ALPHA16F                       0x881C
+#define GR_GL_ALPHA32F                       0x8816
+
+/* Alpha integer sized formats */
+#define GR_GL_ALPHA8I                        0x8D90
+#define GR_GL_ALPHA8UI                       0x8D7E
+#define GR_GL_ALPHA16I                       0x8D8A
+#define GR_GL_ALPHA16UI                      0x8D78
+#define GR_GL_ALPHA32I                       0x8D84
+#define GR_GL_ALPHA32UI                      0x8D72
+
+/* RG sized formats */
+#define GR_GL_RG8                            0x822B
+#define GR_GL_RG16                           0x822C
+#define GR_GL_R16F                           0x822D
+#define GR_GL_R32F                           0x822E
+
+/* RG sized integer formats */
+#define GR_GL_RG8I                           0x8237
+#define GR_GL_RG8UI                          0x8238
+#define GR_GL_RG16I                          0x8239
+#define GR_GL_RG16UI                         0x823A
+#define GR_GL_RG32I                          0x823B
+#define GR_GL_RG32UI                         0x823C
+
+/* RGB sized formats */
+#define GR_GL_RGB5                           0x8050
+#define GR_GL_RGB565                         0x8D62
+#define GR_GL_RGB8                           0x8051
+#define GR_GL_SRGB8                          0x8C41
+
+/* RGB integer sized formats */
+#define GR_GL_RGB8I                          0x8D8F
+#define GR_GL_RGB8UI                         0x8D7D
+#define GR_GL_RGB16I                         0x8D89
+#define GR_GL_RGB16UI                        0x8D77
+#define GR_GL_RGB32I                         0x8D83
+#define GR_GL_RGB32UI                        0x8D71
+
+/* RGBA sized formats */
+#define GR_GL_RGBA4                          0x8056
+#define GR_GL_RGB5_A1                        0x8057
+#define GR_GL_PALETTE8_RGBA8                 0x8B96
+#define GR_GL_RGBA8                          0x8058
+#define GR_GL_SRGB8_ALPHA8                   0x8C43
+#define GR_GL_RGBA16F                        0x881A
+#define GR_GL_RGBA32F                        0x8814
+
+/* RGBA integer sized formats */
+#define GR_GL_RGBA8I                         0x8D8E
+#define GR_GL_RGBA8UI                        0x8D7C
+#define GR_GL_RGBA16I                        0x8D88
+#define GR_GL_RGBA16UI                       0x8D76
+#define GR_GL_RGBA32I                        0x8D82
+#define GR_GL_RGBA32UI                       0x8D70
+
+/* BGRA sized formats */
+#define GR_GL_BGRA8                          0x93A1
 
 /* PixelType */
 /*      GL_UNSIGNED_BYTE */
@@ -782,26 +870,6 @@
 
 #define GR_GL_RENDERBUFFER                   0x8D41
 
-#define GR_GL_RGBA4                          0x8056
-#define GR_GL_RGB5_A1                        0x8057
-#define GR_GL_RGB565                         0x8D62
-#define GR_GL_RGBA8                          0x8058
-#define GR_GL_RGBA32F                        0x8814
-#define GR_GL_RGB5                           0x8050
-#define GR_GL_RGB8                           0x8051
-#define GR_GL_BGRA8                          0x93A1
-#define GR_GL_SRGB                           0x8C40
-#define GR_GL_SRGB8                          0x8C41
-#define GR_GL_SRGB_ALPHA                     0x8C42
-#define GR_GL_SRGB8_ALPHA8                   0x8C43
-#define GR_GL_DEPTH_COMPONENT16              0x81A5
-#define GR_GL_STENCIL_INDEX                  0x1901
-#define GR_GL_STENCIL_INDEX4                 0x8D47
-#define GR_GL_STENCIL_INDEX8                 0x8D48
-#define GR_GL_STENCIL_INDEX16                0x8D49
-#define GR_GL_DEPTH_STENCIL                  0x84F9
-#define GR_GL_DEPTH24_STENCIL8               0x88F0
-
 #define GR_GL_MAX_SAMPLES                    0x8D57
 // GL_IMG_multisampled_render_to_texture uses a different value for GL_MAX_SAMPLES
 #define GR_GL_MAX_SAMPLES_IMG                0x9135
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 9ccd073..63f0c28 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -922,6 +922,7 @@
         case kBGRA_8888_GrPixelConfig:
         case kSRGBA_8888_GrPixelConfig:
         case kSBGRA_8888_GrPixelConfig:
+        case kRGBA_8888_sint_GrPixelConfig:
         case kRGBA_float_GrPixelConfig:
             return 4;
         default:
@@ -971,14 +972,14 @@
     // This means if we may later want to add mipmaps, we cannot use TexStorage.
     // Right now, we cannot know if we will later add mipmaps or not.
     // The only time we can use TexStorage is when we already have the
-    // mipmaps.
-    useTexStorage &= texels.count() > 1;
+    // mipmaps or are using a format incompatible with MIP maps.
+    useTexStorage &= texels.count() > 1 || GrPixelConfigIsSint(desc.fConfig);
 
     if (useTexStorage) {
         // We never resize or change formats of textures.
         GL_ALLOC_CALL(&interface,
                       TexStorage2D(target,
-                                   texels.count(),
+                                   SkTMax(texels.count(), 1),
                                    internalFormatForTexStorage,
                                    desc.fWidth, desc.fHeight));
         GrGLenum error = check_alloc_error(desc, &interface);
@@ -3488,6 +3489,9 @@
         !gpu->glCaps().canConfigBeFBOColorAttachment(src->config())) {
         return false;
     }
+    // Blits are not allowed between int color buffers and float/fixed color buffers. GrGpu should
+    // have filtered such cases out.
+    SkASSERT(GrPixelConfigIsSint(dst->config()) == GrPixelConfigIsSint(src->config()));
     const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
     const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(dst->asTexture());
     const GrRenderTarget* dstRT = dst->asRenderTarget();
@@ -3723,19 +3727,10 @@
     return false;
 }
 
-bool GrGLGpu::createCopyProgram(int progIdx) {
+bool GrGLGpu::createCopyProgram(GrTexture* srcTex) {
+    int progIdx = TextureToCopyProgramIdx(srcTex);
     const GrGLSLCaps* glslCaps = this->glCaps().glslCaps();
-    static const GrSLType kSamplerTypes[3] = { kTexture2DSampler_GrSLType,
-                                               kTextureExternalSampler_GrSLType,
-                                               kTexture2DRectSampler_GrSLType };
-    if (kTextureExternalSampler_GrSLType == kSamplerTypes[progIdx] &&
-        !this->glCaps().glslCaps()->externalTextureSupport()) {
-        return false;
-    }
-    if (kTexture2DRectSampler_GrSLType == kSamplerTypes[progIdx] &&
-        !this->glCaps().rectangleTextureSupport()) {
-        return false;
-    }
+    GrSLType samplerType = srcTex->texturePriv().samplerType();
 
     if (!fCopyProgramArrayBuffer) {
         static const GrGLfloat vdata[] = {
@@ -3763,7 +3758,7 @@
                                  GrShaderVar::kUniform_TypeModifier);
     GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType,
                               GrShaderVar::kUniform_TypeModifier);
-    GrGLSLShaderVar uTexture("u_texture", kSamplerTypes[progIdx],
+    GrGLSLShaderVar uTexture("u_texture", samplerType,
                              GrShaderVar::kUniform_TypeModifier);
     GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType,
                               GrShaderVar::kVaryingOut_TypeModifier);
@@ -3802,7 +3797,7 @@
             fshaderTxt.appendf("#extension %s : require\n", extension);
         }
     }
-    if (kSamplerTypes[progIdx] == kTextureExternalSampler_GrSLType) {
+    if (samplerType == kTextureExternalSampler_GrSLType) {
         fshaderTxt.appendf("#extension %s : require\n",
                            glslCaps->externalTextureExtensionString());
     }
@@ -3818,7 +3813,7 @@
         "void main() {"
         "  sk_FragColor = %s(u_texture, v_texCoord);"
         "}",
-        GrGLSLTexture2DFunctionName(kVec2f_GrSLType, kSamplerTypes[progIdx], this->glslGeneration())
+        GrGLSLTexture2DFunctionName(kVec2f_GrSLType, samplerType, this->glslGeneration())
     );
 
     const char* str;
@@ -4170,10 +4165,10 @@
                                 const SkIRect& srcRect,
                                 const SkIPoint& dstPoint) {
     GrGLTexture* srcTex = static_cast<GrGLTexture*>(src->asTexture());
-    int progIdx = TextureTargetToCopyProgramIdx(srcTex->target());
+    int progIdx = TextureToCopyProgramIdx(srcTex);
 
     if (!fCopyPrograms[progIdx].fProgram) {
-        if (!this->createCopyProgram(progIdx)) {
+        if (!this->createCopyProgram(srcTex)) {
             SkDebugf("Failed to create copy program.\n");
             return false;
         }
@@ -4359,6 +4354,7 @@
 // Uses draw calls to do a series of downsample operations to successive mips.
 // If this returns false, then the calling code falls back to using glGenerateMipmap.
 bool GrGLGpu::generateMipmap(GrGLTexture* texture, bool gammaCorrect) {
+    SkASSERT(!GrPixelConfigIsSint(texture->config()));
     // Our iterative downsample requires the ability to limit which level we're sampling:
     if (!this->glCaps().doManualMipmapping()) {
         return false;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 32ce979..0c9d373 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -17,7 +17,7 @@
 #include "GrGLTexture.h"
 #include "GrGLVertexArray.h"
 #include "GrGpu.h"
-#include "GrTypes.h"
+#include "GrTexturePriv.h"
 #include "GrWindowRectsState.h"
 #include "GrXferProcessor.h"
 #include "SkTArray.h"
@@ -395,7 +395,7 @@
 
     sk_sp<GrGLContext>          fGLContext;
 
-    bool createCopyProgram(int progIdx);
+    bool createCopyProgram(GrTexture* srcTexture);
     bool createMipmapProgram(int progIdx);
     bool createWireRectProgram();
     bool createPLSSetupProgram();
@@ -589,13 +589,13 @@
     int                         fHWNumRasterSamples;
     ///@}
 
-    /** IDs for copy surface program. */
+    /** IDs for copy surface program. (4 sampler types) */
     struct {
         GrGLuint    fProgram;
         GrGLint     fTextureUniform;
         GrGLint     fTexCoordXformUniform;
         GrGLint     fPosXformUniform;
-    }                           fCopyPrograms[3];
+    }                           fCopyPrograms[4];
     sk_sp<GrGLBuffer>           fCopyProgramArrayBuffer;
 
     /** IDs for texture mipmap program. (4 filter configurations) */
@@ -613,16 +613,18 @@
     }                           fWireRectProgram;
     sk_sp<GrGLBuffer>           fWireRectArrayBuffer;
 
-    static int TextureTargetToCopyProgramIdx(GrGLenum target) {
-        switch (target) {
-            case GR_GL_TEXTURE_2D:
+    static int TextureToCopyProgramIdx(GrTexture* texture) {
+        switch (texture->texturePriv().samplerType()) {
+            case kTexture2DSampler_GrSLType:
                 return 0;
-            case GR_GL_TEXTURE_EXTERNAL:
+            case kTexture2DISampler_GrSLType:
                 return 1;
-            case GR_GL_TEXTURE_RECTANGLE:
+            case kTexture2DRectSampler_GrSLType:
                 return 2;
+            case kTextureExternalSampler_GrSLType:
+                return 3;
             default:
-                SkFAIL("Unexpected texture target type.");
+                SkFAIL("Unexpected samper type");
                 return 0;
         }
     }
diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp
index c45d08f..9f213fb 100644
--- a/src/gpu/gl/GrGLTexture.cpp
+++ b/src/gpu/gl/GrGLTexture.cpp
@@ -12,20 +12,31 @@
 #define GPUGL static_cast<GrGLGpu*>(this->getGpu())
 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
 
-static inline GrSLType sampler_type(const GrGLTexture::IDDesc& idDesc, const GrGLGpu* gpu) {
+static inline GrSLType sampler_type(const GrGLTexture::IDDesc& idDesc, GrPixelConfig config,
+                                    const GrGLGpu* gpu) {
     if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
         SkASSERT(gpu->glCaps().glslCaps()->externalTextureSupport());
+        SkASSERT(!GrPixelConfigIsSint(config));
         return kTextureExternalSampler_GrSLType;
     } else if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE) {
         SkASSERT(gpu->glCaps().rectangleTextureSupport());
+        SkASSERT(!GrPixelConfigIsSint(config));
         return kTexture2DRectSampler_GrSLType;
+    } else if (GrPixelConfigIsSint(config)) {
+        return kTexture2DISampler_GrSLType;
     } else {
         SkASSERT(idDesc.fInfo.fTarget == GR_GL_TEXTURE_2D);
         return kTexture2DSampler_GrSLType;
     }
 }
 
-static inline GrTextureParams::FilterMode highest_filter_mode(const GrGLTexture::IDDesc& idDesc) {
+static inline GrTextureParams::FilterMode highest_filter_mode(const GrGLTexture::IDDesc& idDesc,
+                                                              GrPixelConfig config) {
+    if (GrPixelConfigIsSint(config)) {
+        // Integer textures in GL can use GL_NEAREST_MIPMAP_NEAREST. This is a mode we don't support
+        // and don't currently have a use for.
+        return GrTextureParams::kNone_FilterMode;
+    }
     if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE ||
         idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
         return GrTextureParams::kBilerp_FilterMode;
@@ -37,7 +48,8 @@
 GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
                          const IDDesc& idDesc)
     : GrSurface(gpu, desc)
-    , INHERITED(gpu, desc, sampler_type(idDesc, gpu), highest_filter_mode(idDesc), false) {
+    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
+                highest_filter_mode(idDesc, desc.fConfig), false) {
     this->init(desc, idDesc);
     this->registerWithCache(budgeted);
 }
@@ -46,7 +58,8 @@
                          const IDDesc& idDesc,
                          bool wasMipMapDataProvided)
     : GrSurface(gpu, desc)
-    , INHERITED(gpu, desc, sampler_type(idDesc, gpu), highest_filter_mode(idDesc),
+    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
+                highest_filter_mode(idDesc, desc.fConfig),
                 wasMipMapDataProvided) {
     this->init(desc, idDesc);
     this->registerWithCache(budgeted);
@@ -54,7 +67,8 @@
 
 GrGLTexture::GrGLTexture(GrGLGpu* gpu, Wrapped, const GrSurfaceDesc& desc, const IDDesc& idDesc)
     : GrSurface(gpu, desc)
-    , INHERITED(gpu, desc, sampler_type(idDesc, gpu), highest_filter_mode(idDesc), false) {
+    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
+                highest_filter_mode(idDesc, desc.fConfig), false) {
     this->init(desc, idDesc);
     this->registerWithCacheWrapped();
 }
@@ -62,7 +76,8 @@
 GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc,
                          bool wasMipMapDataProvided)
     : GrSurface(gpu, desc)
-    , INHERITED(gpu, desc, sampler_type(idDesc, gpu), highest_filter_mode(idDesc),
+    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
+                highest_filter_mode(idDesc, desc.fConfig),
                 wasMipMapDataProvided) {
     this->init(desc, idDesc);
 }
diff --git a/src/gpu/glsl/GrGLSL.h b/src/gpu/glsl/GrGLSL.h
index e4e165b..e6559fd 100644
--- a/src/gpu/glsl/GrGLSL.h
+++ b/src/gpu/glsl/GrGLSL.h
@@ -124,6 +124,8 @@
             return "mat4";
         case kTexture2DSampler_GrSLType:
             return "sampler2D";
+        case kTexture2DISampler_GrSLType:
+            return "isampler2D";
         case kTextureExternalSampler_GrSLType:
             return "samplerExternalOES";
         case kTexture2DRectSampler_GrSLType:
@@ -140,10 +142,9 @@
             return "texture2D";
         case kSampler_GrSLType:
             return "sampler";
-        default:
-            SkFAIL("Unknown shader var type.");
-            return ""; // suppress warning
     }
+    SkFAIL("Unknown shader var type.");
+    return ""; // suppress warning
 }
 
 /** A generic base-class representing a GLSL expression.
diff --git a/src/gpu/glsl/GrGLSLCaps.cpp b/src/gpu/glsl/GrGLSLCaps.cpp
index b33e308..8e464b0 100644
--- a/src/gpu/glsl/GrGLSLCaps.cpp
+++ b/src/gpu/glsl/GrGLSLCaps.cpp
@@ -129,24 +129,25 @@
         }
 
         uint8_t* table = fSamplerPrecisions[visibility];
-        table[kUnknown_GrPixelConfig]    = kDefault_GrSLPrecision;
-        table[kAlpha_8_GrPixelConfig]    = lowp;
-        table[kIndex_8_GrPixelConfig]    = lowp;
-        table[kRGB_565_GrPixelConfig]    = lowp;
-        table[kRGBA_4444_GrPixelConfig]  = lowp;
-        table[kRGBA_8888_GrPixelConfig]  = lowp;
-        table[kBGRA_8888_GrPixelConfig]  = lowp;
-        table[kSRGBA_8888_GrPixelConfig] = lowp;
-        table[kSBGRA_8888_GrPixelConfig] = lowp;
-        table[kETC1_GrPixelConfig]       = lowp;
-        table[kLATC_GrPixelConfig]       = lowp;
-        table[kR11_EAC_GrPixelConfig]    = lowp;
-        table[kASTC_12x12_GrPixelConfig] = lowp;
-        table[kRGBA_float_GrPixelConfig] = kHigh_GrSLPrecision;
-        table[kAlpha_half_GrPixelConfig] = mediump;
-        table[kRGBA_half_GrPixelConfig]  = mediump;
+        table[kUnknown_GrPixelConfig]        = kDefault_GrSLPrecision;
+        table[kAlpha_8_GrPixelConfig]        = lowp;
+        table[kIndex_8_GrPixelConfig]        = lowp;
+        table[kRGB_565_GrPixelConfig]        = lowp;
+        table[kRGBA_4444_GrPixelConfig]      = lowp;
+        table[kRGBA_8888_GrPixelConfig]      = lowp;
+        table[kBGRA_8888_GrPixelConfig]      = lowp;
+        table[kSRGBA_8888_GrPixelConfig]     = lowp;
+        table[kSBGRA_8888_GrPixelConfig]     = lowp;
+        table[kRGBA_8888_sint_GrPixelConfig] = lowp;
+        table[kETC1_GrPixelConfig]           = lowp;
+        table[kLATC_GrPixelConfig]           = lowp;
+        table[kR11_EAC_GrPixelConfig]        = lowp;
+        table[kASTC_12x12_GrPixelConfig]     = lowp;
+        table[kRGBA_float_GrPixelConfig]     = kHigh_GrSLPrecision;
+        table[kAlpha_half_GrPixelConfig]     = mediump;
+        table[kRGBA_half_GrPixelConfig]      = mediump;
 
-        GR_STATIC_ASSERT(16 == kGrPixelConfigCnt);
+        GR_STATIC_ASSERT(17 == kGrPixelConfigCnt);
     }
 }
 
diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h
index ac409a3..618afa5 100644
--- a/src/gpu/glsl/GrGLSLCaps.h
+++ b/src/gpu/glsl/GrGLSLCaps.h
@@ -15,8 +15,6 @@
 
 class GrGLSLCaps : public GrShaderCaps {
 public:
-
-
     /**
     * Indicates how GLSL must interact with advanced blend equations. The KHR extension requires
     * special layout qualifiers in the fragment shader.
diff --git a/src/gpu/vk/GrVkUniformHandler.cpp b/src/gpu/vk/GrVkUniformHandler.cpp
index 4a6e977..7c11b9d 100644
--- a/src/gpu/vk/GrVkUniformHandler.cpp
+++ b/src/gpu/vk/GrVkUniformHandler.cpp
@@ -25,10 +25,11 @@
         0x7, // kMat22f_GrSLType
         0xF, // kMat33f_GrSLType
         0xF, // kMat44f_GrSLType
-        0x0, // Sampler2D_GrSLType, should never return this
-        0x0, // SamplerExternal_GrSLType, should never return this
-        0x0, // Sampler2DRect_GrSLType, should never return this
-        0x0, // SamplerBuffer_GrSLType, should never return this
+        0x0, // kTexture2DSampler_GrSLType, should never return this
+        0x0, // kTexture2DISampler_GrSLType, should never return this
+        0x0, // kTextureExternalSampler_GrSLType, should never return this
+        0x0, // kTexture2DSamplerRect_GrSLType, should never return this
+        0x0, // ktextureBufferSampler_GrSLType, should never return this
         0x0, // kBool_GrSLType
         0x7, // kInt_GrSLType
         0x7, // kUint_GrSLType
@@ -44,14 +45,15 @@
     GR_STATIC_ASSERT(6 == kMat33f_GrSLType);
     GR_STATIC_ASSERT(7 == kMat44f_GrSLType);
     GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType);
-    GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType);
-    GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType);
-    GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType);
-    GR_STATIC_ASSERT(12 == kBool_GrSLType);
-    GR_STATIC_ASSERT(13 == kInt_GrSLType);
-    GR_STATIC_ASSERT(14 == kUint_GrSLType);
-    GR_STATIC_ASSERT(15 == kTexture2D_GrSLType);
-    GR_STATIC_ASSERT(16 == kSampler_GrSLType);
+    GR_STATIC_ASSERT(9 == kTexture2DISampler_GrSLType);
+    GR_STATIC_ASSERT(10 == kTextureExternalSampler_GrSLType);
+    GR_STATIC_ASSERT(11 == kTexture2DRectSampler_GrSLType);
+    GR_STATIC_ASSERT(12 == kTextureBufferSampler_GrSLType);
+    GR_STATIC_ASSERT(13 == kBool_GrSLType);
+    GR_STATIC_ASSERT(14 == kInt_GrSLType);
+    GR_STATIC_ASSERT(15 == kUint_GrSLType);
+    GR_STATIC_ASSERT(16 == kTexture2D_GrSLType);
+    GR_STATIC_ASSERT(17 == kSampler_GrSLType);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kAlignmentMask) == kGrSLTypeCount);
     return kAlignmentMask[type];
 }
@@ -71,6 +73,7 @@
         12 * sizeof(float),       // kMat33f_GrSLType
         16 * sizeof(float),       // kMat44f_GrSLType
         0,                        // kTexture2DSampler_GrSLType
+        0,                        // kTexture2DISampler_GrSLType
         0,                        // kTextureExternalSampler_GrSLType
         0,                        // kTexture2DRectSampler_GrSLType
         0,                        // kTextureBufferSampler_GrSLType
@@ -91,14 +94,15 @@
     GR_STATIC_ASSERT(6 == kMat33f_GrSLType);
     GR_STATIC_ASSERT(7 == kMat44f_GrSLType);
     GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType);
-    GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType);
-    GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType);
-    GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType);
-    GR_STATIC_ASSERT(12 == kBool_GrSLType);
-    GR_STATIC_ASSERT(13 == kInt_GrSLType);
-    GR_STATIC_ASSERT(14 == kUint_GrSLType);
-    GR_STATIC_ASSERT(15 == kTexture2D_GrSLType);
-    GR_STATIC_ASSERT(16 == kSampler_GrSLType);
+    GR_STATIC_ASSERT(9 == kTexture2DISampler_GrSLType);
+    GR_STATIC_ASSERT(10 == kTextureExternalSampler_GrSLType);
+    GR_STATIC_ASSERT(11 == kTexture2DRectSampler_GrSLType);
+    GR_STATIC_ASSERT(12 == kTextureBufferSampler_GrSLType);
+    GR_STATIC_ASSERT(13 == kBool_GrSLType);
+    GR_STATIC_ASSERT(14 == kInt_GrSLType);
+    GR_STATIC_ASSERT(15 == kUint_GrSLType);
+    GR_STATIC_ASSERT(16 == kTexture2D_GrSLType);
+    GR_STATIC_ASSERT(17 == kSampler_GrSLType);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kSizes) == kGrSLTypeCount);
 }
 
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index a14f827..1d93e8d 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -19,58 +19,62 @@
     }
 
     switch (config) {
+        case kUnknown_GrPixelConfig:
+            return false;
         case kRGBA_8888_GrPixelConfig:
             *format = VK_FORMAT_R8G8B8A8_UNORM;
-            break;
+            return true;
         case kBGRA_8888_GrPixelConfig:
             *format = VK_FORMAT_B8G8R8A8_UNORM;
-            break;
+            return true;
         case kSRGBA_8888_GrPixelConfig:
             *format = VK_FORMAT_R8G8B8A8_SRGB;
-            break;
+            return true;
         case kSBGRA_8888_GrPixelConfig:
             *format = VK_FORMAT_B8G8R8A8_SRGB;
-            break;
+            return true;
+        case kRGBA_8888_sint_GrPixelConfig:
+            *format = VK_FORMAT_R8G8B8A8_SINT;
+            return true;
         case kRGB_565_GrPixelConfig:
             *format = VK_FORMAT_R5G6B5_UNORM_PACK16;
-            break;
+            return true;
         case kRGBA_4444_GrPixelConfig:
             // R4G4B4A4 is not required to be supported so we actually
             // store the data is if it was B4G4R4A4 and swizzle in shaders
             *format = VK_FORMAT_B4G4R4A4_UNORM_PACK16;
-            break;
+            return true;
         case kIndex_8_GrPixelConfig:
             // No current vulkan support for this config
             return false;
         case kAlpha_8_GrPixelConfig:
             *format = VK_FORMAT_R8_UNORM;
-            break;
+            return true;
         case kETC1_GrPixelConfig:
             // converting to ETC2 which is a superset of ETC1
             *format = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
-            break;
+            return true;
         case kLATC_GrPixelConfig:
             // No current vulkan support for this config
             return false;
         case kR11_EAC_GrPixelConfig:
             *format = VK_FORMAT_EAC_R11_UNORM_BLOCK;
-            break;
+            return true;
         case kASTC_12x12_GrPixelConfig:
             *format = VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
-            break;
+            return true;
         case kRGBA_float_GrPixelConfig:
             *format = VK_FORMAT_R32G32B32A32_SFLOAT;
-            break;
+            return true;
         case kRGBA_half_GrPixelConfig:
             *format = VK_FORMAT_R16G16B16A16_SFLOAT;
-            break;
+            return true;
         case kAlpha_half_GrPixelConfig:
             *format = VK_FORMAT_R16_SFLOAT;
-            break;
-        default:
-            return false;
+            return true;
     }
-    return true;
+    SkFAIL("Unexpected config");
+    return false;
 }
 
 bool GrVkFormatToPixelConfig(VkFormat format, GrPixelConfig* config) {
@@ -92,6 +96,9 @@
         case VK_FORMAT_B8G8R8A8_SRGB:
             *config = kSBGRA_8888_GrPixelConfig;
             break;
+        case VK_FORMAT_R8G8B8A8_SINT:
+            *config = kRGBA_8888_sint_GrPixelConfig;
+            break;
         case VK_FORMAT_R5G6B5_UNORM_PACK16:
             *config = kRGB_565_GrPixelConfig;
             break;
diff --git a/src/gpu/vk/GrVkVaryingHandler.cpp b/src/gpu/vk/GrVkVaryingHandler.cpp
index f6fed21..10c5362 100644
--- a/src/gpu/vk/GrVkVaryingHandler.cpp
+++ b/src/gpu/vk/GrVkVaryingHandler.cpp
@@ -20,6 +20,7 @@
         3,  // kMat33f_GrSLType
         4,  // kMat44f_GrSLType
         0,  // kTexture2DSampler_GrSLType
+        0,  // kTexture2DISampler_GrSLType
         0,  // kTextureExternalSampler_GrSLType
         0,  // kTexture2DRectSampler_GrSLType
         0,  // kTextureBufferSampler_GrSLType
@@ -40,14 +41,15 @@
     GR_STATIC_ASSERT(6 == kMat33f_GrSLType);
     GR_STATIC_ASSERT(7 == kMat44f_GrSLType);
     GR_STATIC_ASSERT(8 == kTexture2DSampler_GrSLType);
-    GR_STATIC_ASSERT(9 == kTextureExternalSampler_GrSLType);
-    GR_STATIC_ASSERT(10 == kTexture2DRectSampler_GrSLType);
-    GR_STATIC_ASSERT(11 == kTextureBufferSampler_GrSLType);
-    GR_STATIC_ASSERT(12 == kBool_GrSLType);
-    GR_STATIC_ASSERT(13 == kInt_GrSLType);
-    GR_STATIC_ASSERT(14 == kUint_GrSLType);
-    GR_STATIC_ASSERT(15 == kTexture2D_GrSLType);
-    GR_STATIC_ASSERT(16 == kSampler_GrSLType);
+    GR_STATIC_ASSERT(9 == kTexture2DISampler_GrSLType);
+    GR_STATIC_ASSERT(10 == kTextureExternalSampler_GrSLType);
+    GR_STATIC_ASSERT(11 == kTexture2DRectSampler_GrSLType);
+    GR_STATIC_ASSERT(12 == kTextureBufferSampler_GrSLType);
+    GR_STATIC_ASSERT(13 == kBool_GrSLType);
+    GR_STATIC_ASSERT(14 == kInt_GrSLType);
+    GR_STATIC_ASSERT(15 == kUint_GrSLType);
+    GR_STATIC_ASSERT(16 == kTexture2D_GrSLType);
+    GR_STATIC_ASSERT(17 == kSampler_GrSLType);
     GR_STATIC_ASSERT(SK_ARRAY_COUNT(kSizes) == kGrSLTypeCount);
 }
 
diff --git a/src/sksl/SkSLCompiler.cpp b/src/sksl/SkSLCompiler.cpp
index c3adaea..72ea9c4 100644
--- a/src/sksl/SkSLCompiler.cpp
+++ b/src/sksl/SkSLCompiler.cpp
@@ -111,6 +111,8 @@
     ADD_TYPE(Sampler2DMS);
     ADD_TYPE(Sampler2DMSArray);
 
+    ADD_TYPE(ISampler2D);
+
     ADD_TYPE(GSampler1D);
     ADD_TYPE(GSampler2D);
     ADD_TYPE(GSampler3D);
diff --git a/src/sksl/SkSLContext.h b/src/sksl/SkSLContext.h
index dc41c6d..80ad7fb 100644
--- a/src/sksl/SkSLContext.h
+++ b/src/sksl/SkSLContext.h
@@ -78,6 +78,8 @@
     , fSampler1DArrayShadow_Type(new Type("sampler1DArrayShadow"))
     , fSampler2DArrayShadow_Type(new Type("sampler2DArrayShadow"))
     , fSamplerCubeArrayShadow_Type(new Type("samplerCubeArrayShadow"))
+    // Related to below FIXME, gsampler*s don't currently expand to cover integer case.
+    , fISampler2D_Type(new Type("isampler2D", SpvDim2D, false, false, false, true))
     // FIXME figure out what we're supposed to do with the gsampler et al. types)
     , fGSampler1D_Type(new Type("$gsampler1D", static_type(*fSampler1D_Type)))
     , fGSampler2D_Type(new Type("$gsampler2D", static_type(*fSampler2D_Type)))
@@ -193,6 +195,8 @@
     const std::unique_ptr<Type> fSampler2DArrayShadow_Type;
     const std::unique_ptr<Type> fSamplerCubeArrayShadow_Type;
 
+    const std::unique_ptr<Type> fISampler2D_Type;
+
     const std::unique_ptr<Type> fGSampler1D_Type;
     const std::unique_ptr<Type> fGSampler2D_Type;
     const std::unique_ptr<Type> fGSampler3D_Type;
diff --git a/src/sksl/sksl.include b/src/sksl/sksl.include
index f57e62a..6458a15 100644
--- a/src/sksl/sksl.include
+++ b/src/sksl/sksl.include
@@ -251,6 +251,9 @@
 $gvec4 texture($gsampler1D sampler, float P);
 $gvec4 texture($gsampler1D sampler, float P, float bias);
 $gvec4 texture($gsampler2D sampler, vec2 P);
+// The above currently only expand to handle the float/fixed case. So we also declare this integer
+// version of texture().
+ivec4 texture(isampler2D sampler, vec2 P);
 vec4 texture(samplerExternalOES sampler, vec2 P, float bias);
 vec4 texture(samplerExternalOES sampler, vec2 P);
 
@@ -483,6 +486,7 @@
 vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod);
 */
 vec4 texture2D(sampler2D sampler, vec2 coord);
+ivec4 texture2D(isampler2D sampler, vec2 coord);
 vec4 texture2D(samplerExternalOES sampler, vec2 coord);
 vec4 texture2D(sampler2D sampler, vec2 coord, float bias);
 vec4 texture2DProj(sampler2D sampler, vec3 coord);