Revert "Reland "Separate compressed and uncompressed texture functions""

This reverts commit c0519233cdd2545a938848336c7d470bfe27fa96.

Reason for revert: breaking google3 cause of abort in constexpr

Original change's description:
> Reland "Separate compressed and uncompressed texture functions"
> 
> This is a reland of 9acfb33ad8c6f5fc6097dff57c0de5e51ea590fd
> 
> Original change's description:
> > Separate compressed and uncompressed texture functions
> > 
> > Change-Id: Iccf31e1e4dbebde8aab4bb9b57cfb0341bb05912
> > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/223802
> > Reviewed-by: Greg Daniel <egdaniel@google.com>
> > Commit-Queue: Brian Salomon <bsalomon@google.com>
> 
> Change-Id: I9f212b7d34cf43216f7d2ec63b959b75fd6a71b3
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/223992
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

TBR=egdaniel@google.com,bsalomon@google.com,robertphillips@google.com

Change-Id: I9cee240b438a3682911a3c6cddadfe2062447b8c
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/223995
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h
index eba8ccd..c0c0561 100644
--- a/src/gpu/GrCaps.h
+++ b/src/gpu/GrCaps.h
@@ -367,8 +367,6 @@
                                                             GrSRGBEncoded srgbEncoded) const = 0;
     GrBackendFormat getBackendFormatFromColorType(SkColorType ct) const;
 
-    virtual GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const = 0;
-
     /**
      * The CLAMP_TO_BORDER wrap mode for texture coordinates was added to desktop GL in 1.3, and
      * GLES 3.2, but is also available in extensions. Vulkan and Metal always have support.
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index 9dcc25b..c83a3cf 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -113,14 +113,10 @@
     return w * h;
 }
 
-size_t GrCompressedDataSize(SkImage::CompressionType type, int width, int height) {
-    switch (type) {
-        case SkImage::kETC1_CompressionType:
-            int numBlocks = num_ETC1_blocks(width, height);
-            return numBlocks * sizeof(ETC1Block);
-    }
-    SK_ABORT("Unexpected compression type");
-    return 0;
+size_t GrETC1CompressedDataSize(int width, int height) {
+    int numBlocks = num_ETC1_blocks(width, height);
+
+    return numBlocks * sizeof(ETC1Block);
 }
 
 // Fill in 'dest' with ETC1 blocks derived from 'colorf'
@@ -304,14 +300,22 @@
     return true;
 }
 
-size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, int baseWidth, int baseHeight,
-                                        SkTArray<size_t>* individualMipOffsets, int mipLevelCount) {
+size_t GrComputeTightCombinedBufferSize(GrCompression compression, size_t bytesPerPixel,
+                                        int baseWidth, int baseHeight,
+                                        SkTArray<size_t>* individualMipOffsets,
+                                        int mipLevelCount) {
     SkASSERT(individualMipOffsets && !individualMipOffsets->count());
     SkASSERT(mipLevelCount >= 1);
 
     individualMipOffsets->push_back(0);
 
     size_t combinedBufferSize = baseWidth * bytesPerPixel * baseHeight;
+    if (GrCompression::kETC1 == compression) {
+        SkASSERT(0 == bytesPerPixel);
+        bytesPerPixel = 4; // munge Bpp to make the following code work (and not assert)
+        combinedBufferSize = GrETC1CompressedDataSize(baseWidth, baseHeight);
+    }
+
     int currentWidth = baseWidth;
     int currentHeight = baseHeight;
 
@@ -325,7 +329,12 @@
         currentWidth = SkTMax(1, currentWidth / 2);
         currentHeight = SkTMax(1, currentHeight / 2);
 
-        size_t trimmedSize = currentWidth * bytesPerPixel * currentHeight;
+        size_t trimmedSize;
+        if (GrCompression::kETC1 == compression) {
+            trimmedSize = GrETC1CompressedDataSize(currentWidth, currentHeight);
+        } else {
+            trimmedSize = currentWidth * bytesPerPixel * currentHeight;
+        }
         const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
         if (alignmentDiff != 0) {
             combinedBufferSize += desiredAlignment - alignmentDiff;
@@ -340,11 +349,12 @@
     return combinedBufferSize;
 }
 
-void GrFillInData(GrPixelConfig config, int baseWidth, int baseHeight,
+void GrFillInData(GrCompression compression, GrPixelConfig config,
+                  int baseWidth, int baseHeight,
                   const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
                   const SkColor4f& colorf) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-    SkASSERT(!GrPixelConfigIsCompressed(config));
+
     int mipLevels = individualMipOffsets.count();
 
     int currentWidth = baseWidth;
@@ -352,22 +362,19 @@
     for (int currentMipLevel = 0; currentMipLevel < mipLevels; ++currentMipLevel) {
         size_t offset = individualMipOffsets[currentMipLevel];
 
-        fill_buffer_with_color(config, currentWidth, currentHeight, colorf, &(dstPixels[offset]));
+        if (GrCompression::kETC1 == compression) {
+            // TODO: compute the ETC1 block for 'colorf' just once
+            fillin_ETC1_with_color(currentWidth, currentHeight, colorf, &(dstPixels[offset]));
+        } else {
+            fill_buffer_with_color(config, currentWidth, currentHeight, colorf,
+                                   &(dstPixels[offset]));
+        }
+
         currentWidth = SkTMax(1, currentWidth / 2);
         currentHeight = SkTMax(1, currentHeight / 2);
     }
 }
 
-void GrFillInCompressedData(SkImage::CompressionType type, int baseWidth, int baseHeight,
-                            char* dstPixels, const SkColor4f& colorf) {
-    TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-    int currentWidth = baseWidth;
-    int currentHeight = baseHeight;
-    if (SkImage::kETC1_CompressionType == type) {
-        fillin_ETC1_with_color(currentWidth, currentHeight, colorf, dstPixels);
-    }
-}
-
 static GrSwizzle get_load_and_get_swizzle(GrColorType ct, SkRasterPipeline::StockStage* load,
                                           bool* isNormalized) {
     GrSwizzle swizzle("rgba");
@@ -410,6 +417,7 @@
                                              break;
 
         case GrColorType::kUnknown:
+        case GrColorType::kRGB_ETC1:
             SK_ABORT("unexpected CT");
     }
     return swizzle;
@@ -457,6 +465,7 @@
 
         case GrColorType::kGray_8:  // not currently supported as output
         case GrColorType::kUnknown:
+        case GrColorType::kRGB_ETC1:
             SK_ABORT("unexpected CT");
     }
     return swizzle;
diff --git a/src/gpu/GrDataUtils.h b/src/gpu/GrDataUtils.h
index a55342f..fcf7a07 100644
--- a/src/gpu/GrDataUtils.h
+++ b/src/gpu/GrDataUtils.h
@@ -12,19 +12,27 @@
 #include "include/private/GrTypesPriv.h"
 #include "src/gpu/GrSwizzle.h"
 
-size_t GrCompressedDataSize(SkImage::CompressionType, int w, int h);
+// TODO: consolidate all the backend-specific flavors of this method to this
+size_t GrETC1CompressedDataSize(int w, int h);
+
+// TODO: should this be grown into a replacement for GrPixelConfig?
+enum class GrCompression {
+    kNone,
+    kETC1,
+};
 
 // Compute the size of the buffer required to hold all the mipLevels of the specified type
 // of data when all rowBytes are tight.
 // Note there may still be padding between the mipLevels to meet alignment requirements.
-size_t GrComputeTightCombinedBufferSize(size_t bytesPerPixel, int baseWidth, int baseHeight,
-                                        SkTArray<size_t>* individualMipOffsets, int mipLevelCount);
+size_t GrComputeTightCombinedBufferSize(GrCompression, size_t bytesPerPixel,
+                                        int baseWidth, int baseHeight,
+                                        SkTArray<size_t>* individualMipOffsets,
+                                        int mipLevelCount);
 
-void GrFillInData(GrPixelConfig, int baseWidth, int baseHeight,
-                  const SkTArray<size_t>& individualMipOffsets, char* dest, const SkColor4f& color);
-
-void GrFillInCompressedData(SkImage::CompressionType, int width, int height, char* dest,
-                            const SkColor4f& color);
+void GrFillInData(GrCompression, GrPixelConfig,
+                  int baseWidth, int baseHeight,
+                  const SkTArray<size_t>& individualMipOffsets,
+                  char* dest, const SkColor4f& color);
 
 struct GrColorInfo {
     GrColorType fColorType = GrColorType::kUnknown;
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 6c22e5c..52adb00 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -15,7 +15,6 @@
 #include "src/gpu/GrAuditTrail.h"
 #include "src/gpu/GrCaps.h"
 #include "src/gpu/GrContextPriv.h"
-#include "src/gpu/GrDataUtils.h"
 #include "src/gpu/GrGpuResourcePriv.h"
 #include "src/gpu/GrMesh.h"
 #include "src/gpu/GrPathRendering.h"
@@ -102,10 +101,6 @@
 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& origDesc, SkBudgeted budgeted,
                                       const GrMipLevel texels[], int mipLevelCount) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
-    if (GrPixelConfigIsCompressed(origDesc.fConfig)) {
-        // Call GrGpu::createCompressedTexture.
-        return nullptr;
-    }
     GrSurfaceDesc desc = origDesc;
 
     GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
@@ -124,6 +119,10 @@
         return nullptr;
     }
 
+    // We shouldn't be rendering into compressed textures
+    SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig) || !isRT);
+    SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig) || 1 == desc.fSampleCnt);
+
     this->handleDirtyContext();
     sk_sp<GrTexture> tex = this->onCreateTexture(desc, budgeted, texels, mipLevelCount);
     if (tex) {
@@ -144,27 +143,6 @@
     return this->createTexture(desc, budgeted, nullptr, 0);
 }
 
-sk_sp<GrTexture> GrGpu::createCompressedTexture(int width, int height,
-                                                SkImage::CompressionType compressionType,
-                                                SkBudgeted budgeted, const void* data,
-                                                size_t dataSize) {
-    this->handleDirtyContext();
-    if (width  < 1 || width  > this->caps()->maxTextureSize() ||
-        height < 1 || height > this->caps()->maxTextureSize()) {
-        return nullptr;
-    }
-    if (!data) {
-        return nullptr;
-    }
-    if (!this->caps()->isConfigTexturable(GrCompressionTypePixelConfig(compressionType))) {
-        return nullptr;
-    }
-    if (dataSize < GrCompressedDataSize(compressionType, width, height)) {
-        return nullptr;
-    }
-    return this->onCreateCompressedTexture(width, height, compressionType, budgeted, data);
-}
-
 sk_sp<GrTexture> GrGpu::wrapBackendTexture(const GrBackendTexture& backendTex,
                                            GrWrapOwnership ownership, GrWrapCacheable cacheable,
                                            GrIOType ioType) {
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index e52c476..3fb9862 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -103,9 +103,6 @@
      */
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, SkBudgeted);
 
-    sk_sp<GrTexture> createCompressedTexture(int width, int height, SkImage::CompressionType,
-                                             SkBudgeted, const void* data, size_t dataSize);
-
     /**
      * Implements GrResourceProvider::wrapBackendTexture
      */
@@ -495,9 +492,7 @@
     // onCreateTexture is called.
     virtual sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted,
                                              const GrMipLevel texels[], int mipLevelCount) = 0;
-    virtual sk_sp<GrTexture> onCreateCompressedTexture(int width, int height,
-                                                       SkImage::CompressionType, SkBudgeted,
-                                                       const void* data) = 0;
+
     virtual sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership,
                                                   GrWrapCacheable, GrIOType) = 0;
     virtual sk_sp<GrTexture> onWrapRenderableBackendTexture(const GrBackendTexture&, int sampleCnt,
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index cb2cefa..aa52c00 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -411,10 +411,6 @@
     if (kUnknown_GrPixelConfig == config) {
         return false;
     }
-    if (GrPixelConfigIsCompressed(config)) {
-        // We have no way to verify these at the moment.
-        return true;
-    }
     SkColorType colorType = GrColorTypeToSkColorType(GrPixelConfigToColorType(config));
     if (colorType == kUnknown_SkColorType) {
         // We should add support for validating GrColorType with a GrBackendFormat. Currently we
@@ -435,10 +431,6 @@
                                                    SkBudgeted budgeted,
                                                    GrInternalSurfaceFlags surfaceFlags) {
     SkASSERT(validate_backend_format_and_config(this->caps(), format, desc.fConfig));
-    if (GrPixelConfigIsCompressed(desc.fConfig)) {
-        // Deferred proxies for compressed textures are not supported.
-        return nullptr;
-    }
     if (GrMipMapped::kYes == mipMapped) {
         // SkMipMap doesn't include the base level in the level count so we have to add 1
         int mipCount = SkMipMap::ComputeLevelCount(desc.fWidth, desc.fHeight) + 1;
@@ -473,27 +465,25 @@
                                                     fit, budgeted, surfaceFlags));
 }
 
-sk_sp<GrTextureProxy> GrProxyProvider::createCompressedTextureProxy(
-        int width, int height, SkBudgeted budgeted, SkImage::CompressionType compressionType,
-        sk_sp<SkData> data) {
-    GrBackendFormat format = this->caps()->getBackendFormatFromCompressionType(compressionType);
-
-    GrSurfaceDesc desc;
-    desc.fConfig = GrCompressionTypePixelConfig(compressionType);
-    desc.fWidth = width;
-    desc.fHeight = height;
-
+sk_sp<GrTextureProxy> GrProxyProvider::createProxy(sk_sp<SkData> data, const GrSurfaceDesc& desc) {
     if (!this->caps()->isConfigTexturable(desc.fConfig)) {
         return nullptr;
     }
 
+    const GrColorType ct = GrPixelConfigToColorType(desc.fConfig);
+    const GrBackendFormat format =
+                            this->caps()->getBackendFormatFromGrColorType(ct, GrSRGBEncoded::kNo);
+
     sk_sp<GrTextureProxy> proxy = this->createLazyProxy(
-            [width, height, compressionType, budgeted, data](GrResourceProvider* resourceProvider) {
-                return LazyInstantiationResult(resourceProvider->createCompressedTexture(
-                        width, height, compressionType, budgeted, data.get()));
-            },
-            format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
-            SkBudgeted::kYes);
+        [desc, data](GrResourceProvider* resourceProvider) {
+            GrMipLevel texels;
+            texels.fPixels = data->data();
+            texels.fRowBytes = GrBytesPerPixel(desc.fConfig)*desc.fWidth;
+            return LazyInstantiationResult(
+                    resourceProvider->createTexture(desc, SkBudgeted::kYes, &texels, 1));
+        },
+        format, desc, kTopLeft_GrSurfaceOrigin, GrMipMapped::kNo, SkBackingFit::kExact,
+        SkBudgeted::kYes);
 
     if (!proxy) {
         return nullptr;
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h
index 435f973..bfa2243 100644
--- a/src/gpu/GrProxyProvider.h
+++ b/src/gpu/GrProxyProvider.h
@@ -96,11 +96,9 @@
     }
 
     /*
-     * Create a texture proxy from compressed texture data.
+     * Create a texture proxy with data. It's assumed that the data is packed tightly.
      */
-    sk_sp<GrTextureProxy> createCompressedTextureProxy(int width, int height, SkBudgeted budgeted,
-                                                       SkImage::CompressionType compressionType,
-                                                       sk_sp<SkData> data);
+    sk_sp<GrTextureProxy> createProxy(sk_sp<SkData>, const GrSurfaceDesc& desc);
 
     // These match the definitions in SkImage & GrTexture.h, for whence they came
     typedef void* ReleaseContext;
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 023f86d..ae847e8 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -118,17 +118,6 @@
     }
 }
 
-sk_sp<GrTexture> GrResourceProvider::createCompressedTexture(int width, int height,
-                                                             SkImage::CompressionType compression,
-                                                             SkBudgeted budgeted, SkData* data) {
-    ASSERT_SINGLE_OWNER
-    if (this->isAbandoned()) {
-        return nullptr;
-    }
-    return fGpu->createCompressedTexture(width, height, compression, budgeted, data->data(),
-                                         data->size());
-}
-
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                                    Flags flags) {
     ASSERT_SINGLE_OWNER
diff --git a/src/gpu/GrResourceProvider.h b/src/gpu/GrResourceProvider.h
index 00bf3d2..f382be8 100644
--- a/src/gpu/GrResourceProvider.h
+++ b/src/gpu/GrResourceProvider.h
@@ -88,11 +88,6 @@
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc&, SkBudgeted, SkBackingFit,
                                    const GrMipLevel&, Flags);
 
-    // Creates a compressed texture. The GrGpu must support the SkImageImage::Compression type.
-    // This does not currently support MIP maps.
-    sk_sp<GrTexture> createCompressedTexture(int width, int height, SkImage::CompressionType,
-                                             SkBudgeted, SkData* data);
-
     ///////////////////////////////////////////////////////////////////////////
     // Wrapped Backend Surfaces
 
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 1a62316..afc1124 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -72,6 +72,7 @@
         case GrColorType::kRGBA_F16_Clamped: return true;
         case GrColorType::kRG_F32:           return false;
         case GrColorType::kRGBA_F32:         return true;
+        case GrColorType::kRGB_ETC1:         return false;
         case GrColorType::kR_16:             return false;
         case GrColorType::kRG_1616:          return false;
         // Experimental (for Y416 and mutant P016/P010)
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index ecb3d3e..1a935b2 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -3333,16 +3333,6 @@
     return GrBackendFormat::MakeGL(this->configSizedInternalFormat(config), GR_GL_TEXTURE_2D);
 }
 
-GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
-        SkImage::CompressionType compressionType) const {
-    switch (compressionType) {
-        case SkImage::kETC1_CompressionType:
-            return GrBackendFormat::MakeGL(GR_GL_COMPRESSED_ETC1_RGB8, GR_GL_TEXTURE_2D);
-    }
-    SK_ABORT("Invalid compression type");
-    return {};
-}
-
 #ifdef SK_DEBUG
 static bool format_color_type_valid_pair(GrGLenum format, GrColorType colorType) {
     switch (colorType) {
@@ -3357,10 +3347,7 @@
         case GrColorType::kRGBA_8888:
             return GR_GL_RGBA8 == format || GR_GL_SRGB8_ALPHA8 == format;
         case GrColorType::kRGB_888x:
-            GR_STATIC_ASSERT(GrCompressionTypeClosestColorType(SkImage::kETC1_CompressionType) ==
-                             GrColorType::kRGB_888x);
-            return GR_GL_RGB8 == format || GR_GL_RGBA8 == format ||
-                   GR_GL_COMPRESSED_RGB8_ETC2 == format || GR_GL_COMPRESSED_ETC1_RGB8 == format;
+            return GR_GL_RGB8 == format || GR_GL_RGBA8 == format;
         case GrColorType::kRG_88:
             return GR_GL_RG8 == format;
         case GrColorType::kBGRA_8888:
@@ -3379,6 +3366,8 @@
             return GR_GL_RG32F == format;
         case GrColorType::kRGBA_F32:
             return GR_GL_RGBA32F == format;
+        case GrColorType::kRGB_ETC1:
+            return GR_GL_COMPRESSED_RGB8_ETC2 == format || GR_GL_COMPRESSED_ETC1_RGB8 == format;
         case GrColorType::kR_16:
             return GR_GL_R16 == format;
         case GrColorType::kRG_1616:
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index 633df54..d963ae9 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -422,7 +422,6 @@
 
     GrBackendFormat getBackendFormatFromGrColorType(GrColorType ct,
                                                     GrSRGBEncoded srgbEncoded) const override;
-    GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
 
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index f219f2b..84f28ad 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1086,6 +1086,108 @@
 }
 
 /**
+ * Creates storage space for the texture and fills it with texels.
+ *
+ * @param config         Compressed pixel config of the texture.
+ * @param interface      The GL interface in use.
+ * @param caps           The capabilities of the GL device.
+ * @param target         Which bound texture to target (GR_GL_TEXTURE_2D, e.g.)
+ * @param internalFormat The data format used for the internal storage of the texture.
+ * @param texels         The texel data of the texture being created.
+ * @param mipLevelCount  Number of mipmap levels
+ * @param baseWidth      The width of the texture's base mipmap level
+ * @param baseHeight     The height of the texture's base mipmap level
+ */
+static bool allocate_and_populate_compressed_texture(GrPixelConfig config,
+                                                     const GrGLInterface& interface,
+                                                     const GrGLCaps& caps,
+                                                     GrGLenum target, GrGLenum internalFormat,
+                                                     const GrMipLevel texels[], int mipLevelCount,
+                                                     int baseWidth, int baseHeight) {
+    CLEAR_ERROR_BEFORE_ALLOC(&interface);
+    SkASSERT(GrGLFormatIsCompressed(internalFormat));
+
+    bool useTexStorage = caps.isConfigTexSupportEnabled(config);
+    // We can only use TexStorage if we know we will not later change the storage requirements.
+    // 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 &= mipLevelCount > 1;
+
+    if (useTexStorage) {
+        // We never resize or change formats of textures.
+        GL_ALLOC_CALL(&interface,
+                      TexStorage2D(target,
+                                   mipLevelCount,
+                                   internalFormat,
+                                   baseWidth, baseHeight));
+        GrGLenum error = CHECK_ALLOC_ERROR(&interface);
+        if (error != GR_GL_NO_ERROR) {
+            return false;
+        } else {
+            for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+                const void* currentMipData = texels[currentMipLevel].fPixels;
+                if (currentMipData == nullptr) {
+                    // Compressed textures require data for every level
+                    return false;
+                }
+
+                int twoToTheMipLevel = 1 << currentMipLevel;
+                int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
+                int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
+
+                // Make sure that the width and height that we pass to OpenGL
+                // is a multiple of the block size.
+                size_t dataSize = GrGLFormatCompressedDataSize(internalFormat,
+                                                               currentWidth, currentHeight);
+                GR_GL_CALL(&interface, CompressedTexSubImage2D(target,
+                                                               currentMipLevel,
+                                                               0, // left
+                                                               0, // top
+                                                               currentWidth,
+                                                               currentHeight,
+                                                               internalFormat,
+                                                               SkToInt(dataSize),
+                                                               currentMipData));
+            }
+        }
+    } else {
+        for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+            const void* currentMipData = texels[currentMipLevel].fPixels;
+            if (currentMipData == nullptr) {
+                // Compressed textures require data for every level
+                return false;
+            }
+
+            int twoToTheMipLevel = 1 << currentMipLevel;
+            int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
+            int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
+
+            // Make sure that the width and height that we pass to OpenGL
+            // is a multiple of the block size.
+            size_t dataSize = GrGLFormatCompressedDataSize(internalFormat, baseWidth, baseHeight);
+
+            GL_ALLOC_CALL(&interface,
+                          CompressedTexImage2D(target,
+                                               currentMipLevel,
+                                               internalFormat,
+                                               currentWidth,
+                                               currentHeight,
+                                               0, // border
+                                               SkToInt(dataSize),
+                                               currentMipData));
+
+            GrGLenum error = CHECK_ALLOC_ERROR(&interface);
+            if (error != GR_GL_NO_ERROR) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+/**
  * After a texture is created, any state which was altered during its creation
  * needs to be restored.
  *
@@ -1299,58 +1401,32 @@
     return succeeded;
 }
 
-GrGLenum GrGLGpu::uploadCompressedTexData(SkImage::CompressionType compressionType, int width,
-                                          int height, GrGLenum target, const void* data) {
+bool GrGLGpu::uploadCompressedTexData(GrPixelConfig texConfig, int texWidth, int texHeight,
+                                      GrGLenum target,
+                                      const GrMipLevel texels[], int mipLevelCount,
+                                      GrMipMapsStatus* mipMapsStatus) {
+    SkASSERT(this->caps()->isConfigTexturable(texConfig));
+
+    const GrGLInterface* interface = this->glInterface();
     const GrGLCaps& caps = this->glCaps();
 
-    GrPixelConfig config = GrCompressionTypePixelConfig(compressionType);
     // We only need the internal format for compressed 2D textures.
     GrGLenum internalFormat;
-    if (!caps.getCompressedTexImageFormats(config, &internalFormat)) {
-        return 0;
+    if (!caps.getCompressedTexImageFormats(texConfig, &internalFormat)) {
+        return false;
     }
 
-    bool useTexStorage = caps.isConfigTexSupportEnabled(config);
-
-    static constexpr int kMipLevelCount = 1;
-
-    // Make sure that the width and height that we pass to OpenGL
-    // is a multiple of the block size.
-    size_t dataSize = GrCompressedDataSize(compressionType, width, height);
-
-    if (useTexStorage) {
-        // We never resize or change formats of textures.
-        GL_ALLOC_CALL(this->glInterface(),
-                      TexStorage2D(target, kMipLevelCount, internalFormat, width, height));
-        GrGLenum error = CHECK_ALLOC_ERROR(this->glInterface());
-        if (error != GR_GL_NO_ERROR) {
-            return 0;
-        }
-        GL_CALL(CompressedTexSubImage2D(target,
-                                        0,  // level
-                                        0,  // left
-                                        0,  // top
-                                        width,
-                                        height,
-                                        internalFormat,
-                                        SkToInt(dataSize),
-                                        data));
-    } else {
-        GL_ALLOC_CALL(this->glInterface(), CompressedTexImage2D(target,
-                                                                0,  // level
-                                                                internalFormat,
-                                                                width,
-                                                                height,
-                                                                0,  // border
-                                                                SkToInt(dataSize),
-                                                                data));
-
-        GrGLenum error = CHECK_ALLOC_ERROR(this->glInterface());
-        if (error != GR_GL_NO_ERROR) {
-            return 0;
+    if (mipMapsStatus) {
+        if (mipLevelCount <= 1) {
+            *mipMapsStatus = GrMipMapsStatus::kNotAllocated;
+        } else {
+            *mipMapsStatus = GrMipMapsStatus::kValid;
         }
     }
-    return internalFormat;
+
+    return allocate_and_populate_compressed_texture(texConfig, *interface, caps, target,
+                                                    internalFormat, texels, mipLevelCount,
+                                                    texWidth, texHeight);
 }
 
 static bool renderbuffer_storage_msaa(const GrGLContext& ctx,
@@ -1592,30 +1668,6 @@
     return std::move(tex);
 }
 
-sk_sp<GrTexture> GrGLGpu::onCreateCompressedTexture(int width, int height,
-                                                    SkImage::CompressionType compression,
-                                                    SkBudgeted budgeted, const void* data) {
-    GrGLTexture::IDDesc idDesc;
-    GrGLTextureParameters::SamplerOverriddenState initialState;
-    if (!this->createCompressedTextureImpl(&idDesc.fInfo, width, height, compression, &initialState,
-                                           data)) {
-        return nullptr;
-    }
-    idDesc.fOwnership = GrBackendObjectOwnership::kOwned;
-
-    GrSurfaceDesc desc;
-    desc.fConfig = GrCompressionTypePixelConfig(compression);
-    desc.fWidth = width;
-    desc.fHeight = height;
-    desc.fSampleCnt = 1;
-    auto tex =
-            sk_make_sp<GrGLTexture>(this, budgeted, desc, idDesc, GrMipMapsStatus::kNotAllocated);
-    // The non-sampler params are still at their default values.
-    tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
-                           fResetTimestampForTextureParameters);
-    return std::move(tex);
-}
-
 namespace {
 
 const GrGLuint kUnknownBitCount = GrGLStencilAttachment::kUnknownBitCount;
@@ -1759,7 +1811,6 @@
                                 GrGLTextureParameters::SamplerOverriddenState* initialState,
                                 const GrMipLevel texels[], int mipLevelCount,
                                 GrMipMapsStatus* mipMapsStatus) {
-    SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
     info->fID = 0;
     info->fTarget = GR_GL_TEXTURE_2D;
     GL_CALL(GenTextures(1, &(info->fID)));
@@ -1781,37 +1832,25 @@
 
     *initialState = set_initial_texture_params(this->glInterface(), *info);
 
-    if (!this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, info->fTarget,
-                             kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
-                             texels, mipLevelCount, mipMapsStatus)) {
+    bool success = false;
+    if (GrGLFormatIsCompressed(info->fFormat)) {
+        SkASSERT(GrRenderable::kNo == renderable);
+
+        success = this->uploadCompressedTexData(desc.fConfig, desc.fWidth, desc.fHeight,
+                                                info->fTarget,
+                                                texels, mipLevelCount, mipMapsStatus);
+    } else {
+        success = this->uploadTexData(desc.fConfig, desc.fWidth, desc.fHeight, info->fTarget,
+                                      kNewTexture_UploadType, 0, 0, desc.fWidth, desc.fHeight,
+                                      desc.fConfig, texels, mipLevelCount, mipMapsStatus);
+    }
+    if (!success) {
         GL_CALL(DeleteTextures(1, &(info->fID)));
         return false;
     }
     return true;
 }
 
-bool GrGLGpu::createCompressedTextureImpl(
-        GrGLTextureInfo* info, int width, int height, SkImage::CompressionType compression,
-        GrGLTextureParameters::SamplerOverriddenState* initialState, const void* data) {
-    info->fID = 0;
-    GL_CALL(GenTextures(1, &info->fID));
-    if (!info->fID) {
-        return false;
-    }
-
-    info->fTarget = GR_GL_TEXTURE_2D;
-    this->bindTextureToScratchUnit(info->fTarget, info->fID);
-
-    *initialState = set_initial_texture_params(this->glInterface(), *info);
-
-    info->fFormat = this->uploadCompressedTexData(compression, width, height, info->fTarget, data);
-    if (!info->fFormat) {
-        GL_CALL(DeleteTextures(1, &info->fID));
-        return false;
-    }
-    return true;
-}
-
 GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
                                                                      int width, int height) {
     SkASSERT(width >= rt->width());
@@ -3984,8 +4023,8 @@
         return GrBackendTexture();  // invalid
     }
 
-    if (w < 1 || w > this->caps()->maxTextureSize() ||
-        h < 1 || h > this->caps()->maxTextureSize()) {
+    if (w == 0 || w > this->caps()->maxTextureSize() ||
+        h == 0 || h > this->caps()->maxTextureSize()) {
         return GrBackendTexture();  // invalid
     }
 
@@ -3998,70 +4037,60 @@
         return GrBackendTexture();  // invalid
     }
 
-    GrGLTextureInfo info;
-    GrGLTextureParameters::SamplerOverriddenState initialState;
-
     int mipLevelCount = 0;
     SkAutoTMalloc<GrMipLevel> texels;
     SkAutoMalloc pixelStorage;
-    SkImage::CompressionType compressionType;
-    if (GrGLFormatToCompressionType(*glFormat, &compressionType)) {
-        // Compressed textures currently must be non-MIP mapped and have initial data.
-        if (mipMapped == GrMipMapped::kYes) {
-            return GrBackendTexture();
-        }
-        if (!srcPixels) {
-            if (!color) {
-                return GrBackendTexture();
-            }
+
+    if (srcPixels) {
+        mipLevelCount = 1;
+
+        texels.reset(mipLevelCount);
+
+        if (GrGLFormatIsCompressed(*glFormat)) {
             SkASSERT(0 == rowBytes);
-            size_t size = GrCompressedDataSize(compressionType, w, h);
-            srcPixels = pixelStorage.reset(size);
-            GrFillInCompressedData(compressionType, w, h, (char*)srcPixels, *color);
         }
-        if (!this->createCompressedTextureImpl(&info, w, h, compressionType, &initialState,
-                                               srcPixels)) {
-            return GrBackendTexture();
+
+        texels.get()[0] = { srcPixels, rowBytes };
+    } else if (color) {
+        mipLevelCount = 1;
+        if (GrMipMapped::kYes == mipMapped) {
+            mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
         }
-    } else {
-        if (srcPixels) {
-            mipLevelCount = 1;
-            texels.reset(mipLevelCount);
-            texels.get()[0] = {srcPixels, rowBytes};
-        } else if (color) {
-            mipLevelCount = 1;
-            if (GrMipMapped::kYes == mipMapped) {
-                mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
-            }
 
-            texels.reset(mipLevelCount);
-            SkTArray<size_t> individualMipOffsets(mipLevelCount);
+        texels.reset(mipLevelCount);
+        SkTArray<size_t> individualMipOffsets(mipLevelCount);
 
-            size_t bytesPerPixel = GrBytesPerPixel(config);
+        GrCompression compression = GrGLFormat2Compression(*glFormat);
+        size_t bytesPerPixel = GrBytesPerPixel(config);
 
-            size_t totalSize = GrComputeTightCombinedBufferSize(
-                    bytesPerPixel, w, h, &individualMipOffsets, mipLevelCount);
+        size_t totalSize = GrComputeTightCombinedBufferSize(compression, bytesPerPixel, w, h,
+                                                            &individualMipOffsets, mipLevelCount);
 
-            char* tmpPixels = (char*)pixelStorage.reset(totalSize);
+        char* tmpPixels = (char *) pixelStorage.reset(totalSize);
 
-            GrFillInData(config, w, h, individualMipOffsets, tmpPixels, *color);
-            for (int i = 0; i < mipLevelCount; ++i) {
-                size_t offset = individualMipOffsets[i];
+        GrFillInData(compression, config, w, h, individualMipOffsets, tmpPixels, *color);
 
-                int twoToTheMipLevel = 1 << i;
-                int currentWidth = SkTMax(1, w / twoToTheMipLevel);
+        for (int i = 0; i < mipLevelCount; ++i) {
+            size_t offset = individualMipOffsets[i];
 
-                texels.get()[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
-            }
+            int twoToTheMipLevel = 1 << i;
+            int currentWidth = SkTMax(1, w / twoToTheMipLevel);
+
+            texels.get()[i] = { &(tmpPixels[offset]), currentWidth*bytesPerPixel };
         }
-        GrSurfaceDesc desc;
-        desc.fWidth = w;
-        desc.fHeight = h;
-        desc.fConfig = config;
-        if (!this->createTextureImpl(desc, &info, renderable, &initialState, texels.get(),
-                                     mipLevelCount, nullptr)) {
-            return GrBackendTexture();  // invalid
-        }
+    }
+
+    GrSurfaceDesc desc;
+    desc.fWidth = w;
+    desc.fHeight = h;
+    desc.fConfig = config;
+
+    GrGLTextureInfo info;
+    GrGLTextureParameters::SamplerOverriddenState initialState;
+
+    if (!this->createTextureImpl(desc, &info, renderable, &initialState, texels.get(),
+                                 mipLevelCount, nullptr)) {
+        return GrBackendTexture();  // invalid
     }
 
     // unbind the texture from the texture unit to avoid asserts
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index db6564e..47e75e6 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -194,9 +194,6 @@
 
     sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                      const GrMipLevel texels[], int mipLevelCount) override;
-    sk_sp<GrTexture> onCreateCompressedTexture(int width, int height,
-                                               SkImage::CompressionType compression, SkBudgeted,
-                                               const void* data) override;
 
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType intendedType, GrAccessPattern,
                                       const void* data) override;
@@ -224,11 +221,6 @@
                            const GrMipLevel texels[], int mipLevelCount,
                            GrMipMapsStatus* mipMapsStatus);
 
-    bool createCompressedTextureImpl(GrGLTextureInfo* info, int width, int height,
-                                     SkImage::CompressionType compression,
-                                     GrGLTextureParameters::SamplerOverriddenState* initialState,
-                                     const void* data);
-
     // Checks whether glReadPixels can be called to get pixel values in readConfig from the
     // render target.
     bool readPixelsSupported(GrRenderTarget* target, GrPixelConfig readConfig);
@@ -406,11 +398,12 @@
                        GrPixelConfig dataConfig, const GrMipLevel texels[], int mipLevelCount,
                        GrMipMapsStatus* mipMapsStatus = nullptr);
 
-    // Helper for onCreateCompressedTexture. Compressed textures are read-only so we
-    // only use this to populate a new texture. Returns the internal format of the texture
-    // or 0 on failure.
-    GrGLenum uploadCompressedTexData(SkImage::CompressionType, int width, int height,
-                                     GrGLenum target, const void* data);
+    // helper for onCreateCompressedTexture. Compressed textures are read-only so we
+    // only use this to populate a new texture.
+    bool uploadCompressedTexData(GrPixelConfig texConfig, int texWidth, int texHeight,
+                                 GrGLenum target,
+                                 const GrMipLevel texels[], int mipLevelCount,
+                                 GrMipMapsStatus* mipMapsStatus = nullptr);
 
     bool createRenderTargetObjects(const GrSurfaceDesc&, const GrGLTextureInfo& texInfo,
                                    GrGLRenderTarget::IDDesc*);
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 0efeac6..d7ad1aa 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -602,17 +602,36 @@
         default:
             return false;
     }
+    SK_ABORT("Invalid format");
+    return false;
 }
 
-bool GrGLFormatToCompressionType(GrGLenum glFormat, SkImage::CompressionType* compressionType) {
+GrCompression GrGLFormat2Compression(GrGLenum glFormat) {
     switch (glFormat) {
         case GR_GL_COMPRESSED_RGB8_ETC2: // fall through
         case GR_GL_COMPRESSED_ETC1_RGB8:
-            *compressionType = SkImage::kETC1_CompressionType;
-            return true;
+            return GrCompression::kETC1;
         default:
-            return false;
+            return GrCompression::kNone;
     }
+    SK_ABORT("Invalid format");
+    return GrCompression::kNone;
+}
+
+size_t GrGLFormatCompressedDataSize(GrGLenum glFormat, int width, int height) {
+    SkASSERT(GrGLFormatIsCompressed(glFormat));
+
+    switch (glFormat) {
+        case GR_GL_COMPRESSED_RGB8_ETC2:  // fall through
+        case GR_GL_COMPRESSED_ETC1_RGB8:
+            return GrETC1CompressedDataSize(width, height);
+        default:
+            SK_ABORT("Unknown compressed format");
+            return 4 * width * height;
+    }
+
+    SK_ABORT("Unknown compressed format");
+    return 4 * width * height;
 }
 
 size_t GrGLBytesPerFormat(GrGLenum glFormat) {
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index 9670776..4093816 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -282,9 +282,14 @@
 bool GrGLFormatIsCompressed(GrGLenum glFormat);
 
 /**
- * Maps a gl format into the CompressionType enum if appropriate.
+ * Maps a gl format into the GrCompressed enum.
  */
-bool GrGLFormatToCompressionType(GrGLenum glFormat, SkImage::CompressionType*);
+GrCompression GrGLFormat2Compression(GrGLenum glFormat);
+
+/**
+ * Returns the data size for the given compressed format
+ */
+size_t GrGLFormatCompressedDataSize(GrGLenum glFormat, int width, int height);
 
 size_t GrGLBytesPerFormat(GrGLenum glFormat);
 
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index ff39757..678ce1c 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -150,16 +150,6 @@
         return GrBackendFormat::MakeMock(config);
     }
 
-    GrBackendFormat getBackendFormatFromCompressionType(
-            SkImage::CompressionType compressionType) const override {
-        switch (compressionType) {
-            case SkImage::kETC1_CompressionType:
-                return GrBackendFormat::MakeMock(kRGB_ETC1_GrPixelConfig);
-        }
-        SK_ABORT("Invalid compression type");
-        return {};
-    }
-
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override {
         return GrSwizzle();
     }
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index e8c1899..f0355e5 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -106,25 +106,6 @@
     return sk_sp<GrTexture>(new GrMockTexture(this, budgeted, desc, mipMapsStatus, texInfo));
 }
 
-sk_sp<GrTexture> GrMockGpu::onCreateCompressedTexture(int width, int height,
-                                                      SkImage::CompressionType compressionType,
-                                                      SkBudgeted budgeted, const void* data) {
-    if (fMockOptions.fFailTextureAllocations) {
-        return nullptr;
-    }
-    GrBackendFormat format = this->caps()->getBackendFormatFromCompressionType(compressionType);
-
-    GrMockTextureInfo texInfo;
-    texInfo.fConfig = *format.getMockFormat();
-    texInfo.fID = NextInternalTextureID();
-    GrSurfaceDesc desc;
-    desc.fConfig = texInfo.fConfig;
-    desc.fWidth = width;
-    desc.fHeight = height;
-    return sk_sp<GrTexture>(
-            new GrMockTexture(this, budgeted, desc, GrMipMapsStatus::kNotAllocated, texInfo));
-}
-
 sk_sp<GrTexture> GrMockGpu::onWrapBackendTexture(const GrBackendTexture& tex,
                                                  GrWrapOwnership ownership,
                                                  GrWrapCacheable wrapType, GrIOType ioType) {
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index b26c4e1..b95f90b 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -66,9 +66,6 @@
     sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted, const GrMipLevel[],
                                      int mipLevelCount) override;
 
-    sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, SkImage::CompressionType,
-                                               SkBudgeted, const void* data) override;
-
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership, GrWrapCacheable,
                                           GrIOType) override;
 
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index adebbce..4134194 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -73,7 +73,6 @@
 
     GrBackendFormat getBackendFormatFromGrColorType(GrColorType ct,
                                                     GrSRGBEncoded srgbEncoded) const override;
-    GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
 
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/mtl/GrMtlCaps.mm b/src/gpu/mtl/GrMtlCaps.mm
index dc3469a..e2dc706 100644
--- a/src/gpu/mtl/GrMtlCaps.mm
+++ b/src/gpu/mtl/GrMtlCaps.mm
@@ -637,20 +637,6 @@
     return GrBackendFormat::MakeMtl(format);
 }
 
-GrBackendFormat GrMtlCaps::getBackendFormatFromCompressionType(
-        SkImage::CompressionType compressionType) const {
-    switch (compressionType) {
-        case SkImage::kETC1_CompressionType:
-#ifdef SK_BUILD_FOR_MAC
-            return {};
-#else
-            return GrBackendFormat::MakeMtl(MTLPixelFormatETC2_RGB8);
-#endif
-    }
-    SK_ABORT("Invalid compression type");
-    return {};
-}
-
 #ifdef SK_DEBUG
 static bool format_color_type_valid_pair(MTLPixelFormat format, GrColorType colorType) {
     switch (colorType) {
@@ -673,13 +659,7 @@
         case GrColorType::kRGBA_8888:
             return MTLPixelFormatRGBA8Unorm == format || MTLPixelFormatRGBA8Unorm_sRGB == format;
         case GrColorType::kRGB_888x:
-            GR_STATIC_ASSERT(GrCompressionTypeClosestColorType(SkImage::kETC1_CompressionType) ==
-                             GrColorType::kRGB_888x);
-#ifdef SK_BUILD_FOR_MAC
             return MTLPixelFormatRGBA8Unorm == format;
-#else
-            return MTLPixelFormatRGBA8Unorm == format || MTLPixelFormatETC2_RGB8 == format;
-#endif
         case GrColorType::kRG_88:
             return MTLPixelFormatRG8Unorm == format;
         case GrColorType::kBGRA_8888:
@@ -698,6 +678,12 @@
             return MTLPixelFormatRG32Float == format;
         case GrColorType::kRGBA_F32:
             return MTLPixelFormatRGBA32Float == format;
+        case GrColorType::kRGB_ETC1:
+#ifdef SK_BUILD_FOR_MAC
+            return false;
+#else
+            return MTLPixelFormatETC2_RGB8 == format;
+#endif
         case GrColorType::kR_16:
             return MTLPixelFormatR16Unorm == format;
         case GrColorType::kRG_1616:
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 8cd8288..6d5979a 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -131,10 +131,6 @@
 
     sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
                                      const GrMipLevel texels[], int mipLevelCount) override;
-    sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, SkImage::CompressionType,
-                                               SkBudgeted, const void* data) override {
-        return nullptr;
-    }
 
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership, GrWrapCacheable,
                                           GrIOType) override;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 28417e7..8b904d3 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -1086,16 +1086,6 @@
     return GrBackendFormat::MakeVk(format);
 }
 
-GrBackendFormat GrVkCaps::getBackendFormatFromCompressionType(
-        SkImage::CompressionType compressionType) const {
-    switch (compressionType) {
-        case SkImage::kETC1_CompressionType:
-            return GrBackendFormat::MakeVk(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK);
-    }
-    SK_ABORT("Invalid compression type");
-    return {};
-}
-
 #ifdef SK_DEBUG
 static bool format_color_type_valid_pair(VkFormat vkFormat, GrColorType colorType) {
     switch (colorType) {
@@ -1111,10 +1101,7 @@
         case GrColorType::kRGBA_8888:
             return VK_FORMAT_R8G8B8A8_UNORM == vkFormat || VK_FORMAT_R8G8B8A8_SRGB == vkFormat;
         case GrColorType::kRGB_888x:
-            GR_STATIC_ASSERT(GrCompressionTypeClosestColorType(SkImage::kETC1_CompressionType) ==
-                             GrColorType::kRGB_888x);
-            return VK_FORMAT_R8G8B8_UNORM == vkFormat || VK_FORMAT_R8G8B8A8_UNORM == vkFormat ||
-                   VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK == vkFormat;
+            return VK_FORMAT_R8G8B8_UNORM == vkFormat || VK_FORMAT_R8G8B8A8_UNORM == vkFormat;
         case GrColorType::kRG_88:
             return VK_FORMAT_R8G8_UNORM == vkFormat;
         case GrColorType::kBGRA_8888:
@@ -1133,6 +1120,8 @@
             return VK_FORMAT_R32G32_SFLOAT == vkFormat;
         case GrColorType::kRGBA_F32:
             return VK_FORMAT_R32G32B32A32_SFLOAT == vkFormat;
+        case GrColorType::kRGB_ETC1:
+            return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK == vkFormat;
         case GrColorType::kR_16:
             return VK_FORMAT_R16_UNORM == vkFormat;
         case GrColorType::kRG_1616:
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index c859121..9d1f04d 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -169,7 +169,6 @@
 
     GrBackendFormat getBackendFormatFromGrColorType(GrColorType ct,
                                                     GrSRGBEncoded srgbEncoded) const override;
-    GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
 
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 7b7bff5..7699ff4 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -896,30 +896,62 @@
 // It's probably possible to roll this into uploadTexDataOptimal,
 // but for now it's easier to maintain as a separate entity.
 bool GrVkGpu::uploadTexDataCompressed(GrVkTexture* tex, int left, int top, int width, int height,
-                                      SkImage::CompressionType compressionType, const void* data) {
-    SkASSERT(data);
+                                      GrColorType dataColorType, const GrMipLevel texels[],
+                                      int mipLevelCount) {
     SkASSERT(!tex->isLinearTiled());
     // For now the assumption is that our rect is the entire texture.
     // Compressed textures are read-only so this should be a reasonable assumption.
     SkASSERT(0 == left && 0 == top && width == tex->width() && height == tex->height());
 
+    // We assume that if the texture has mip levels, we either upload to all the levels or just the
+    // first.
+    SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
+
+    SkASSERT(GrPixelConfigIsCompressed(GrColorTypeToPixelConfig(dataColorType,
+                                                                GrSRGBEncoded::kNo)));
+
     if (width == 0 || height == 0) {
         return false;
     }
 
-    SkImage::CompressionType textureCompressionType;
-    if (!GrVkFormatToCompressionType(tex->imageFormat(), &textureCompressionType) ||
-        textureCompressionType != compressionType) {
+    if (GrPixelConfigToColorType(tex->config()) != dataColorType) {
         return false;
     }
 
     SkASSERT(this->vkCaps().isFormatTexturable(tex->imageFormat()));
 
-    size_t dataSize = GrCompressedDataSize(compressionType, width, height);
+    SkTArray<size_t> individualMipOffsets(mipLevelCount);
+    individualMipOffsets.push_back(0);
+    size_t combinedBufferSize = GrVkFormatCompressedDataSize(tex->imageFormat(), width, height);
+    int currentWidth = width;
+    int currentHeight = height;
+    if (!texels[0].fPixels) {
+        return false;
+    }
+
+    // We assume that the alignment for any compressed format is at least 4 bytes and so we don't
+    // need to worry about alignment issues. For example, each block in ETC1 is 8 bytes.
+    for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; currentMipLevel++) {
+        currentWidth = SkTMax(1, currentWidth / 2);
+        currentHeight = SkTMax(1, currentHeight / 2);
+
+        if (texels[currentMipLevel].fPixels) {
+            const size_t dataSize = GrVkFormatCompressedDataSize(tex->imageFormat(), currentWidth,
+                                                                 currentHeight);
+            individualMipOffsets.push_back(combinedBufferSize);
+            combinedBufferSize += dataSize;
+        } else {
+            return false;
+        }
+    }
+    if (0 == combinedBufferSize) {
+        // We don't have any data to upload so fail (compressed textures are read-only).
+        return false;
+    }
 
     // allocate buffer to hold our mip data
     sk_sp<GrVkTransferBuffer> transferBuffer =
-            GrVkTransferBuffer::Make(this, dataSize, GrVkBuffer::kCopyRead_Type);
+            GrVkTransferBuffer::Make(this, combinedBufferSize, GrVkBuffer::kCopyRead_Type);
     if (!transferBuffer) {
         return false;
     }
@@ -929,17 +961,38 @@
     GrVkTexture* uploadTexture = tex;
 
     char* buffer = (char*)transferBuffer->map();
+    SkTArray<VkBufferImageCopy> regions(mipLevelCount);
 
-    memcpy(buffer, data, dataSize);
+    currentWidth = width;
+    currentHeight = height;
+    int layerHeight = uploadTexture->height();
+    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+        if (texels[currentMipLevel].fPixels) {
+            // Again, we're assuming that our rect is the entire texture
+            SkASSERT(currentHeight == layerHeight);
+            SkASSERT(0 == uploadLeft && 0 == uploadTop);
 
-    VkBufferImageCopy region;
-    memset(&region, 0, sizeof(VkBufferImageCopy));
-    region.bufferOffset = transferBuffer->offset();
-    region.bufferRowLength = width;
-    region.bufferImageHeight = height;
-    region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
-    region.imageOffset = { uploadLeft, uploadTop, 0 };
-    region.imageExtent = { SkToU32(width), SkToU32(height), 1 };
+            const size_t dataSize = GrVkFormatCompressedDataSize(tex->imageFormat(), currentWidth,
+                                                                 currentHeight);
+
+            // copy data into the buffer, skipping the trailing bytes
+            char* dst = buffer + individualMipOffsets[currentMipLevel];
+            const char* src = (const char*)texels[currentMipLevel].fPixels;
+            memcpy(dst, src, dataSize);
+
+            VkBufferImageCopy& region = regions.push_back();
+            memset(&region, 0, sizeof(VkBufferImageCopy));
+            region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
+            region.bufferRowLength = currentWidth;
+            region.bufferImageHeight = currentHeight;
+            region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
+            region.imageOffset = { uploadLeft, uploadTop, 0 };
+            region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
+        }
+        currentWidth = SkTMax(1, currentWidth / 2);
+        currentHeight = SkTMax(1, currentHeight / 2);
+        layerHeight = currentHeight;
+    }
 
     // no need to flush non-coherent memory, unmap will do that for us
     transferBuffer->unmap();
@@ -956,8 +1009,12 @@
                                          transferBuffer.get(),
                                          uploadTexture,
                                          VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                                         1,
-                                         &region);
+                                         regions.count(),
+                                         regions.begin());
+
+    if (1 == mipLevelCount) {
+        tex->texturePriv().markMipMapsDirty();
+    }
 
     return true;
 }
@@ -1022,16 +1079,24 @@
         return nullptr;
     }
 
+    bool isCompressed = GrVkFormatIsCompressed(tex->imageFormat());
     auto colorType = GrPixelConfigToColorType(desc.fConfig);
     if (mipLevelCount) {
-        if (!this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType,
-                                        texels, mipLevelCount)) {
+        bool success;
+        if (isCompressed) {
+            success = this->uploadTexDataCompressed(tex.get(), 0, 0, desc.fWidth, desc.fHeight,
+                                                    colorType, texels, mipLevelCount);
+        } else {
+            success = this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight,
+                                                 colorType, texels, mipLevelCount);
+        }
+        if (!success) {
             tex->unref();
             return nullptr;
         }
     }
 
-    if (SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag)) {
+    if (SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) && !isCompressed) {
         VkClearColorValue zeroClearColor;
         memset(&zeroClearColor, 0, sizeof(zeroClearColor));
         VkImageSubresourceRange range;
@@ -1047,55 +1112,6 @@
     return std::move(tex);
 }
 
-sk_sp<GrTexture> GrVkGpu::onCreateCompressedTexture(int width, int height,
-                                                    SkImage::CompressionType compressionType,
-                                                    SkBudgeted budgeted, const void* data) {
-    GrBackendFormat format = this->caps()->getBackendFormatFromCompressionType(compressionType);
-    if (!format.getVkFormat()) {
-        return nullptr;
-    }
-    VkFormat pixelFormat = *format.getVkFormat();
-
-    VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT;
-
-    // For now we will set the VK_IMAGE_USAGE_TRANSFER_DESTINATION_BIT and
-    // VK_IMAGE_USAGE_TRANSFER_SOURCE_BIT on every texture since we do not know whether or not we
-    // will be using this texture in some copy or not. Also this assumes, as is the current case,
-    // that all render targets in vulkan are also textures. If we change this practice of setting
-    // both bits, we must make sure to set the destination bit if we are uploading srcData to the
-    // texture.
-    usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
-
-    // Compressed textures with MIP levels or multiple samples are not supported as of now.
-    GrVkImage::ImageDesc imageDesc;
-    imageDesc.fImageType = VK_IMAGE_TYPE_2D;
-    imageDesc.fFormat = pixelFormat;
-    imageDesc.fWidth = width;
-    imageDesc.fHeight = height;
-    imageDesc.fLevels = 1;
-    imageDesc.fSamples = 1;
-    imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
-    imageDesc.fUsageFlags = usageFlags;
-    imageDesc.fIsProtected = GrProtected::kNo;
-
-    GrSurfaceDesc desc;
-    desc.fConfig = GrCompressionTypePixelConfig(compressionType);
-    desc.fWidth = width;
-    desc.fHeight = height;
-    auto tex = GrVkTexture::MakeNewTexture(this, budgeted, desc, imageDesc,
-                                           GrMipMapsStatus::kNotAllocated);
-    if (!tex) {
-        return nullptr;
-    }
-
-    if (!this->uploadTexDataCompressed(tex.get(), 0, 0, desc.fWidth, desc.fHeight, compressionType,
-                                       data)) {
-        return nullptr;
-    }
-
-    return std::move(tex);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 
 void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset,
@@ -1464,30 +1480,6 @@
                    int width, int height,
                    const void* srcData, size_t srcRowBytes) {
     SkASSERT(srcData);
-    SkASSERT(!GrVkFormatIsCompressed(vkFormat));
-
-    void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
-    if (!mapPtr) {
-        return false;
-    }
-    size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
-    const size_t trimRowBytes = width * bytesPerPixel;
-    if (!srcRowBytes) {
-        srcRowBytes = trimRowBytes;
-    }
-    SkASSERT(trimRowBytes * height <= alloc.fSize);
-
-    SkRectMemcpy(mapPtr, trimRowBytes, srcData, srcRowBytes, trimRowBytes, height);
-
-    GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
-    GrVkMemory::UnmapAlloc(gpu, alloc);
-    return true;
-}
-
-bool copy_compressed_src_data(GrVkGpu* gpu, const GrVkAlloc& alloc,
-                              SkImage::CompressionType compressionType, int width, int height,
-                              const void* data) {
-    SkASSERT(data);
 
     void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
     if (!mapPtr) {
@@ -1495,30 +1487,43 @@
     }
     mapPtr = reinterpret_cast<char*>(mapPtr);
 
-    size_t dataSize = GrCompressedDataSize(compressionType, width, height);
-    SkASSERT(dataSize <= alloc.fSize);
-    memcpy(mapPtr, data, dataSize);
+    if (GrVkFormatIsCompressed(vkFormat)) {
+        SkASSERT(0 == srcRowBytes);
+        size_t levelSize = GrVkFormatCompressedDataSize(vkFormat, width, height);
+
+        SkASSERT(levelSize <= alloc.fSize);
+        memcpy(mapPtr, srcData, levelSize);
+    } else {
+        size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
+        const size_t trimRowBytes = width * bytesPerPixel;
+        if (!srcRowBytes) {
+            srcRowBytes = trimRowBytes;
+        }
+        SkASSERT(trimRowBytes * height <= alloc.fSize);
+
+        SkRectMemcpy(mapPtr, trimRowBytes, srcData, srcRowBytes, trimRowBytes, height);
+    }
+
     GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
     GrVkMemory::UnmapAlloc(gpu, alloc);
     return true;
 }
+
 bool fill_in_with_color(GrVkGpu* gpu, const GrVkAlloc& alloc, VkFormat vkFormat,
                         int baseWidth, int baseHeight,
                         const SkTArray<size_t>& individualMipOffsets,
                         GrPixelConfig config, const SkColor4f& color) {
 
+    GrCompression compression = GrVkFormat2Compression(vkFormat);
+
     void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
     if (!mapPtr) {
         return false;
     }
 
-    SkImage::CompressionType compressionType;
-    if (GrVkFormatToCompressionType(vkFormat, &compressionType)) {
-        GrFillInCompressedData(compressionType, baseWidth, baseHeight, (char*)mapPtr, color);
-    } else {
-        // TODO: pass in alloc.fSize and assert we never write past it
-        GrFillInData(config, baseWidth, baseHeight, individualMipOffsets, (char*)mapPtr, color);
-    }
+    // TODO: pass in alloc.fSize and assert we never write past it
+    GrFillInData(compression, config, baseWidth, baseHeight,
+                 individualMipOffsets, (char*) mapPtr, color);
 
     GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
     GrVkMemory::UnmapAlloc(gpu, alloc);
@@ -1661,24 +1666,10 @@
 
     SkTArray<size_t> individualMipOffsets(mipLevels);
 
-    SkImage::CompressionType compressionType;
-    bool isCompressed = GrVkFormatToCompressionType(vkFormat, &compressionType);
+    GrCompression compression = GrVkFormat2Compression(vkFormat);
 
-    size_t combinedBufferSize;
-    if (isCompressed) {
-        // Compressed textures currently must be non-MIP mapped and have initial data.
-        if (mipMapped == GrMipMapped::kYes) {
-            return false;
-        }
-        if (!srcData && !color) {
-            return false;
-        }
-        combinedBufferSize = GrCompressedDataSize(compressionType, w, h);
-        individualMipOffsets.push_back(0);
-    } else {
-        combinedBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel, w, h,
-                                                              &individualMipOffsets, mipLevels);
-    }
+    size_t combinedBufferSize = GrComputeTightCombinedBufferSize(compression, bytesPerPixel, w, h,
+                                                                 &individualMipOffsets, mipLevels);
 
     VkBufferCreateInfo bufInfo;
     memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
@@ -1711,10 +1702,9 @@
     if (!srcData) {
         result = fill_in_with_color(this, bufferAlloc, vkFormat, w, h, individualMipOffsets,
                                     config, *color);
-    } else if (isCompressed) {
-        result = copy_compressed_src_data(this, bufferAlloc, compressionType, w, h, srcData);
     } else {
         SkASSERT(1 == mipLevels);
+
         result = copy_src_data(this, bufferAlloc, vkFormat, w, h, srcData, srcRowBytes);
     }
 
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 8392c48..5600eac 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -194,8 +194,6 @@
 
     sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted, const GrMipLevel[],
                                      int mipLevelCount) override;
-    sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, SkImage::CompressionType,
-                                               SkBudgeted, const void* data) override;
 
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&, GrWrapOwnership, GrWrapCacheable,
                                           GrIOType) override;
@@ -258,7 +256,8 @@
     bool uploadTexDataOptimal(GrVkTexture* tex, int left, int top, int width, int height,
                               GrColorType colorType, const GrMipLevel texels[], int mipLevelCount);
     bool uploadTexDataCompressed(GrVkTexture* tex, int left, int top, int width, int height,
-                                 SkImage::CompressionType, const void* data);
+                                 GrColorType dataColorType, const GrMipLevel texels[],
+                                 int mipLevelCount);
     void resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect,
                       const SkIPoint& dstPoint);
 
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index 39b6a0d..cf4bd64 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -337,14 +337,33 @@
         default:
             return false;
     }
+    SK_ABORT("Invalid format");
+    return false;
 }
 
-bool GrVkFormatToCompressionType(VkFormat vkFormat, SkImage::CompressionType* compressionType) {
+GrCompression GrVkFormat2Compression(VkFormat vkFormat) {
     switch (vkFormat) {
         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-            *compressionType = SkImage::kETC1_CompressionType;
-            return true;
+            return GrCompression::kETC1;
         default:
-            return false;
+            return GrCompression::kNone;
     }
+    SK_ABORT("Invalid format");
+    return GrCompression::kNone;
 }
+
+size_t GrVkFormatCompressedDataSize(VkFormat vkFormat, int width, int height) {
+    SkASSERT(GrVkFormatIsCompressed(vkFormat));
+
+    switch (vkFormat) {
+        case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+            return GrETC1CompressedDataSize(width, height);
+        default:
+            SK_ABORT("Unknown compressed format");
+            return 4 * width * height;
+    }
+
+    SK_ABORT("Unknown compressed format");
+    return 4 * width * height;
+}
+
diff --git a/src/gpu/vk/GrVkUtil.h b/src/gpu/vk/GrVkUtil.h
index 6c77c74..7d2b241 100644
--- a/src/gpu/vk/GrVkUtil.h
+++ b/src/gpu/vk/GrVkUtil.h
@@ -68,8 +68,13 @@
 bool GrVkFormatIsCompressed(VkFormat);
 
 /**
- * Maps a vk format into the CompressionType enum if applicable.
+ * Returns the data size for the given compressed format
  */
-bool GrVkFormatToCompressionType(VkFormat vkFormat, SkImage::CompressionType* compressionType);
+size_t GrVkFormatCompressedDataSize(VkFormat, int width, int height);
+
+/**
+ * Maps a vk format into the GrCompressed enum.
+ */
+GrCompression GrVkFormat2Compression(VkFormat);
 
 #endif
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index d4f9710..6fefd63 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -175,9 +175,23 @@
 
 sk_sp<SkImage> SkImage::MakeFromCompressed(GrContext* context, sk_sp<SkData> data,
                                            int width, int height, CompressionType type) {
+    // create the backing texture
+    GrSurfaceDesc desc;
+    desc.fFlags = kNone_GrSurfaceFlags;
+    desc.fWidth = width;
+    desc.fHeight = height;
+    switch (type) {
+        case kETC1_CompressionType:
+            desc.fConfig = kRGB_ETC1_GrPixelConfig;
+            break;
+        default:
+            desc.fConfig = kUnknown_GrPixelConfig;
+            break;
+    }
+    desc.fSampleCnt = 1;
+
     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
-    sk_sp<GrTextureProxy> proxy = proxyProvider->createCompressedTextureProxy(
-            width, height, SkBudgeted::kYes, type, std::move(data));
+    sk_sp<GrTextureProxy> proxy = proxyProvider->createProxy(std::move(data), desc);
 
     if (!proxy) {
         return nullptr;