Reland "Remove code to push pixmaps to backend textures from GrGpu classes"

This is a reland of 45889d12696f8e0af2796a6bbd3938b6d2614eca

Original change's description:
> Remove code to push pixmaps to backend textures from GrGpu classes
>
> Replace GrGpu::updateBackendTexture with narrower method that clears
> a backend texture.
>
> Creation of data for a solid color compressed texture is lifted up to
> GrDirectContext and goes through updateCompressedBackendTexture.
>
> Bug: skia:11786
> Change-Id: I1d617623df5e65686f30e57c361a64f78d77f7bd
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/392836
> Reviewed-by: Jim Van Verth <jvanverth@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

Bug: skia:11786
Change-Id: Ibf85794a33e68acb17f0fb704f6815cd6460b3f2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/396098
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrDataUtils.cpp b/src/gpu/GrDataUtils.cpp
index ce8f7bb..e5a7adf 100644
--- a/src/gpu/GrDataUtils.cpp
+++ b/src/gpu/GrDataUtils.cpp
@@ -686,7 +686,7 @@
     return true;
 }
 
-bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, SkColor4f color) {
+bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, std::array<float, 4> color) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
 
     if (!dstInfo.isValid()) {
@@ -700,7 +700,7 @@
     }
     if (dstInfo.colorType() == GrColorType::kRGB_888) {
         // SkRasterPipeline doesn't handle writing to RGB_888. So we handle that specially here.
-        uint32_t rgba = color.toBytes_RGBA();
+        uint32_t rgba = SkColor4f{color[0], color[1], color[2], color[3]}.toBytes_RGBA();
         for (int y = 0; y < dstInfo.height(); ++y) {
             char* d = static_cast<char*>(dst) + y * dstRB;
             for (int x = 0; x < dstInfo.width(); ++x, d += 3) {
@@ -719,7 +719,7 @@
     char block[64];
     SkArenaAlloc alloc(block, sizeof(block), 1024);
     SkRasterPipeline_<256> pipeline;
-    pipeline.append_constant_color(&alloc, color);
+    pipeline.append_constant_color(&alloc, color.data());
     switch (lumMode) {
         case LumMode::kNone:
             break;
diff --git a/src/gpu/GrDataUtils.h b/src/gpu/GrDataUtils.h
index dbc9661..ff58246 100644
--- a/src/gpu/GrDataUtils.h
+++ b/src/gpu/GrDataUtils.h
@@ -39,7 +39,7 @@
 bool GrConvertPixels(const GrPixmap& dst, const GrCPixmap& src, bool flipY = false);
 
 /** Clears the dst image to a constant color. */
-bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, SkColor4f color);
+bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, std::array<float, 4> color);
 
 #if GR_TEST_UTILS
 /**
diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp
index 69f60c5..4b0a867 100644
--- a/src/gpu/GrDirectContext.cpp
+++ b/src/gpu/GrDirectContext.cpp
@@ -10,7 +10,9 @@
 
 #include "include/core/SkTraceMemoryDump.h"
 #include "include/gpu/GrContextThreadSafeProxy.h"
+#include "src/core/SkAutoMalloc.h"
 #include "src/core/SkTaskGroup.h"
+#include "src/gpu/GrBackendUtils.h"
 #include "src/gpu/GrClientMappedBufferManager.h"
 #include "src/gpu/GrContextThreadSafeProxyPriv.h"
 #include "src/gpu/GrDirectContextPriv.h"
@@ -472,26 +474,24 @@
     return this->createBackendTexture(width, height, format, mipMapped, renderable, isProtected);
 }
 
-static GrBackendTexture create_and_update_backend_texture(
-        GrDirectContext* dContext,
-        SkISize dimensions,
-        const GrBackendFormat& backendFormat,
-        GrMipmapped mipMapped,
-        GrRenderable renderable,
-        GrProtected isProtected,
-        sk_sp<GrRefCntedCallback> finishedCallback,
-        const GrGpu::BackendTextureData* data) {
+static GrBackendTexture create_and_clear_backend_texture(GrDirectContext* dContext,
+                                                         SkISize dimensions,
+                                                         const GrBackendFormat& backendFormat,
+                                                         GrMipmapped mipMapped,
+                                                         GrRenderable renderable,
+                                                         GrProtected isProtected,
+                                                         sk_sp<GrRefCntedCallback> finishedCallback,
+                                                         std::array<float, 4> color) {
     GrGpu* gpu = dContext->priv().getGpu();
-    SkASSERT(data->type() == GrGpu::BackendTextureData::Type::kColor);
     GrBackendTexture beTex = gpu->createBackendTexture(dimensions, backendFormat, renderable,
                                                        mipMapped, isProtected);
     if (!beTex.isValid()) {
         return {};
     }
 
-    if (!dContext->priv().getGpu()->updateBackendTexture(beTex,
-                                                         std::move(finishedCallback),
-                                                         data)) {
+    if (!dContext->priv().getGpu()->clearBackendTexture(beTex,
+                                                        std::move(finishedCallback),
+                                                        color)) {
         dContext->deleteBackendTexture(beTex);
         return {};
     }
@@ -555,10 +555,14 @@
         return {};
     }
 
-    GrGpu::BackendTextureData data(color);
-    return create_and_update_backend_texture(this, {width, height},
-                                             backendFormat, mipMapped, renderable, isProtected,
-                                             std::move(finishedCallback), &data);
+    return create_and_clear_backend_texture(this,
+                                            {width, height},
+                                            backendFormat,
+                                            mipMapped,
+                                            renderable,
+                                            isProtected,
+                                            std::move(finishedCallback),
+                                            color.array());
 }
 
 GrBackendTexture GrDirectContext::createBackendTexture(int width, int height,
@@ -583,10 +587,14 @@
     GrColorType grColorType = SkColorTypeToGrColorType(skColorType);
     SkColor4f swizzledColor = this->caps()->getWriteSwizzle(format, grColorType).applyTo(color);
 
-    GrGpu::BackendTextureData data(swizzledColor);
-    return create_and_update_backend_texture(this, {width, height}, format,
-                                             mipMapped, renderable, isProtected,
-                                             std::move(finishedCallback), &data);
+    return create_and_clear_backend_texture(this,
+                                            {width, height},
+                                            format,
+                                            mipMapped,
+                                            renderable,
+                                            isProtected,
+                                            std::move(finishedCallback),
+                                            swizzledColor.array());
 }
 
 GrBackendTexture GrDirectContext::createBackendTexture(const SkPixmap srcData[],
@@ -647,8 +655,7 @@
         return false;
     }
 
-    GrGpu::BackendTextureData data(color);
-    return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data);
+    return fGpu->clearBackendTexture(backendTexture, std::move(finishedCallback), color.array());
 }
 
 bool GrDirectContext::updateBackendTexture(const GrBackendTexture& backendTexture,
@@ -670,9 +677,11 @@
     }
 
     GrSwizzle swizzle = this->caps()->getWriteSwizzle(format, grColorType);
-    GrGpu::BackendTextureData data(swizzle.applyTo(color));
+    SkColor4f swizzledColor = swizzle.applyTo(color);
 
-    return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data);
+    return fGpu->clearBackendTexture(backendTexture,
+                                     std::move(finishedCallback),
+                                     swizzledColor.array());
 }
 
 bool GrDirectContext::updateBackendTexture(const GrBackendTexture& backendTexture,
@@ -717,7 +726,8 @@
         GrMipmapped mipMapped,
         GrProtected isProtected,
         sk_sp<GrRefCntedCallback> finishedCallback,
-        const GrGpu::BackendTextureData* data) {
+        const void* data,
+        size_t size) {
     GrGpu* gpu = dContext->priv().getGpu();
 
     GrBackendTexture beTex = gpu->createCompressedBackendTexture(dimensions, backendFormat,
@@ -727,20 +737,21 @@
     }
 
     if (!dContext->priv().getGpu()->updateCompressedBackendTexture(
-                beTex, std::move(finishedCallback), data)) {
+                beTex, std::move(finishedCallback), data, size)) {
         dContext->deleteBackendTexture(beTex);
         return {};
     }
     return beTex;
 }
 
-GrBackendTexture GrDirectContext::createCompressedBackendTexture(int width, int height,
-                                                             const GrBackendFormat& backendFormat,
-                                                             const SkColor4f& color,
-                                                             GrMipmapped mipMapped,
-                                                             GrProtected isProtected,
-                                                             GrGpuFinishedProc finishedProc,
-                                                             GrGpuFinishedContext finishedContext) {
+GrBackendTexture GrDirectContext::createCompressedBackendTexture(
+        int width, int height,
+        const GrBackendFormat& backendFormat,
+        const SkColor4f& color,
+        GrMipmapped mipmapped,
+        GrProtected isProtected,
+        GrGpuFinishedProc finishedProc,
+        GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
@@ -748,19 +759,35 @@
         return {};
     }
 
-    GrGpu::BackendTextureData data(color);
-    return create_and_update_compressed_backend_texture(this, {width, height},
-                                                        backendFormat, mipMapped, isProtected,
-                                                        std::move(finishedCallback), &data);
+    SkImage::CompressionType compression = GrBackendFormatToCompressionType(backendFormat);
+    if (compression == SkImage::CompressionType::kNone) {
+        return {};
+    }
+
+    size_t size = SkCompressedDataSize(compression,
+                                       {width, height},
+                                       nullptr,
+                                       mipmapped == GrMipmapped::kYes);
+    auto storage = std::make_unique<char[]>(size);
+    GrFillInCompressedData(compression, {width, height}, mipmapped, storage.get(), color);
+    return create_and_update_compressed_backend_texture(this,
+                                                        {width, height},
+                                                        backendFormat,
+                                                        mipmapped,
+                                                        isProtected,
+                                                        std::move(finishedCallback),
+                                                        storage.get(),
+                                                        size);
 }
 
-GrBackendTexture GrDirectContext::createCompressedBackendTexture(int width, int height,
-                                                             SkImage::CompressionType compression,
-                                                             const SkColor4f& color,
-                                                             GrMipmapped mipMapped,
-                                                             GrProtected isProtected,
-                                                             GrGpuFinishedProc finishedProc,
-                                                             GrGpuFinishedContext finishedContext) {
+GrBackendTexture GrDirectContext::createCompressedBackendTexture(
+        int width, int height,
+        SkImage::CompressionType compression,
+        const SkColor4f& color,
+        GrMipmapped mipMapped,
+        GrProtected isProtected,
+        GrGpuFinishedProc finishedProc,
+        GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     GrBackendFormat format = this->compressedBackendFormat(compression);
     return this->createCompressedBackendTexture(width, height, format, color,
@@ -768,14 +795,15 @@
                                                 finishedContext);
 }
 
-GrBackendTexture GrDirectContext::createCompressedBackendTexture(int width, int height,
-                                                             const GrBackendFormat& backendFormat,
-                                                             const void* compressedData,
-                                                             size_t dataSize,
-                                                             GrMipmapped mipMapped,
-                                                             GrProtected isProtected,
-                                                             GrGpuFinishedProc finishedProc,
-                                                             GrGpuFinishedContext finishedContext) {
+GrBackendTexture GrDirectContext::createCompressedBackendTexture(
+        int width, int height,
+        const GrBackendFormat& backendFormat,
+        const void* compressedData,
+        size_t dataSize,
+        GrMipmapped mipMapped,
+        GrProtected isProtected,
+        GrGpuFinishedProc finishedProc,
+        GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     auto finishedCallback = GrRefCntedCallback::Make(finishedProc, finishedContext);
 
@@ -783,19 +811,24 @@
         return {};
     }
 
-    GrGpu::BackendTextureData data(compressedData, dataSize);
-    return create_and_update_compressed_backend_texture(this, {width, height},
-                                                        backendFormat, mipMapped, isProtected,
-                                                        std::move(finishedCallback), &data);
+    return create_and_update_compressed_backend_texture(this,
+                                                        {width, height},
+                                                        backendFormat,
+                                                        mipMapped,
+                                                        isProtected,
+                                                        std::move(finishedCallback),
+                                                        compressedData,
+                                                        dataSize);
 }
 
-GrBackendTexture GrDirectContext::createCompressedBackendTexture(int width, int height,
-                                                             SkImage::CompressionType compression,
-                                                             const void* data, size_t dataSize,
-                                                             GrMipmapped mipMapped,
-                                                             GrProtected isProtected,
-                                                             GrGpuFinishedProc finishedProc,
-                                                             GrGpuFinishedContext finishedContext) {
+GrBackendTexture GrDirectContext::createCompressedBackendTexture(
+        int width, int height,
+        SkImage::CompressionType compression,
+        const void* data, size_t dataSize,
+        GrMipmapped mipMapped,
+        GrProtected isProtected,
+        GrGpuFinishedProc finishedProc,
+        GrGpuFinishedContext finishedContext) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     GrBackendFormat format = this->compressedBackendFormat(compression);
     return this->createCompressedBackendTexture(width, height, format, data, dataSize, mipMapped,
@@ -812,8 +845,25 @@
         return false;
     }
 
-    GrGpu::BackendTextureData data(color);
-    return fGpu->updateCompressedBackendTexture(backendTexture, std::move(finishedCallback), &data);
+    SkImage::CompressionType compression =
+            GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
+    if (compression == SkImage::CompressionType::kNone) {
+        return {};
+    }
+    size_t size = SkCompressedDataSize(compression,
+                                       backendTexture.dimensions(),
+                                       nullptr,
+                                       backendTexture.hasMipmaps());
+    SkAutoMalloc storage(size);
+    GrFillInCompressedData(compression,
+                           backendTexture.dimensions(),
+                           backendTexture.mipmapped(),
+                           static_cast<char*>(storage.get()),
+                           color);
+    return fGpu->updateCompressedBackendTexture(backendTexture,
+                                                std::move(finishedCallback),
+                                                storage.get(),
+                                                size);
 }
 
 bool GrDirectContext::updateCompressedBackendTexture(const GrBackendTexture& backendTexture,
@@ -831,9 +881,10 @@
         return false;
     }
 
-    GrGpu::BackendTextureData data(compressedData, dataSize);
-
-    return fGpu->updateCompressedBackendTexture(backendTexture, std::move(finishedCallback), &data);
+    return fGpu->updateCompressedBackendTexture(backendTexture,
+                                                std::move(finishedCallback),
+                                                compressedData,
+                                                dataSize);
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 22a0172..3d94791 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -755,58 +755,16 @@
 #endif // GR_GPU_STATS
 #endif // GR_TEST_UTILS
 
-bool GrGpu::MipMapsAreCorrect(SkISize dimensions,
-                              GrMipmapped mipmapped,
-                              const BackendTextureData* data) {
-    int numMipLevels = 1;
-    if (mipmapped == GrMipmapped::kYes) {
-        numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
-    }
-
-    if (!data || data->type() == BackendTextureData::Type::kColor) {
-        return true;
-    }
-
-    if (data->type() == BackendTextureData::Type::kCompressed) {
-        return false;  // This should be going through CompressedDataIsCorrect
-    }
-
-    SkASSERT(data->type() == BackendTextureData::Type::kPixmaps);
-
-    if (data->pixmap(0).dimensions() != dimensions) {
-        return false;
-    }
-
-    GrColorType colorType = data->pixmap(0).colorType();
-    for (int i = 1; i < numMipLevels; ++i) {
-        dimensions = {std::max(1, dimensions.width()/2), std::max(1, dimensions.height()/2)};
-        if (dimensions != data->pixmap(i).dimensions()) {
-            return false;
-        }
-        if (colorType != data->pixmap(i).colorType()) {
-            return false;
-        }
-    }
-    return true;
-}
-
-bool GrGpu::CompressedDataIsCorrect(SkISize dimensions, SkImage::CompressionType compressionType,
-                                    GrMipmapped mipMapped, const BackendTextureData* data) {
-
-    if (!data || data->type() == BackendTextureData::Type::kColor) {
-        return true;
-    }
-
-    if (data->type() == BackendTextureData::Type::kPixmaps) {
-        return false;
-    }
-
-    SkASSERT(data->type() == BackendTextureData::Type::kCompressed);
-
-    size_t computedSize = SkCompressedDataSize(compressionType, dimensions,
-                                               nullptr, mipMapped == GrMipmapped::kYes);
-
-    return computedSize == data->compressedSize();
+bool GrGpu::CompressedDataIsCorrect(SkISize dimensions,
+                                    SkImage::CompressionType compressionType,
+                                    GrMipmapped mipMapped,
+                                    const void* data,
+                                    size_t length) {
+    size_t computedSize = SkCompressedDataSize(compressionType,
+                                               dimensions,
+                                               nullptr,
+                                               mipMapped == GrMipmapped::kYes);
+    return computedSize == length;
 }
 
 GrBackendTexture GrGpu::createBackendTexture(SkISize dimensions,
@@ -837,33 +795,18 @@
     return this->onCreateBackendTexture(dimensions, format, renderable, mipMapped, isProtected);
 }
 
-bool GrGpu::updateBackendTexture(const GrBackendTexture& backendTexture,
-                                 sk_sp<GrRefCntedCallback> finishedCallback,
-                                 const BackendTextureData* data) {
-    SkASSERT(data);
-    const GrCaps* caps = this->caps();
-
+bool GrGpu::clearBackendTexture(const GrBackendTexture& backendTexture,
+                                sk_sp<GrRefCntedCallback> finishedCallback,
+                                std::array<float, 4> color) {
     if (!backendTexture.isValid()) {
         return false;
     }
 
-    if (data->type() == BackendTextureData::Type::kPixmaps) {
-        auto ct = data->pixmap(0).colorType();
-        if (!caps->areColorTypeAndFormatCompatible(ct, backendTexture.getBackendFormat())) {
-            return false;
-        }
-    }
-
     if (backendTexture.hasMipmaps() && !this->caps()->mipmapSupport()) {
         return false;
     }
 
-    GrMipmapped mipmapped = backendTexture.hasMipmaps() ? GrMipmapped::kYes : GrMipmapped::kNo;
-    if (!MipMapsAreCorrect(backendTexture.dimensions(), mipmapped, data)) {
-        return false;
-    }
-
-    return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data);
+    return this->onClearBackendTexture(backendTexture, std::move(finishedCallback), color);
 }
 
 GrBackendTexture GrGpu::createCompressedBackendTexture(SkISize dimensions,
@@ -897,7 +840,8 @@
 
 bool GrGpu::updateCompressedBackendTexture(const GrBackendTexture& backendTexture,
                                            sk_sp<GrRefCntedCallback> finishedCallback,
-                                           const BackendTextureData* data) {
+                                           const void* data,
+                                           size_t length) {
     SkASSERT(data);
 
     if (!backendTexture.isValid()) {
@@ -918,10 +862,16 @@
 
     GrMipmapped mipMapped = backendTexture.hasMipmaps() ? GrMipmapped::kYes : GrMipmapped::kNo;
 
-    if (!CompressedDataIsCorrect(backendTexture.dimensions(), compressionType, mipMapped, data)) {
+    if (!CompressedDataIsCorrect(backendTexture.dimensions(),
+                                 compressionType,
+                                 mipMapped,
+                                 data,
+                                 length)) {
         return false;
     }
 
-    return this->onUpdateCompressedBackendTexture(backendTexture, std::move(finishedCallback),
-                                                  data);
+    return this->onUpdateCompressedBackendTexture(backendTexture,
+                                                  std::move(finishedCallback),
+                                                  data,
+                                                  length);
 }
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 3c2b09d..498668c 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -498,58 +498,6 @@
     Stats* stats() { return &fStats; }
     void dumpJSON(SkJSONWriter*) const;
 
-    /** Used to initialize a backend texture with either a constant color, pixmaps or
-     *  compressed data.
-     */
-    class BackendTextureData {
-    public:
-        enum class Type { kColor, kPixmaps, kCompressed };
-        BackendTextureData() = default;
-        BackendTextureData(const SkColor4f& color) : fType(Type::kColor), fColor(color) {}
-        BackendTextureData(const GrPixmap pixmaps[]) : fType(Type::kPixmaps), fPixmaps(pixmaps) {
-            SkASSERT(pixmaps);
-        }
-        BackendTextureData(const void* data, size_t size) : fType(Type::kCompressed) {
-            SkASSERT(data);
-            fCompressed.fData = data;
-            fCompressed.fSize = size;
-        }
-
-        Type type() const { return fType; }
-        SkColor4f color() const {
-            SkASSERT(this->type() == Type::kColor);
-            return fColor;
-        }
-
-        const GrPixmap& pixmap(int i) const {
-            SkASSERT(this->type() == Type::kPixmaps);
-            return fPixmaps[i];
-        }
-        const GrPixmap* pixmaps() const {
-            SkASSERT(this->type() == Type::kPixmaps);
-            return fPixmaps;
-        }
-
-        const void* compressedData() const {
-            SkASSERT(this->type() == Type::kCompressed);
-            return fCompressed.fData;
-        }
-        size_t compressedSize() const {
-            SkASSERT(this->type() == Type::kCompressed);
-            return fCompressed.fSize;
-        }
-
-    private:
-        Type fType = Type::kColor;
-        union {
-            SkColor4f fColor = {0, 0, 0, 0};
-            const GrPixmap* fPixmaps;
-            struct {
-                const void*  fData;
-                size_t       fSize;
-            } fCompressed;
-        };
-    };
 
     /**
      * Creates a texture directly in the backend API without wrapping it in a GrTexture.
@@ -571,9 +519,9 @@
                                           GrMipmapped,
                                           GrProtected);
 
-    bool updateBackendTexture(const GrBackendTexture&,
-                              sk_sp<GrRefCntedCallback> finishedCallback,
-                              const BackendTextureData*);
+    bool clearBackendTexture(const GrBackendTexture&,
+                             sk_sp<GrRefCntedCallback> finishedCallback,
+                             std::array<float, 4> color);
 
     /**
      * Same as the createBackendTexture case except compressed backend textures can
@@ -586,7 +534,8 @@
 
     bool updateCompressedBackendTexture(const GrBackendTexture&,
                                         sk_sp<GrRefCntedCallback> finishedCallback,
-                                        const BackendTextureData*);
+                                        const void* data,
+                                        size_t length);
 
     virtual bool setBackendTextureState(const GrBackendTexture&,
                                         const GrBackendSurfaceMutableState&,
@@ -686,9 +635,11 @@
     virtual void xferBarrier(GrRenderTarget*, GrXferBarrierType) = 0;
 
 protected:
-    static bool MipMapsAreCorrect(SkISize dimensions, GrMipmapped, const BackendTextureData*);
-    static bool CompressedDataIsCorrect(SkISize dimensions, SkImage::CompressionType,
-                                        GrMipmapped, const BackendTextureData*);
+    static bool CompressedDataIsCorrect(SkISize dimensions,
+                                        SkImage::CompressionType,
+                                        GrMipmapped,
+                                        const void* data,
+                                        size_t length);
 
     // Handles cases where a surface will be updated without a call to flushRenderTarget.
     void didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds,
@@ -711,13 +662,14 @@
     virtual GrBackendTexture onCreateCompressedBackendTexture(
             SkISize dimensions, const GrBackendFormat&, GrMipmapped, GrProtected) = 0;
 
-    virtual bool onUpdateBackendTexture(const GrBackendTexture&,
-                                        sk_sp<GrRefCntedCallback> finishedCallback,
-                                        const BackendTextureData*) = 0;
+    virtual bool onClearBackendTexture(const GrBackendTexture&,
+                                       sk_sp<GrRefCntedCallback> finishedCallback,
+                                       std::array<float, 4> color) = 0;
 
     virtual bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                                   sk_sp<GrRefCntedCallback> finishedCallback,
-                                                  const BackendTextureData*) = 0;
+                                                  const void* data,
+                                                  size_t length) = 0;
 
     // called when the 3D context state is unknown. Subclass should emit any
     // assumed 3D context state and dirty any state cache.
diff --git a/src/gpu/d3d/GrD3DGpu.cpp b/src/gpu/d3d/GrD3DGpu.cpp
index ee8a73b..0dafd83 100644
--- a/src/gpu/d3d/GrD3DGpu.cpp
+++ b/src/gpu/d3d/GrD3DGpu.cpp
@@ -996,32 +996,12 @@
     return GrBackendTexture(dimensions.width(), dimensions.height(), info);
 }
 
-static void copy_src_data(char* mapPtr,
-                          DXGI_FORMAT dxgiFormat,
-                          D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
-                          const GrPixmap srcData[],
-                          int numMipLevels) {
-    SkASSERT(srcData && numMipLevels);
-    SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
-    SkASSERT(mapPtr);
-
-    size_t bytesPerPixel = GrDxgiFormatBytesPerBlock(dxgiFormat);
-
-    for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
-        const size_t trimRowBytes = srcData[currentMipLevel].width() * bytesPerPixel;
-
-        // copy data into the buffer, skipping any trailing bytes
-        char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
-        SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
-                     srcData[currentMipLevel].addr(), srcData[currentMipLevel].rowBytes(),
-                     trimRowBytes, srcData[currentMipLevel].height());
-    }
-}
-
-static bool copy_color_data(const GrD3DCaps& caps, char* mapPtr,
-                            DXGI_FORMAT dxgiFormat, SkISize dimensions,
+static bool copy_color_data(const GrD3DCaps& caps,
+                            char* mapPtr,
+                            DXGI_FORMAT dxgiFormat,
+                            SkISize dimensions,
                             D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
-                            SkColor4f color) {
+                            std::array<float, 4> color) {
     auto colorType = caps.getFormatColorType(dxgiFormat);
     if (colorType == GrColorType::kUnknown) {
         return false;
@@ -1034,11 +1014,12 @@
     return true;
 }
 
-bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
-                                      sk_sp<GrRefCntedCallback> finishedCallback,
-                                      const BackendTextureData* data) {
+bool GrD3DGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
+                                     sk_sp<GrRefCntedCallback> finishedCallback,
+                                     std::array<float, 4> color) {
     GrD3DTextureResourceInfo info;
     SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
+    SkASSERT(!GrDxgiFormatIsCompressed(info.fFormat));
 
     sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
     SkASSERT(state);
@@ -1062,27 +1043,23 @@
     D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
     unsigned int mipLevelCount = 1;
     if (backendTexture.fMipmapped == GrMipmapped::kYes) {
-        mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions().width(),
-                                                    backendTexture.dimensions().height()) + 1;
+        mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions()) + 1;
     }
     SkASSERT(mipLevelCount == info.fLevelCount);
-    SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
+    SkAutoSTMalloc<15, D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
+    UINT numRows;
+    UINT64 rowSizeInBytes;
     UINT64 combinedBufferSize;
-    SkAutoTMalloc<UINT> numRows(mipLevelCount);
-    SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
-    fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
-                                   numRows.get(), rowSizeInBytes.get(), &combinedBufferSize);
+    // We reuse the same top-level buffer area for all levels, hence passing 1 for level count.
+    fDevice->GetCopyableFootprints(&desc,
+                                   /* first resource  */ 0,
+                                   /* mip level count */ 1,
+                                   /* base offset     */ 0,
+                                   placedFootprints.get(),
+                                   &numRows,
+                                   &rowSizeInBytes,
+                                   &combinedBufferSize);
     SkASSERT(combinedBufferSize);
-    if (data->type() == BackendTextureData::Type::kColor &&
-        !GrDxgiFormatIsCompressed(info.fFormat) && mipLevelCount > 1) {
-        // For a single uncompressed color, we reuse the same top-level buffer area for all levels.
-        combinedBufferSize =
-                placedFootprints[0].Footprint.RowPitch * placedFootprints[0].Footprint.Height;
-        for (unsigned int i = 1; i < mipLevelCount; ++i) {
-            placedFootprints[i].Offset = 0;
-            placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
-        }
-    }
 
     GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
             combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
@@ -1092,42 +1069,37 @@
 
     char* bufferData = (char*)slice.fOffsetMapPtr;
     SkASSERT(bufferData);
-
-    if (data->type() == BackendTextureData::Type::kPixmaps) {
-        copy_src_data(bufferData, info.fFormat, placedFootprints.get(), data->pixmaps(),
-                      info.fLevelCount);
-    } else if (data->type() == BackendTextureData::Type::kCompressed) {
-        copy_compressed_data(bufferData, info.fFormat, placedFootprints.get(), numRows.get(),
-                             rowSizeInBytes.get(), data->compressedData(), info.fLevelCount);
-    } else {
-        SkASSERT(data->type() == BackendTextureData::Type::kColor);
-        SkImage::CompressionType compression =
-                GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
-        if (SkImage::CompressionType::kNone == compression) {
-            if (!copy_color_data(this->d3dCaps(), bufferData, info.fFormat,
-                                 backendTexture.dimensions(), placedFootprints, data->color())) {
-              return false;
-            }
-        } else {
-            size_t totalCompressedSize = SkCompressedFormatDataSize(compression,
-                                                                    backendTexture.dimensions(),
-                                                                    backendTexture.hasMipmaps());
-            SkAutoTMalloc<char> tempData(totalCompressedSize);
-            GrFillInCompressedData(compression, backendTexture.dimensions(),
-                                   backendTexture.fMipmapped, tempData, data->color());
-            copy_compressed_data(bufferData, info.fFormat, placedFootprints.get(), numRows.get(),
-                                 rowSizeInBytes.get(), tempData.get(), info.fLevelCount);
-        }
+    if (!copy_color_data(this->d3dCaps(),
+                         bufferData,
+                         info.fFormat,
+                         backendTexture.dimensions(),
+                         placedFootprints,
+                         color)) {
+        return false;
     }
-
-    // Update the offsets in the footprints to be relative to the slice's offset
-    for (unsigned int i = 0; i < mipLevelCount; ++i) {
-        placedFootprints[i].Offset += slice.fOffset;
+    // Update the offsets in the footprint to be relative to the slice's offset
+    placedFootprints[0].Offset += slice.fOffset;
+    // Since we're sharing data for all the levels, set all the upper level footprints to the base.
+    UINT w = placedFootprints[0].Footprint.Width;
+    UINT h = placedFootprints[0].Footprint.Height;
+    for (unsigned int i = 1; i < mipLevelCount; ++i) {
+        w = std::max(1U, w/2);
+        h = std::max(1U, h/2);
+        placedFootprints[i].Offset = placedFootprints[0].Offset;
+        placedFootprints[i].Footprint.Format   = placedFootprints[0].Footprint.Format;
+        placedFootprints[i].Footprint.Width    = w;
+        placedFootprints[i].Footprint.Height   = h;
+        placedFootprints[i].Footprint.Depth    = 1;
+        placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
     }
 
     ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
-    cmdList->copyBufferToTexture(d3dBuffer, texture.get(), mipLevelCount, placedFootprints.get(), 0,
-                                 0);
+    cmdList->copyBufferToTexture(d3dBuffer,
+                                 texture.get(),
+                                 mipLevelCount,
+                                 placedFootprints.get(),
+                                 /*left*/ 0,
+                                 /*top */ 0);
 
     if (finishedCallback) {
         this->addFinishedCallback(std::move(finishedCallback));
@@ -1145,8 +1117,88 @@
 
 bool GrD3DGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
                                                 sk_sp<GrRefCntedCallback> finishedCallback,
-                                                const BackendTextureData* data) {
-    return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data);
+                                                const void* data,
+                                                size_t size) {
+    GrD3DTextureResourceInfo info;
+    SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
+
+    sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
+    SkASSERT(state);
+    sk_sp<GrD3DTexture> texture = GrD3DTexture::MakeWrappedTexture(this,
+                                                                   backendTexture.dimensions(),
+                                                                   GrWrapCacheable::kNo,
+                                                                   kRW_GrIOType,
+                                                                   info,
+                                                                   std::move(state));
+    if (!texture) {
+        return false;
+    }
+
+    GrD3DDirectCommandList* cmdList = this->currentCommandList();
+    if (!cmdList) {
+        return false;
+    }
+
+    texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
+
+    ID3D12Resource* d3dResource = texture->d3dResource();
+    SkASSERT(d3dResource);
+    D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
+    unsigned int mipLevelCount = 1;
+    if (backendTexture.hasMipmaps()) {
+        mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions().width(),
+                                                    backendTexture.dimensions().height()) + 1;
+    }
+    SkASSERT(mipLevelCount == info.fLevelCount);
+    SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
+    UINT64 combinedBufferSize;
+    SkAutoTMalloc<UINT> numRows(mipLevelCount);
+    SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
+    fDevice->GetCopyableFootprints(&desc,
+                                   0,
+                                   mipLevelCount,
+                                   0,
+                                   placedFootprints.get(),
+                                   numRows.get(),
+                                   rowSizeInBytes.get(),
+                                   &combinedBufferSize);
+    SkASSERT(combinedBufferSize);
+    SkASSERT(GrDxgiFormatIsCompressed(info.fFormat));
+
+    GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
+            combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
+    if (!slice.fBuffer) {
+        return false;
+    }
+
+    char* bufferData = (char*)slice.fOffsetMapPtr;
+    SkASSERT(bufferData);
+    copy_compressed_data(bufferData,
+                         info.fFormat,
+                         placedFootprints.get(),
+                         numRows.get(),
+                         rowSizeInBytes.get(),
+                         data,
+                         info.fLevelCount);
+
+    // Update the offsets in the footprints to be relative to the slice's offset
+    for (unsigned int i = 0; i < mipLevelCount; ++i) {
+        placedFootprints[i].Offset += slice.fOffset;
+    }
+
+    ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
+    cmdList->copyBufferToTexture(d3dBuffer,
+                                 texture.get(),
+                                 mipLevelCount,
+                                 placedFootprints.get(),
+                                 0,
+                                 0);
+
+    if (finishedCallback) {
+        this->addFinishedCallback(std::move(finishedCallback));
+    }
+
+    return true;
 }
 
 void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
diff --git a/src/gpu/d3d/GrD3DGpu.h b/src/gpu/d3d/GrD3DGpu.h
index fe952b8..7b6db87 100644
--- a/src/gpu/d3d/GrD3DGpu.h
+++ b/src/gpu/d3d/GrD3DGpu.h
@@ -218,9 +218,9 @@
                                             GrMipmapped,
                                             GrProtected) override;
 
-    bool onUpdateBackendTexture(const GrBackendTexture&,
-                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                const BackendTextureData*) override;
+    bool onClearBackendTexture(const GrBackendTexture&,
+                               sk_sp<GrRefCntedCallback> finishedCallback,
+                               std::array<float, 4> color) override;
 
     GrBackendTexture onCreateCompressedBackendTexture(SkISize dimensions,
                                                       const GrBackendFormat&,
@@ -229,7 +229,8 @@
 
     bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                           sk_sp<GrRefCntedCallback> finishedCallback,
-                                          const BackendTextureData*) override;
+                                          const void* data,
+                                          size_t size) override;
 
     bool submitDirectCommandList(SyncQueue sync);
 
diff --git a/src/gpu/dawn/GrDawnGpu.cpp b/src/gpu/dawn/GrDawnGpu.cpp
index 9411efc..5c19f55 100644
--- a/src/gpu/dawn/GrDawnGpu.cpp
+++ b/src/gpu/dawn/GrDawnGpu.cpp
@@ -383,35 +383,23 @@
     }
 }
 
-bool GrDawnGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
-                                       sk_sp<GrRefCntedCallback> finishedCallback,
-                                       const BackendTextureData* data) {
+bool GrDawnGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
+                                      sk_sp<GrRefCntedCallback> finishedCallback,
+                                      std::array<float, 4> color) {
     GrDawnTextureInfo info;
     SkAssertResult(backendTexture.getDawnTextureInfo(&info));
 
-    size_t bpp = GrDawnBytesPerBlock(info.fFormat);
-    size_t baseLayerSize = bpp * backendTexture.width() * backendTexture.height();
-    const void* pixels;
-    SkAutoMalloc defaultStorage(baseLayerSize);
-    if (data && data->type() == BackendTextureData::Type::kPixmaps) {
-        int numMipLevels = info.fLevelCount;
-        SkAutoTArray<GrMipLevel> texels(numMipLevels);
-        GrColorType colorType = data->pixmap(0).colorType();
-        for (int i = 0; i < numMipLevels; ++i) {
-            texels[i] = {data->pixmap(i).addr(), data->pixmap(i).rowBytes(), nullptr};
-        }
-        SkIRect dstRect = SkIRect::MakeSize(backendTexture.dimensions());
-        this->uploadTextureData(colorType, texels.get(), numMipLevels, dstRect, info.fTexture);
-        return true;
-    }
-    pixels = defaultStorage.get();
     GrColorType colorType;
     if (!GrDawnFormatToGrColorType(info.fFormat, &colorType)) {
         return false;
     }
-    SkISize size{backendTexture.width(), backendTexture.height()};
-    GrImageInfo imageInfo(colorType, kUnpremul_SkAlphaType, nullptr, size);
-    GrClearImage(imageInfo, defaultStorage.get(), bpp * backendTexture.width(), data->color());
+
+    size_t bpp = GrDawnBytesPerBlock(info.fFormat);
+    size_t baseLayerSize = bpp * backendTexture.width() * backendTexture.height();
+    SkAutoMalloc defaultStorage(baseLayerSize);
+    GrImageInfo imageInfo(colorType, kUnpremul_SkAlphaType, nullptr, backendTexture.dimensions());
+    GrClearImage(imageInfo, defaultStorage.get(), bpp * backendTexture.width(), color);
+
     wgpu::Device device = this->device();
     wgpu::CommandEncoder copyEncoder = this->getCopyEncoder();
     int w = backendTexture.width(), h = backendTexture.height();
@@ -422,9 +410,9 @@
         GrStagingBufferManager::Slice stagingBuffer =
                 this->stagingBufferManager()->allocateStagingBufferSlice(size);
         if (rowBytes == origRowBytes) {
-            memcpy(stagingBuffer.fOffsetMapPtr, pixels, size);
+            memcpy(stagingBuffer.fOffsetMapPtr, defaultStorage.get(), size);
         } else {
-            const char* src = static_cast<const char*>(pixels);
+            const char* src = static_cast<const char*>(defaultStorage.get());
             char* dst = static_cast<char*>(stagingBuffer.fOffsetMapPtr);
             for (int row = 0; row < h; row++) {
                 memcpy(dst, src, origRowBytes);
@@ -456,7 +444,8 @@
 
 bool GrDawnGpu::onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                                  sk_sp<GrRefCntedCallback> finishedCallback,
-                                                 const BackendTextureData*) {
+                                                 const void* data,
+                                                 size_t size) {
     return false;
 }
 
diff --git a/src/gpu/dawn/GrDawnGpu.h b/src/gpu/dawn/GrDawnGpu.h
index 5959a16..f1b34b4 100644
--- a/src/gpu/dawn/GrDawnGpu.h
+++ b/src/gpu/dawn/GrDawnGpu.h
@@ -144,9 +144,9 @@
                                             GrMipmapped,
                                             GrProtected) override;
 
-    bool onUpdateBackendTexture(const GrBackendTexture&,
-                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                const BackendTextureData*) override;
+    bool onClearBackendTexture(const GrBackendTexture&,
+                               sk_sp<GrRefCntedCallback> finishedCallback,
+                               std::array<float, 4> color) override;
 
     GrBackendTexture onCreateCompressedBackendTexture(SkISize dimensions,
                                                       const GrBackendFormat&,
@@ -155,7 +155,8 @@
 
     bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                           sk_sp<GrRefCntedCallback> finishedCallback,
-                                          const BackendTextureData*) override;
+                                          const void* data,
+                                          size_t size) override;
 
     sk_sp<GrGpuBuffer> onCreateBuffer(size_t size, GrGpuBufferType type, GrAccessPattern,
                                       const void* data) override;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 8e1e5fd..bf1f3d9 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -980,7 +980,7 @@
 bool GrGLGpu::uploadColorToTex(GrGLFormat textureFormat,
                                SkISize texDims,
                                GrGLenum target,
-                               SkColor4f color,
+                               std::array<float, 4> color,
                                uint32_t levelMask) {
     GrColorType colorType;
     GrGLenum externalFormat, externalType;
@@ -1386,8 +1386,11 @@
             fHWBoundRenderTargetUniqueID.makeInvalid();
         } else {
             this->bindTextureToScratchUnit(texDesc.fTarget, tex->textureID());
-            static constexpr SkColor4f kZeroColor = {0, 0, 0, 0};
-            this->uploadColorToTex(texDesc.fFormat, texDesc.fSize, texDesc.fTarget, kZeroColor,
+            std::array<float, 4> zeros = {};
+            this->uploadColorToTex(texDesc.fFormat,
+                                   texDesc.fSize,
+                                   texDesc.fTarget,
+                                   zeros,
                                    levelClearMask);
         }
     }
@@ -1482,11 +1485,8 @@
 
 bool GrGLGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
                                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                               const BackendTextureData* data) {
-    SkASSERT(data && data->type() != BackendTextureData::Type::kPixmaps);
-
-    this->handleDirtyContext();
-
+                                               const void* data,
+                                               size_t length) {
     GrGLTextureInfo info;
     SkAssertResult(backendTexture.getGLTextureInfo(&info));
 
@@ -1499,27 +1499,6 @@
 
     GrMipmapped mipMapped = backendTexture.hasMipmaps() ? GrMipmapped::kYes : GrMipmapped::kNo;
 
-    const char* rawData = nullptr;
-    size_t rawDataSize = 0;
-    SkAutoMalloc am;
-    if (data->type() == BackendTextureData::Type::kCompressed) {
-        rawData = (const char*)data->compressedData();
-        rawDataSize = data->compressedSize();
-    } else {
-        SkASSERT(data->type() == BackendTextureData::Type::kColor);
-        SkASSERT(compression != SkImage::CompressionType::kNone);
-
-        rawDataSize = SkCompressedDataSize(compression, backendTexture.dimensions(), nullptr,
-                                           backendTexture.hasMipmaps());
-
-        am.reset(rawDataSize);
-
-        GrFillInCompressedData(compression, backendTexture.dimensions(), mipMapped, (char*)am.get(),
-                               data->color());
-
-        rawData = (const char*)am.get();
-    }
-
     this->bindTextureToScratchUnit(info.fTarget, info.fID);
 
     // If we have mips make sure the base level is set to 0 and the max level set to numMipLevels-1
@@ -1540,9 +1519,13 @@
         params->set(nullptr, nonsamplerState, fResetTimestampForTextureParameters);
     }
 
-    bool result = this->uploadCompressedTexData(
-            compression, glFormat, backendTexture.dimensions(),  mipMapped, GR_GL_TEXTURE_2D,
-            rawData, rawDataSize);
+    bool result = this->uploadCompressedTexData(compression,
+                                                glFormat,
+                                                backendTexture.dimensions(),
+                                                mipMapped,
+                                                GR_GL_TEXTURE_2D,
+                                                data,
+                                                length);
 
     // Unbind this texture from the scratch texture unit.
     this->bindTextureToScratchUnit(info.fTarget, 0);
@@ -3618,9 +3601,9 @@
                             std::move(parameters));
 }
 
-bool GrGLGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
-                                     sk_sp<GrRefCntedCallback> finishedCallback,
-                                     const BackendTextureData* data) {
+bool GrGLGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
+                                    sk_sp<GrRefCntedCallback> finishedCallback,
+                                    std::array<float, 4> color) {
     this->handleDirtyContext();
 
     GrGLTextureInfo info;
@@ -3652,26 +3635,12 @@
         params->set(nullptr, nonsamplerState, fResetTimestampForTextureParameters);
     }
 
-    SkASSERT(data->type() != BackendTextureData::Type::kCompressed);
-    bool result = false;
-    if (data->type() == BackendTextureData::Type::kPixmaps) {
-        SkTArray<GrMipLevel> texels;
-        texels.push_back_n(numMipLevels);
-        GrColorType colorType = data->pixmap(0).colorType();
-        for (int i = 0; i < numMipLevels; ++i) {
-            texels[i] = {data->pixmap(i).addr(),
-                         data->pixmap(i).rowBytes(),
-                         data->pixmap(i).pixelStorage()};
-        }
-        SkIRect dstRect = SkIRect::MakeSize(backendTexture.dimensions());
-        result = this->uploadColorTypeTexData(glFormat, colorType, backendTexture.dimensions(),
-                                              info.fTarget, dstRect, colorType, texels.begin(),
-                                              texels.count());
-    } else if (data->type() == BackendTextureData::Type::kColor) {
-        uint32_t levelMask = (1 << numMipLevels) - 1;
-        result = this->uploadColorToTex(glFormat, backendTexture.dimensions(), info.fTarget,
-                                        data->color(), levelMask);
-    }
+    uint32_t levelMask = (1 << numMipLevels) - 1;
+    bool result = this->uploadColorToTex(glFormat,
+                                         backendTexture.dimensions(),
+                                         info.fTarget,
+                                         color,
+                                         levelMask);
 
     // Unbind this texture from the scratch texture unit.
     this->bindTextureToScratchUnit(info.fTarget, 0);
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 0a47a9d..9494930 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -212,13 +212,14 @@
                                                       GrMipmapped,
                                                       GrProtected) override;
 
-    bool onUpdateBackendTexture(const GrBackendTexture&,
-                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                const BackendTextureData*) override;
+    bool onClearBackendTexture(const GrBackendTexture&,
+                               sk_sp<GrRefCntedCallback> finishedCallback,
+                               std::array<float, 4> color) override;
 
     bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                           sk_sp<GrRefCntedCallback> finishedCallback,
-                                          const BackendTextureData*) override;
+                                          const void* data,
+                                          size_t length) override;
 
     void onResetContext(uint32_t resetBits) override;
 
@@ -454,7 +455,7 @@
     bool uploadColorToTex(GrGLFormat textureFormat,
                           SkISize texDims,
                           GrGLenum target,
-                          SkColor4f color,
+                          std::array<float, 4> color,
                           uint32_t levelMask);
 
     // Pushes data to the currently bound texture to the currently active unit. 'dstRect' must be
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 085191f..05064a1 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -165,9 +165,9 @@
                                             GrMipmapped,
                                             GrProtected) override;
 
-    bool onUpdateBackendTexture(const GrBackendTexture&,
-                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                const BackendTextureData*) override {
+    bool onClearBackendTexture(const GrBackendTexture&,
+                               sk_sp<GrRefCntedCallback> finishedCallback,
+                               std::array<float, 4> color) override {
         return true;
     }
 
@@ -178,7 +178,8 @@
 
     bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                           sk_sp<GrRefCntedCallback> finishedCallback,
-                                          const BackendTextureData*) override {
+                                          const void*,
+                                          size_t) override {
         return true;
     }
 
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 5370da2..4502050 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -131,9 +131,9 @@
                                             GrMipmapped,
                                             GrProtected) override;
 
-    bool onUpdateBackendTexture(const GrBackendTexture&,
-                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                const BackendTextureData*) override;
+    bool onClearBackendTexture(const GrBackendTexture&,
+                               sk_sp<GrRefCntedCallback> finishedCallback,
+                               std::array<float, 4> color) override;
 
     GrBackendTexture onCreateCompressedBackendTexture(SkISize dimensions,
                                                       const GrBackendFormat&,
@@ -142,7 +142,8 @@
 
     bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                           sk_sp<GrRefCntedCallback> finishedCallback,
-                                          const BackendTextureData*) override;
+                                          const void* data,
+                                          size_t size) override;
 
     sk_sp<GrTexture> onCreateTexture(SkISize,
                                      const GrBackendFormat&,
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 93c042a..c28a15f 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -947,9 +947,9 @@
     return backendTex;
 }
 
-bool GrMtlGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
-                                      sk_sp<GrRefCntedCallback> finishedCallback,
-                                      const BackendTextureData* data) {
+bool GrMtlGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
+                                     sk_sp<GrRefCntedCallback> finishedCallback,
+                                     std::array<float, 4> color) {
     GrMtlTextureInfo info;
     SkAssertResult(backendTexture.getMtlTextureInfo(&info));
 
@@ -957,45 +957,19 @@
 
     const MTLPixelFormat mtlFormat = mtlTexture.pixelFormat;
 
-    int numMipLevels = mtlTexture.mipmapLevelCount;
-    GrMipmapped mipMapped = numMipLevels > 1 ? GrMipmapped::kYes : GrMipmapped::kNo;
-
-    SkImage::CompressionType compression = GrBackendFormatToCompressionType(
-            backendTexture.getBackendFormat());
-
     // Create a transfer buffer and fill with data.
     size_t bytesPerPixel = GrMtlFormatBytesPerBlock(mtlFormat);
-    SkSTArray<16, size_t> individualMipOffsets;
     size_t combinedBufferSize;
 
-    if (data->type() == BackendTextureData::Type::kColor &&
-        compression == SkImage::CompressionType::kNone) {
-        combinedBufferSize = bytesPerPixel*backendTexture.width()*backendTexture.height();
-        // Reuse the same buffer for all levels. Should be ok since we made the row bytes tight.
-        individualMipOffsets.push_back_n(numMipLevels, (size_t)0);
-    } else if (compression == SkImage::CompressionType::kNone) {
-        combinedBufferSize = GrComputeTightCombinedBufferSize(bytesPerPixel,
-                                                              backendTexture.dimensions(),
-                                                              &individualMipOffsets,
-                                                              numMipLevels);
-    } else {
-        combinedBufferSize = SkCompressedDataSize(compression, backendTexture.dimensions(),
-                                                  &individualMipOffsets,
-                                                  mipMapped == GrMipmapped::kYes);
-    }
-    SkASSERT(individualMipOffsets.count() == numMipLevels);
+    // Reuse the same buffer for all levels. Should be ok since we made the row bytes tight.
+    combinedBufferSize = bytesPerPixel*backendTexture.width()*backendTexture.height();
 
 #ifdef SK_BUILD_FOR_MAC
     static const size_t kMinAlignment = 4;
 #else
     static const size_t kMinAlignment = 1;
 #endif
-    size_t alignment;
-    if (data->type() == BackendTextureData::Type::kCompressed) {
-        alignment = std::max(SkCompressedBlockSize(compression), kMinAlignment);
-    } else {
-        alignment = std::max(bytesPerPixel, kMinAlignment);
-    }
+    size_t alignment = std::max(bytesPerPixel, kMinAlignment);
     GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
             combinedBufferSize, alignment);
     if (!slice.fBuffer) {
@@ -1003,28 +977,15 @@
     }
     char* buffer = (char*)slice.fOffsetMapPtr;
 
-    if (data->type() == BackendTextureData::Type::kPixmaps) {
-        copy_src_data(buffer, bytesPerPixel, individualMipOffsets, data->pixmaps(),
-                      numMipLevels, combinedBufferSize);
-    } else if (data->type() == BackendTextureData::Type::kCompressed) {
-        memcpy(buffer, data->compressedData(), data->compressedSize());
-    } else {
-        SkASSERT(data->type() == BackendTextureData::Type::kColor);
-        if (compression == SkImage::CompressionType::kNone) {
-            auto colorType = mtl_format_to_backend_tex_clear_colortype(mtlFormat);
-            if (colorType == GrColorType::kUnknown) {
-                return false;
-            }
-            GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, backendTexture.dimensions());
-            auto rb = ii.minRowBytes();
-            SkASSERT(rb == bytesPerPixel*backendTexture.width());
-            if (!GrClearImage(ii, buffer, rb, data->color())) {
-                return false;
-            }
-        } else {
-            GrFillInCompressedData(compression, backendTexture.dimensions(), mipMapped, buffer,
-                                   data->color());
-        }
+    auto colorType = mtl_format_to_backend_tex_clear_colortype(mtlFormat);
+    if (colorType == GrColorType::kUnknown) {
+        return false;
+    }
+    GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, backendTexture.dimensions());
+    auto rb = ii.minRowBytes();
+    SkASSERT(rb == bytesPerPixel*backendTexture.width());
+    if (!GrClearImage(ii, buffer, rb, color)) {
+        return false;
     }
 
     // Transfer buffer contents to texture
@@ -1035,32 +996,29 @@
     GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
 
     SkISize levelDimensions(backendTexture.dimensions());
+    int numMipLevels = mtlTexture.mipmapLevelCount;
     for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
         size_t levelRowBytes;
         size_t levelSize;
 
-        if (compression == SkImage::CompressionType::kNone) {
-            levelRowBytes = levelDimensions.width() * bytesPerPixel;
-            levelSize = levelRowBytes * levelDimensions.height();
-        } else {
-            levelRowBytes = GrCompressedRowBytes(compression, levelDimensions.width());
-            levelSize = SkCompressedDataSize(compression, levelDimensions, nullptr, false);
-        }
+        levelRowBytes = levelDimensions.width() * bytesPerPixel;
+        levelSize = levelRowBytes * levelDimensions.height();
 
         // TODO: can this all be done in one go?
         [blitCmdEncoder copyFromBuffer: mtlBuffer->mtlBuffer()
-                          sourceOffset: slice.fOffset + individualMipOffsets[currentMipLevel]
+                          sourceOffset: slice.fOffset
                      sourceBytesPerRow: levelRowBytes
                    sourceBytesPerImage: levelSize
                             sourceSize: MTLSizeMake(levelDimensions.width(),
-                                                    levelDimensions.height(), 1)
+                                                    levelDimensions.height(),
+                                                    1)
                              toTexture: mtlTexture
                       destinationSlice: 0
                       destinationLevel: currentMipLevel
                      destinationOrigin: origin];
 
-        levelDimensions = { std::max(1, levelDimensions.width() / 2),
-                            std::max(1, levelDimensions.height() / 2) };
+        levelDimensions = {std::max(1, levelDimensions.width() / 2),
+                           std::max(1, levelDimensions.height() / 2)};
     }
 #ifdef SK_BUILD_FOR_MAC
     [mtlBuffer->mtlBuffer() didModifyRange: NSMakeRange(slice.fOffset, combinedBufferSize)];
@@ -1089,8 +1047,84 @@
 
 bool GrMtlGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
                                                 sk_sp<GrRefCntedCallback> finishedCallback,
-                                                const BackendTextureData* data) {
-    return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data);
+                                                const void* data,
+                                                size_t size) {
+    GrMtlTextureInfo info;
+    SkAssertResult(backendTexture.getMtlTextureInfo(&info));
+
+    id<MTLTexture> mtlTexture = GrGetMTLTexture(info.fTexture.get());
+
+    int numMipLevels = mtlTexture.mipmapLevelCount;
+    GrMipmapped mipMapped = numMipLevels > 1 ? GrMipmapped::kYes : GrMipmapped::kNo;
+
+    SkImage::CompressionType compression =
+            GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
+    SkASSERT(compression != SkImage::CompressionType::kNone);
+
+    // Create a transfer buffer and fill with data.
+    SkSTArray<16, size_t> individualMipOffsets;
+    size_t combinedBufferSize;
+    combinedBufferSize = SkCompressedDataSize(compression,
+                                              backendTexture.dimensions(),
+                                              &individualMipOffsets,
+                                              mipMapped == GrMipmapped::kYes);
+    SkASSERT(individualMipOffsets.count() == numMipLevels);
+
+#ifdef SK_BUILD_FOR_MAC
+    static const size_t kMinAlignment = 4;
+#else
+    static const size_t kMinAlignment = 1;
+#endif
+    size_t alignment = std::max(SkCompressedBlockSize(compression), kMinAlignment);
+    GrStagingBufferManager::Slice slice =
+            fStagingBufferManager.allocateStagingBufferSlice(combinedBufferSize, alignment);
+    if (!slice.fBuffer) {
+        return false;
+    }
+    char* buffer = (char*)slice.fOffsetMapPtr;
+
+    memcpy(buffer, data, size);
+
+    // Transfer buffer contents to texture
+    MTLOrigin origin = MTLOriginMake(0, 0, 0);
+
+    GrMtlCommandBuffer* cmdBuffer = this->commandBuffer();
+    id<MTLBlitCommandEncoder> blitCmdEncoder = cmdBuffer->getBlitCommandEncoder();
+    GrMtlBuffer* mtlBuffer = static_cast<GrMtlBuffer*>(slice.fBuffer);
+
+    SkISize levelDimensions(backendTexture.dimensions());
+    for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
+        size_t levelRowBytes;
+        size_t levelSize;
+
+        levelRowBytes = GrCompressedRowBytes(compression, levelDimensions.width());
+        levelSize = SkCompressedDataSize(compression, levelDimensions, nullptr, false);
+
+        // TODO: can this all be done in one go?
+        [blitCmdEncoder copyFromBuffer: mtlBuffer->mtlBuffer()
+                          sourceOffset: slice.fOffset + individualMipOffsets[currentMipLevel]
+                     sourceBytesPerRow: levelRowBytes
+                   sourceBytesPerImage: levelSize
+                            sourceSize: MTLSizeMake(levelDimensions.width(),
+                                                    levelDimensions.height(),
+                                                    1)
+                             toTexture: mtlTexture
+                      destinationSlice: 0
+                      destinationLevel: currentMipLevel
+                     destinationOrigin: origin];
+
+        levelDimensions = {std::max(1, levelDimensions.width() / 2),
+                           std::max(1, levelDimensions.height() / 2)};
+    }
+#ifdef SK_BUILD_FOR_MAC
+    [mtlBuffer->mtlBuffer() didModifyRange:NSMakeRange(slice.fOffset, combinedBufferSize)];
+#endif
+
+    if (finishedCallback) {
+        this->addFinishedCallback(std::move(finishedCallback));
+    }
+
+    return true;
 }
 
 void GrMtlGpu::deleteBackendTexture(const GrBackendTexture& tex) {
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index e4ec038..fd591ae 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -729,14 +729,17 @@
 
 // This fills in the 'regions' vector in preparation for copying a buffer to an image.
 // 'individualMipOffsets' is filled in as a side-effect.
-static size_t fill_in_regions(GrStagingBufferManager* stagingBufferManager,
-                              SkTArray<VkBufferImageCopy>* regions,
-                              SkTArray<size_t>* individualMipOffsets,
-                              GrStagingBufferManager::Slice* slice,
-                              SkImage::CompressionType compression,
-                              VkFormat vkFormat, SkISize dimensions, GrMipmapped mipMapped) {
+static size_t fill_in_compressed_regions(GrStagingBufferManager* stagingBufferManager,
+                                         SkTArray<VkBufferImageCopy>* regions,
+                                         SkTArray<size_t>* individualMipOffsets,
+                                         GrStagingBufferManager::Slice* slice,
+                                         SkImage::CompressionType compression,
+                                         VkFormat vkFormat,
+                                         SkISize dimensions,
+                                         GrMipmapped mipmapped) {
+    SkASSERT(compression != SkImage::CompressionType::kNone);
     int numMipLevels = 1;
-    if (mipMapped == GrMipmapped::kYes) {
+    if (mipmapped == GrMipmapped::kYes) {
         numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
     }
 
@@ -745,15 +748,10 @@
 
     size_t bytesPerBlock = GrVkFormatBytesPerBlock(vkFormat);
 
-    size_t combinedBufferSize;
-    if (compression == SkImage::CompressionType::kNone) {
-        combinedBufferSize = GrComputeTightCombinedBufferSize(bytesPerBlock, dimensions,
-                                                              individualMipOffsets,
-                                                              numMipLevels);
-    } else {
-        combinedBufferSize = SkCompressedDataSize(compression, dimensions, individualMipOffsets,
-                                                  mipMapped == GrMipmapped::kYes);
-    }
+    size_t bufferSize = SkCompressedDataSize(compression,
+                                             dimensions,
+                                             individualMipOffsets,
+                                             mipmapped == GrMipmapped::kYes);
     SkASSERT(individualMipOffsets->count() == numMipLevels);
 
     // Get a staging buffer slice to hold our mip data.
@@ -764,7 +762,7 @@
         case 2:     alignment *= 2; break;   // alignment is a multiple of 2 but not 4.
         default:    alignment *= 4; break;   // alignment is not a multiple of 2.
     }
-    *slice = stagingBufferManager->allocateStagingBufferSlice(combinedBufferSize, alignment);
+    *slice = stagingBufferManager->allocateStagingBufferSlice(bufferSize, alignment);
     if (!slice->fBuffer) {
         return 0;
     }
@@ -785,7 +783,7 @@
                       std::max(1, dimensions.height()/2)};
     }
 
-    return combinedBufferSize;
+    return bufferSize;
 }
 
 bool GrVkGpu::uploadTexDataOptimal(GrVkAttachment* texAttachment, int left, int top, int width,
@@ -933,10 +931,14 @@
     GrStagingBufferManager::Slice slice;
     SkTArray<VkBufferImageCopy> regions;
     SkTArray<size_t> individualMipOffsets;
-    SkDEBUGCODE(size_t combinedBufferSize =) fill_in_regions(&fStagingBufferManager,
-                                                             &regions, &individualMipOffsets,
-                                                             &slice, compression, vkFormat,
-                                                             dimensions, mipMapped);
+    SkDEBUGCODE(size_t combinedBufferSize =) fill_in_compressed_regions(&fStagingBufferManager,
+                                                                        &regions,
+                                                                        &individualMipOffsets,
+                                                                        &slice,
+                                                                        compression,
+                                                                        vkFormat,
+                                                                        dimensions,
+                                                                        mipMapped);
     if (!slice.fBuffer) {
         return false;
     }
@@ -1462,22 +1464,6 @@
     return true;
 }
 
-bool copy_compressed_data(GrVkGpu* gpu, char* mapPtr,
-                          const void* rawData, size_t dataSize) {
-    SkASSERT(mapPtr);
-    memcpy(mapPtr, rawData, dataSize);
-    return true;
-}
-
-bool generate_compressed_data(GrVkGpu* gpu, char* mapPtr,
-                              SkImage::CompressionType compression, SkISize dimensions,
-                              GrMipmapped mipMapped, const SkColor4f& color) {
-    SkASSERT(mapPtr);
-    GrFillInCompressedData(compression, dimensions, mipMapped, mapPtr, color);
-
-    return true;
-}
-
 bool GrVkGpu::createVkImageForBackendSurface(VkFormat vkFormat,
                                              SkISize dimensions,
                                              int sampleCnt,
@@ -1545,9 +1531,9 @@
     return true;
 }
 
-bool GrVkGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
-                                     sk_sp<GrRefCntedCallback> finishedCallback,
-                                     const BackendTextureData* data) {
+bool GrVkGpu::onClearBackendTexture(const GrBackendTexture& backendTexture,
+                                    sk_sp<GrRefCntedCallback> finishedCallback,
+                                    std::array<float, 4> color) {
     GrVkImageInfo info;
     SkAssertResult(backendTexture.getVkImageInfo(&info));
 
@@ -1571,68 +1557,23 @@
                                   VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
                                   false);
 
-    // Unfortunately, CmdClearColorImage doesn't work for compressed formats
-    bool fastPath = data->type() == BackendTextureData::Type::kColor &&
-                    !GrVkFormatIsCompressed(info.fFormat);
+    // CmdClearColorImage doesn't work for compressed formats
+    SkASSERT(!GrVkFormatIsCompressed(info.fFormat));
 
-    if (fastPath) {
-        SkASSERT(data->type() == BackendTextureData::Type::kColor);
-        VkClearColorValue vkColor;
-        SkColor4f color = data->color();
-        // If we ever support SINT or UINT formats this needs to be updated to use the int32 and
-        // uint32 union members in those cases.
-        vkColor.float32[0] = color.fR;
-        vkColor.float32[1] = color.fG;
-        vkColor.float32[2] = color.fB;
-        vkColor.float32[3] = color.fA;
-        VkImageSubresourceRange range;
-        range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
-        range.baseArrayLayer = 0;
-        range.baseMipLevel = 0;
-        range.layerCount = 1;
-        range.levelCount = info.fLevelCount;
-        cmdBuffer->clearColorImage(this, texAttachment, &vkColor, 1, &range);
-    } else {
-        SkImage::CompressionType compression = GrBackendFormatToCompressionType(
-                backendTexture.getBackendFormat());
-
-        SkTArray<VkBufferImageCopy> regions;
-        SkTArray<size_t> individualMipOffsets;
-        GrStagingBufferManager::Slice slice;
-
-        fill_in_regions(&fStagingBufferManager, &regions, &individualMipOffsets,
-                        &slice, compression, info.fFormat, backendTexture.dimensions(),
-                        backendTexture.fMipmapped);
-
-        if (!slice.fBuffer) {
-            return false;
-        }
-
-        bool result;
-        if (data->type() == BackendTextureData::Type::kPixmaps) {
-            result = copy_src_data((char*)slice.fOffsetMapPtr, info.fFormat, individualMipOffsets,
-                                   data->pixmaps(), info.fLevelCount);
-        } else if (data->type() == BackendTextureData::Type::kCompressed) {
-            result = copy_compressed_data(this, (char*)slice.fOffsetMapPtr,
-                                          data->compressedData(), data->compressedSize());
-        } else {
-            SkASSERT(data->type() == BackendTextureData::Type::kColor);
-            result = generate_compressed_data(this, (char*)slice.fOffsetMapPtr, compression,
-                                              backendTexture.dimensions(),
-                                              backendTexture.fMipmapped, data->color());
-        }
-
-        cmdBuffer->addGrSurface(texture);
-        // Copy the buffer to the image. This call takes the raw VkBuffer instead of a GrGpuBuffer
-        // because we don't need the command buffer to ref the buffer here. The reason being is that
-        // the buffer is coming from the staging manager and the staging manager will make sure the
-        // command buffer has a ref on the buffer. This avoids having to add and remove a ref for
-        // every upload in the frame.
-        const GrVkBuffer* vkBuffer = static_cast<GrVkBuffer*>(slice.fBuffer);
-        cmdBuffer->copyBufferToImage(this, vkBuffer->vkBuffer(), texAttachment,
-                                     texAttachment->currentLayout(), regions.count(),
-                                     regions.begin());
-    }
+    VkClearColorValue vkColor;
+    // If we ever support SINT or UINT formats this needs to be updated to use the int32 and
+    // uint32 union members in those cases.
+    vkColor.float32[0] = color[0];
+    vkColor.float32[1] = color[1];
+    vkColor.float32[2] = color[2];
+    vkColor.float32[3] = color[3];
+    VkImageSubresourceRange range;
+    range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+    range.baseArrayLayer = 0;
+    range.baseMipLevel = 0;
+    range.layerCount = 1;
+    range.levelCount = info.fLevelCount;
+    cmdBuffer->clearColorImage(this, texAttachment, &vkColor, 1, &range);
 
     // Change image layout to shader read since if we use this texture as a borrowed
     // texture within Ganesh we require that its layout be set to that
@@ -1689,8 +1630,82 @@
 
 bool GrVkGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
                                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                               const BackendTextureData* data) {
-    return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data);
+                                               const void* data,
+                                               size_t size) {
+    GrVkImageInfo info;
+    SkAssertResult(backendTexture.getVkImageInfo(&info));
+
+    sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTexture.getMutableState();
+    SkASSERT(mutableState);
+    sk_sp<GrVkTexture> texture = GrVkTexture::MakeWrappedTexture(this,
+                                                                 backendTexture.dimensions(),
+                                                                 kBorrow_GrWrapOwnership,
+                                                                 GrWrapCacheable::kNo,
+                                                                 kRW_GrIOType,
+                                                                 info,
+                                                                 std::move(mutableState));
+    if (!texture) {
+        return false;
+    }
+
+    GrVkPrimaryCommandBuffer* cmdBuffer = this->currentCommandBuffer();
+    if (!cmdBuffer) {
+        return false;
+    }
+    GrVkAttachment* attachment = texture->textureAttachment();
+    attachment->setImageLayout(this,
+                               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                               VK_ACCESS_TRANSFER_WRITE_BIT,
+                               VK_PIPELINE_STAGE_TRANSFER_BIT,
+                               false);
+
+    SkImage::CompressionType compression =
+            GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
+
+    SkTArray<VkBufferImageCopy> regions;
+    SkTArray<size_t> individualMipOffsets;
+    GrStagingBufferManager::Slice slice;
+
+    fill_in_compressed_regions(&fStagingBufferManager,
+                               &regions,
+                               &individualMipOffsets,
+                               &slice,
+                               compression,
+                               info.fFormat,
+                               backendTexture.dimensions(),
+                               backendTexture.fMipmapped);
+
+    if (!slice.fBuffer) {
+        return false;
+    }
+
+    memcpy(slice.fOffsetMapPtr, data, size);
+
+    cmdBuffer->addGrSurface(texture);
+    // Copy the buffer to the image. This call takes the raw VkBuffer instead of a GrGpuBuffer
+    // because we don't need the command buffer to ref the buffer here. The reason being is that
+    // the buffer is coming from the staging manager and the staging manager will make sure the
+    // command buffer has a ref on the buffer. This avoids having to add and remove a ref for
+    // every upload in the frame.
+    cmdBuffer->copyBufferToImage(this,
+                                 static_cast<GrVkBuffer*>(slice.fBuffer)->vkBuffer(),
+                                 attachment,
+                                 attachment->currentLayout(),
+                                 regions.count(),
+                                 regions.begin());
+
+    // Change image layout to shader read since if we use this texture as a borrowed
+    // texture within Ganesh we require that its layout be set to that
+    attachment->setImageLayout(this,
+                               VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
+                               VK_ACCESS_SHADER_READ_BIT,
+                               VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
+                               false);
+
+    if (finishedCallback) {
+        this->addFinishedCallback(std::move(finishedCallback));
+    }
+    return true;
 }
 
 void set_layout_and_queue_from_mutable_state(GrVkGpu* gpu, GrVkImage* image,
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index d4070ec..8dbc3c9 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -218,13 +218,14 @@
                                                       GrMipmapped,
                                                       GrProtected) override;
 
-    bool onUpdateBackendTexture(const GrBackendTexture&,
-                                sk_sp<GrRefCntedCallback> finishedCallback,
-                                const BackendTextureData*) override;
+    bool onClearBackendTexture(const GrBackendTexture&,
+                               sk_sp<GrRefCntedCallback> finishedCallback,
+                               std::array<float, 4> color) override;
 
     bool onUpdateCompressedBackendTexture(const GrBackendTexture&,
                                           sk_sp<GrRefCntedCallback> finishedCallback,
-                                          const BackendTextureData*) override;
+                                          const void* data,
+                                          size_t length) override;
 
     bool setBackendSurfaceState(GrVkImageInfo info,
                                 sk_sp<GrBackendSurfaceMutableStateImpl> currentState,