Revise GrDataUtils to be more self-contained (take 3)

This makes the GL and Vk backends share more code and sets up for the Metal implementation.

Change-Id: I781d5b6188fb2d46ae4ec48204fda74fe28b18c0
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/218964
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index 8b4de2d..965251e 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -117,7 +117,8 @@
     return numBlocks * sizeof(ETC1Block);
 }
 
-void GrFillInETC1WithColor(int width, int height, const SkColor4f& colorf, void* dest) {
+// Fill in 'dest' with ETC1 blocks derived from 'colorf'
+static void fillin_ETC1_with_color(int width, int height, const SkColor4f& colorf, void* dest) {
     SkColor color = colorf.toSkColor();
 
     ETC1Block block;
@@ -130,8 +131,9 @@
     }
 }
 
-bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
-                           const SkColor4f& colorf, void* dest) {
+// Fill in the width x height 'dest' with the munged version of 'colorf' that matches 'config'
+static bool fill_buffer_with_color(GrPixelConfig config, int width, int height,
+                                   const SkColor4f& colorf, void* dest) {
     SkASSERT(kRGB_ETC1_GrPixelConfig != config);
 
     GrColor color = colorf.toBytes_RGBA();
@@ -282,3 +284,78 @@
 
     return true;
 }
+
+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;
+
+    // The Vulkan spec for copying a buffer to an image requires that the alignment must be at
+    // least 4 bytes and a multiple of the bytes per pixel of the image config.
+    SkASSERT(bytesPerPixel == 1 || bytesPerPixel == 2 || bytesPerPixel == 3 ||
+             bytesPerPixel == 4 || bytesPerPixel == 8 || bytesPerPixel == 16);
+    int desiredAlignment = (bytesPerPixel == 3) ? 12 : (bytesPerPixel > 4 ? bytesPerPixel : 4);
+
+    for (int currentMipLevel = 1; currentMipLevel < mipLevelCount; ++currentMipLevel) {
+        currentWidth = SkTMax(1, currentWidth / 2);
+        currentHeight = SkTMax(1, currentHeight / 2);
+
+        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;
+        }
+        SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bytesPerPixel));
+
+        individualMipOffsets->push_back(combinedBufferSize);
+        combinedBufferSize += trimmedSize;
+    }
+
+    SkASSERT(individualMipOffsets->count() == mipLevelCount);
+    return combinedBufferSize;
+}
+
+void GrFillInData(GrCompression compression, GrPixelConfig config,
+                  int baseWidth, int baseHeight,
+                  const SkTArray<size_t>& individualMipOffsets, char* dstPixels,
+                  const SkColor4f& colorf) {
+
+    int mipLevels = individualMipOffsets.count();
+
+    int currentWidth = baseWidth;
+    int currentHeight = baseHeight;
+    for (int currentMipLevel = 0; currentMipLevel < mipLevels; ++currentMipLevel) {
+        size_t offset = individualMipOffsets[currentMipLevel];
+
+        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);
+    }
+}
+
diff --git a/src/gpu/GrDataUtils.h b/src/gpu/GrDataUtils.h
index bdcbd66..b79e84c 100644
--- a/src/gpu/GrDataUtils.h
+++ b/src/gpu/GrDataUtils.h
@@ -11,15 +11,26 @@
 #include "include/core/SkColor.h"
 #include "include/private/GrTypesPriv.h"
 
-// Fill in the width x height 'dest' with the munged version of 'color' that matches 'config'
-bool GrFillBufferWithColor(GrPixelConfig config, int width, int height,
-                           const SkColor4f& color, void* dest);
-
 // TODO: consolidate all the backend-specific flavors of this method to this
 size_t GrETC1CompressedDataSize(int w, int h);
 
-// Fill in 'dest' with ETC1 blocks derived from 'color'
-void GrFillInETC1WithColor(int width, int height,
-                           const SkColor4f& color, void* dest);
+// 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(GrCompression, size_t bytesPerPixel,
+                                        int baseWidth, int baseHeight,
+                                        SkTArray<size_t>* individualMipOffsets,
+                                        int mipLevelCount);
+
+void GrFillInData(GrCompression, GrPixelConfig,
+                  int baseWidth, int baseHeight,
+                  const SkTArray<size_t>& individualMipOffsets,
+                  char* dest, const SkColor4f& color);
 
 #endif
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index f344e2e..d2b18f1 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1589,50 +1589,6 @@
     return state;
 }
 
-size_t GLBytesPerPixel(GrGLenum glFormat) {
-    switch (glFormat) {
-        case GR_GL_LUMINANCE8:
-        case GR_GL_ALPHA8:
-        case GR_GL_R8:
-            return 1;
-
-        case GR_GL_RGB565:
-        case GR_GL_RGBA4:
-        case GR_GL_RG8:
-        case GR_GL_R16F:
-            return 2;
-
-        case GR_GL_RGB8:
-            return 3;
-
-        case GR_GL_RGBA8:
-        case GR_GL_SRGB8_ALPHA8:
-        case GR_GL_BGRA8:
-        case GR_GL_RGB10_A2:
-            return 4;
-
-        case GR_GL_RGBA16F:
-        case GR_GL_RG32F:
-            return 8;
-
-        case GR_GL_RGBA32F:
-            return 16;
-
-        case GR_GL_COMPRESSED_RGB8_ETC2: // fall through
-        case GR_GL_COMPRESSED_ETC1_RGB8:
-            return 0;
-
-        // Experimental (for P016 and P010)
-        case GR_GL_R16:
-            return 2;
-        case GR_GL_RG16:
-            return 4;
-    }
-
-    SK_ABORT("Invalid GL format");
-    return 0;
-}
-
 sk_sp<GrTexture> GrGLGpu::onCreateTexture(const GrSurfaceDesc& desc,
                                           SkBudgeted budgeted,
                                           const GrMipLevel texels[],
@@ -1652,7 +1608,7 @@
     std::unique_ptr<uint8_t[]> zeros;
     if (performClear && !this->glCaps().clearTextureSupport() &&
         !this->glCaps().canConfigBeFBOColorAttachment(desc.fConfig)) {
-        size_t rowSize = GLBytesPerPixel(glFormat) * desc.fWidth;
+        size_t rowSize = GrGLBytesPerFormat(glFormat) * desc.fWidth;
         size_t size = rowSize * desc.fHeight;
         zeros.reset(new uint8_t[size]);
         memset(zeros.get(), 0, size);
@@ -4050,7 +4006,7 @@
                                                const GrBackendFormat& format,
                                                GrMipMapped mipMapped,
                                                GrRenderable renderable,
-                                               const void* pixels, size_t rowBytes,
+                                               const void* srcPixels, size_t rowBytes,
                                                const SkColor4f& colorf) {
     this->handleDirtyContext();
 
@@ -4075,7 +4031,7 @@
     }
 
     // Currently we don't support uploading pixel data when mipped.
-    if (pixels && GrMipMapped::kYes == mipMapped) {
+    if (srcPixels && GrMipMapped::kYes == mipMapped) {
         return GrBackendTexture();  // invalid
     }
 
@@ -4089,43 +4045,39 @@
         mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
     }
 
-    SkAutoMalloc pixelStorage;
-
-    if (GrGLFormatIsCompressed(*glFormat)) {
-        // we have to do something special for compressed textures
-        SkASSERT(0 == rowBytes);
-
-        if (!pixels) {
-            size_t etc1Size = GrGLFormatCompressedDataSize(*glFormat, w, h);
-            pixelStorage.reset(etc1Size);
-            GrFillInETC1WithColor(w, h, colorf, pixelStorage.get());
-            pixels = pixelStorage.get();
-            rowBytes = 0;
-        }
-    } else {
-        int bpp = GrBytesPerPixel(config);
-        const size_t trimRowBytes = w * bpp;
-        if (!rowBytes) {
-            rowBytes = trimRowBytes;
-        }
-
-        if (!pixels) {
-            size_t baseLayerSize = trimRowBytes * h;
-            pixelStorage.reset(baseLayerSize);
-            if (!GrFillBufferWithColor(config, w, h, colorf, pixelStorage.get())) {
-                return GrBackendTexture();  // invalid
-            }
-
-            pixels = pixelStorage.get();
-            rowBytes = trimRowBytes;
-        }
-    }
-
     SkAutoTMalloc<GrMipLevel> texels(mipLevelCount);
 
-    for (int i = 0; i < mipLevelCount; ++i) {
-        // TODO: this isn't correct when pixels for additional mip levels are passed in
-        texels.get()[i] = { pixels, rowBytes };
+    SkAutoMalloc pixelStorage;
+
+    if (!srcPixels) {
+        GrCompression compression = GrGLFormat2Compression(*glFormat);
+
+        SkTArray<size_t> individualMipOffsets(mipLevelCount);
+        size_t bytesPerPixel = GrBytesPerPixel(config);
+
+        size_t totalSize = GrComputeTightCombinedBufferSize(compression, bytesPerPixel, w, h,
+                                                            &individualMipOffsets, mipLevelCount);
+
+        char* tmpPixels = (char *) pixelStorage.reset(totalSize);
+
+        GrFillInData(compression, config, w, h, individualMipOffsets, tmpPixels, colorf);
+
+        for (int i = 0; i < mipLevelCount; ++i) {
+            size_t offset = individualMipOffsets[i];
+
+            int twoToTheMipLevel = 1 << i;
+            int currentWidth = SkTMax(1, w / twoToTheMipLevel);
+
+            texels.get()[i] = { &(tmpPixels[offset]), currentWidth*bytesPerPixel };
+        }
+    } else {
+        SkASSERT(1 == mipLevelCount);
+
+        if (GrGLFormatIsCompressed(*glFormat)) {
+            SkASSERT(0 == rowBytes);
+        }
+
+        texels.get()[0] = { srcPixels, rowBytes };
     }
 
     GrSurfaceDesc desc;
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index 8f67be7..f50932e 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -573,6 +573,18 @@
     return false;
 }
 
+GrCompression GrGLFormat2Compression(GrGLenum glFormat) {
+    switch (glFormat) {
+        case GR_GL_COMPRESSED_RGB8_ETC2: // fall through
+        case GR_GL_COMPRESSED_ETC1_RGB8:
+            return GrCompression::kETC1;
+        default:
+            return GrCompression::kNone;
+    }
+    SK_ABORT("Invalid format");
+    return GrCompression::kNone;
+}
+
 size_t GrGLFormatCompressedDataSize(GrGLenum glFormat, int width, int height) {
     SkASSERT(GrGLFormatIsCompressed(glFormat));
 
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index c9bd3c2..332cddd 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -10,6 +10,7 @@
 
 #include "include/gpu/gl/GrGLInterface.h"
 #include "include/private/GrTypesPriv.h"
+#include "src/gpu/GrDataUtils.h"
 #include "src/gpu/GrStencilSettings.h"
 #include "src/gpu/gl/GrGLDefines.h"
 
@@ -265,6 +266,11 @@
 bool GrGLFormatIsCompressed(GrGLenum glFormat);
 
 /**
+ * Maps a gl format into the GrCompressed enum.
+ */
+GrCompression GrGLFormat2Compression(GrGLenum glFormat);
+
+/**
  * Returns the data size for the given compressed format
  */
 size_t GrGLFormatCompressedDataSize(GrGLenum glFormat, int width, int height);
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index d281524..1387c31 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -663,7 +663,7 @@
                                              options: options];
     } else {
         transferBuffer = [fDevice newBufferWithLength: bufferSize
-                                             options: options];
+                                              options: options];
     }
     if (nil == transferBuffer) {
         return false;
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index eec68dd..873ac8b 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -1444,73 +1444,58 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool copy_testing_data(GrVkGpu* gpu, const void* srcData, const GrVkAlloc& alloc,
-                       size_t bufferOffset, size_t srcRowBytes,
-                       GrPixelConfig destConfig, size_t dstRowBytes,
-                       size_t trimRowBytes, int width, int height, const SkColor4f* color) {
-    SkASSERT(srcData || color);
+bool copy_src_data(GrVkGpu* gpu, const GrVkAlloc& alloc, VkFormat vkFormat,
+                   int width, int height,
+                   const void* srcData, size_t srcRowBytes) {
+    SkASSERT(srcData);
 
-    VkDeviceSize size = dstRowBytes * height;
-    VkDeviceSize offset = bufferOffset;
-    SkASSERT(size + offset <= alloc.fSize);
     void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
     if (!mapPtr) {
         return false;
     }
-    mapPtr = reinterpret_cast<char*>(mapPtr) + offset;
+    mapPtr = reinterpret_cast<char*>(mapPtr);
 
-    if (srcData) {
-        SkRectMemcpy(mapPtr, dstRowBytes, srcData, srcRowBytes, trimRowBytes, height);
+    if (GrVkFormatIsCompressed(vkFormat)) {
+        SkASSERT(0 == srcRowBytes);
+        size_t levelSize = GrVkFormatCompressedDataSize(vkFormat, width, height);
+
+        SkASSERT(levelSize <= alloc.fSize);
+        memcpy(mapPtr, srcData, levelSize);
     } else {
-        if (kRGB_ETC1_GrPixelConfig == destConfig) {
-            GrFillInETC1WithColor(width, height, *color, mapPtr);
-        } else {
-            GrFillBufferWithColor(destConfig, width, height, *color, mapPtr);
+        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, offset, size);
+
+    GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
     GrVkMemory::UnmapAlloc(gpu, alloc);
     return true;
 }
 
-static size_t compute_combined_buffer_size(VkFormat format, size_t bpp, int w, int h,
-                                           SkTArray<size_t>* individualMipOffsets,
-                                           uint32_t mipLevels) {
+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) {
 
-    size_t combinedBufferSize = w * bpp * h;
-    if (GrVkFormatIsCompressed(format)) {
-        combinedBufferSize = GrVkFormatCompressedDataSize(format, w, h);
+    GrCompression compression = GrVkFormat2Compression(vkFormat);
+
+    void* mapPtr = GrVkMemory::MapAlloc(gpu, alloc);
+    if (!mapPtr) {
+        return false;
     }
 
-    int currentWidth = w;
-    int currentHeight = h;
+    // TODO: pass in alloc.fSize and assert we never write past it
+    GrFillInData(compression, config, baseWidth, baseHeight,
+                 individualMipOffsets, (char*) mapPtr, color);
 
-    // The Vulkan spec for copying a buffer to an image, requires that the alignment must be at
-    // least 4 bytes and a multiple of the bytes per pixel of the image config.
-    SkASSERT(bpp == 1 || bpp == 2 || bpp == 3 || bpp == 4 || bpp == 8 || bpp == 16);
-    int desiredAlignment = (bpp == 3) ? 12 : (bpp > 4 ? bpp : 4);
-
-    for (uint32_t currentMipLevel = 1; currentMipLevel < mipLevels; currentMipLevel++) {
-        currentWidth = SkTMax(1, currentWidth / 2);
-        currentHeight = SkTMax(1, currentHeight / 2);
-
-        size_t trimmedSize;
-        if (GrVkFormatIsCompressed(format)) {
-            trimmedSize = GrVkFormatCompressedDataSize(format, currentWidth, currentHeight);
-        } else {
-            trimmedSize = currentWidth * bpp * currentHeight;
-        }
-        const size_t alignmentDiff = combinedBufferSize % desiredAlignment;
-        if (alignmentDiff != 0) {
-            combinedBufferSize += desiredAlignment - alignmentDiff;
-        }
-        SkASSERT((0 == combinedBufferSize % 4) && (0 == combinedBufferSize % bpp));
-
-        individualMipOffsets->push_back(combinedBufferSize);
-        combinedBufferSize += trimmedSize;
-    }
-
-    return combinedBufferSize;
+    GrVkMemory::FlushMappedAlloc(gpu, alloc, 0, alloc.fSize);
+    GrVkMemory::UnmapAlloc(gpu, alloc);
+    return true;
 }
 
 bool GrVkGpu::createTestingOnlyVkImage(GrPixelConfig config, int w, int h, bool texturable,
@@ -1601,14 +1586,15 @@
     err = VK_CALL(BeginCommandBuffer(cmdBuffer, &cmdBufferBeginInfo));
     SkASSERT(!err);
 
-    size_t bpp = GrVkBytesPerFormat(vkFormat);
+    size_t bytesPerPixel = GrVkBytesPerFormat(vkFormat);
     SkASSERT(w && h);
 
     SkTArray<size_t> individualMipOffsets(mipLevels);
-    individualMipOffsets.push_back(0);
 
-    size_t combinedBufferSize = compute_combined_buffer_size(vkFormat, bpp, w, h,
-                                                             &individualMipOffsets, mipLevels);
+    GrCompression compression = GrVkFormat2Compression(vkFormat);
+
+    size_t combinedBufferSize = GrComputeTightCombinedBufferSize(compression, bytesPerPixel, w, h,
+                                                                 &individualMipOffsets, mipLevels);
 
     VkBufferCreateInfo bufInfo;
     memset(&bufInfo, 0, sizeof(VkBufferCreateInfo));
@@ -1637,41 +1623,26 @@
         return false;
     }
 
-    int currentWidth = w;
-    int currentHeight = h;
-    for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
-        SkASSERT(0 == currentMipLevel || !srcData);
-        size_t bufferOffset = individualMipOffsets[currentMipLevel];
-        bool result;
-        if (GrVkFormatIsCompressed(vkFormat)) {
-            size_t levelSize = GrVkFormatCompressedDataSize(vkFormat, currentWidth, currentHeight);
-            size_t currentRowBytes = levelSize / currentHeight;
-            result = copy_testing_data(this, srcData, bufferAlloc, bufferOffset, currentRowBytes,
-                                       config, currentRowBytes, currentRowBytes,
-                                       currentWidth, currentHeight, &color);
-        } else {
-            const size_t trimRowBytes = bpp * currentWidth;
-            if (!srcRowBytes) {
-                srcRowBytes = trimRowBytes;
-            }
+    bool result;
+    if (!srcData) {
+        result = fill_in_with_color(this, bufferAlloc, vkFormat, w, h, individualMipOffsets,
+                                    config, color);
+    } else {
+        SkASSERT(1 == mipLevels);
 
-            size_t currentRowBytes = bpp * currentWidth;
-            result = copy_testing_data(this, srcData, bufferAlloc, bufferOffset, srcRowBytes,
-                                       config, currentRowBytes, trimRowBytes,
-                                       currentWidth, currentHeight, &color);
-        }
-        if (!result) {
-            GrVkImage::DestroyImageInfo(this, info);
-            GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
-            VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
-            VK_CALL(EndCommandBuffer(cmdBuffer));
-            VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
-            return false;
-        }
-        currentWidth = SkTMax(1, currentWidth / 2);
-        currentHeight = SkTMax(1, currentHeight / 2);
+        result = copy_src_data(this, bufferAlloc, vkFormat, w, h, srcData, srcRowBytes);
     }
 
+    if (!result) {
+        GrVkImage::DestroyImageInfo(this, info);
+        GrVkMemory::FreeBufferMemory(this, GrVkBuffer::kCopyRead_Type, bufferAlloc);
+        VK_CALL(DestroyBuffer(fDevice, buffer, nullptr));
+        VK_CALL(EndCommandBuffer(cmdBuffer));
+        VK_CALL(FreeCommandBuffers(fDevice, fCmdPool->vkCommandPool(), 1, &cmdBuffer));
+        return false;
+    }
+
+
     // Set image layout and add barrier
     VkImageMemoryBarrier barrier;
     memset(&barrier, 0, sizeof(VkImageMemoryBarrier));
@@ -1694,8 +1665,8 @@
 
     SkTArray<VkBufferImageCopy> regions(mipLevels);
 
-    currentWidth = w;
-    currentHeight = h;
+    int currentWidth = w;
+    int currentHeight = h;
     for (uint32_t currentMipLevel = 0; currentMipLevel < mipLevels; currentMipLevel++) {
         // Submit copy command
         VkBufferImageCopy& region = regions.push_back();
diff --git a/src/gpu/vk/GrVkUtil.cpp b/src/gpu/vk/GrVkUtil.cpp
index 8787e50..338cc3b 100644
--- a/src/gpu/vk/GrVkUtil.cpp
+++ b/src/gpu/vk/GrVkUtil.cpp
@@ -304,7 +304,7 @@
             return 16;
 
         case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
-            return 8;
+            return 0;
 
         // Experimental (for P016 and P010)
         case VK_FORMAT_R16_UNORM:
@@ -332,6 +332,17 @@
     return false;
 }
 
+GrCompression GrVkFormat2Compression(VkFormat vkFormat) {
+    switch (vkFormat) {
+        case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
+            return GrCompression::kETC1;
+        default:
+            return GrCompression::kNone;
+    }
+    SK_ABORT("Invalid format");
+    return GrCompression::kNone;
+}
+
 size_t GrVkFormatCompressedDataSize(VkFormat vkFormat, int width, int height) {
     SkASSERT(GrVkFormatIsCompressed(vkFormat));
 
diff --git a/src/gpu/vk/GrVkUtil.h b/src/gpu/vk/GrVkUtil.h
index 35c13a7..06e052e 100644
--- a/src/gpu/vk/GrVkUtil.h
+++ b/src/gpu/vk/GrVkUtil.h
@@ -12,6 +12,7 @@
 #include "include/gpu/vk/GrVkTypes.h"
 #include "include/private/GrColor.h"
 #include "include/private/SkMacros.h"
+#include "src/gpu/GrDataUtils.h"
 #include "src/gpu/vk/GrVkInterface.h"
 #include "src/sksl/ir/SkSLProgram.h"
 
@@ -71,4 +72,9 @@
  */
 size_t GrVkFormatCompressedDataSize(VkFormat, int width, int height);
 
+/**
+ * Maps a vk format into the GrCompressed enum.
+ */
+GrCompression GrVkFormat2Compression(VkFormat);
+
 #endif