Revert "Separate texture creation from uploading in GrGpu subclasses."

This reverts commit a7398246cb80746994df430261ed72822a1f60ba.

Reason for revert: breaking bots

Original change's description:
> Separate texture creation from uploading in GrGpu subclasses.
> 
> GrGpu base class still allows creation with initial data, but separated
> at subclass level into create and then write pixels.
> 
> GrGpu handles determining which levels need clearing and GrGpu
> subclasses take a mask and clear levels with mask bit set.
> 
> GrGLGpu uses three pronged clear strategy:
> glClearTexImage() if supported, glClear() if format is FBO bindable, and
> lastly glTexSubImage2D with zero'ed buffer.
> 
> Change-Id: I65fb1e60eed8f9d0896d686d3baeb10b57ff8f39
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/236676
> Commit-Queue: Brian Salomon <bsalomon@google.com>
> Reviewed-by: Greg Daniel <egdaniel@google.com>

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

Change-Id: Icc6860053242ff1a55784a0f38938968f9e5e5b0
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240556
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h
index 112ba43..b7229bc 100644
--- a/src/gpu/GrCaps.h
+++ b/src/gpu/GrCaps.h
@@ -289,6 +289,17 @@
      */
     bool shouldInitializeTextures() const { return fShouldInitializeTextures; }
 
+    /**
+     * When this is true it is required that all textures are initially cleared. However, the
+     * clearing must be implemented by passing level data to GrGpu::createTexture() rather than
+     * be implemeted by GrGpu::createTexture().
+     *
+     * TODO: Make this take GrBacknedFormat when canClearTextureOnCreation() does as well.
+     */
+    bool createTextureMustSpecifyAllLevels() const {
+        return this->shouldInitializeTextures() && !this->canClearTextureOnCreation();
+    }
+
     /** Returns true if the given backend supports importing AHardwareBuffers via the
      * GrAHardwarebufferImageGenerator. This will only ever be supported on Android devices with API
      * level >= 26.
@@ -393,6 +404,17 @@
     virtual GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const = 0;
 
     /**
+     * Used by implementation of shouldInitializeTextures(). Indicates whether GrGpu implements the
+     * clear in GrGpu::createTexture() or if false then the caller must provide cleared MIP level
+     * data or GrGpu::createTexture() will fail.
+     *
+     * TODO: Make this take a GrBackendFormat so that GL can make this faster for cases
+     * when the format is renderable and glTexClearImage is not available. Doing this
+     * is overly complicated until the GrPixelConfig/format mess is straightened out..
+     */
+    virtual bool canClearTextureOnCreation() const = 0;
+
+    /**
      * The CLAMP_TO_BORDER wrap mode for texture coordinates was added to desktop GL in 1.3, and
      * GLES 3.2, but is also available in extensions. Vulkan and Metal always have support.
      */
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index a7a3bb1..07c035d 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -99,8 +99,8 @@
     return false;
 }
 
-static bool validate_texel_levels(int w, int h, const GrMipLevel* texels, int mipLevelCount,
-                                  int bpp, const GrCaps* caps) {
+static bool validate_levels(int w, int h, const GrMipLevel texels[], int mipLevelCount, int bpp,
+                            const GrCaps* caps, bool mustHaveDataForAllLevels = false) {
     SkASSERT(mipLevelCount > 0);
     bool hasBasePixels = texels[0].fPixels;
     int levelsWithPixelsCnt = 0;
@@ -138,7 +138,10 @@
     if (!hasBasePixels) {
         return levelsWithPixelsCnt == 0;
     }
-    return levelsWithPixelsCnt == 1 || levelsWithPixelsCnt == mipLevelCount;
+    if (levelsWithPixelsCnt == 1 && !mustHaveDataForAllLevels) {
+        return true;
+    }
+    return levelsWithPixelsCnt == mipLevelCount;
 }
 
 sk_sp<GrTexture> GrGpu::createTexture(const GrSurfaceDesc& desc,
@@ -148,14 +151,14 @@
                                       SkBudgeted budgeted,
                                       GrProtected isProtected,
                                       const GrMipLevel texels[],
-                                      int texelLevelCount) {
+                                      int mipLevelCount) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     if (this->caps()->isFormatCompressed(format)) {
         // Call GrGpu::createCompressedTexture.
         return nullptr;
     }
 
-    GrMipMapped mipMapped = texelLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
+    GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
     if (!this->caps()->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
                                              renderable, renderTargetSampleCnt, mipMapped)) {
         return nullptr;
@@ -167,26 +170,16 @@
     }
     // Attempt to catch un- or wrongly initialized sample counts.
     SkASSERT(renderTargetSampleCnt > 0 && renderTargetSampleCnt <= 64);
-    if (texelLevelCount) {
+
+    bool mustHaveDataForAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
+    if (mipLevelCount) {
         int bpp = GrBytesPerPixel(desc.fConfig);
-        if (!validate_texel_levels(desc.fWidth, desc.fHeight, texels, texelLevelCount, bpp,
-                                   this->caps())) {
+        if (!validate_levels(desc.fWidth, desc.fHeight, texels, mipLevelCount, bpp, this->caps(),
+                             mustHaveDataForAllLevels)) {
             return nullptr;
         }
-    }
-
-    int mipLevelCount = SkTMax(1, texelLevelCount);
-    uint32_t levelClearMask = 0;
-    if (this->caps()->shouldInitializeTextures()) {
-        if (texelLevelCount) {
-            for (int i = 0; i < mipLevelCount; ++i) {
-                if (!texels->fPixels) {
-                    levelClearMask |= static_cast<uint32_t>(1 << i);
-                }
-            }
-        } else {
-            levelClearMask = static_cast<uint32_t>((1 << mipLevelCount) - 1);
-        }
+    } else if (mustHaveDataForAllLevels) {
+        return nullptr;
     }
 
     this->handleDirtyContext();
@@ -196,36 +189,20 @@
                                                  renderTargetSampleCnt,
                                                  budgeted,
                                                  isProtected,
-                                                 mipLevelCount,
-                                                 levelClearMask);
-
+                                                 texels,
+                                                 mipLevelCount);
     if (tex) {
-        SkASSERT(tex->backendFormat() == format);
-        SkASSERT(GrRenderable::kNo == renderable || tex->asRenderTarget());
         if (!this->caps()->reuseScratchTextures() && renderable == GrRenderable::kNo) {
             tex->resourcePriv().removeScratchKey();
         }
         fStats.incTextureCreates();
-        bool markMipLevelsClean = false;
-        // Currently if level 0 does not have pixels then no other level may, as enforced by
-        // validate_texel_levels.
-        if (texelLevelCount && texels[0].fPixels) {
-            auto textureColorType = GrPixelConfigToColorType(desc.fConfig);
-            auto dataColorType = textureColorType;
-            if (!this->writePixels(tex.get(), 0, 0, desc.fWidth, desc.fHeight, textureColorType,
-                                   dataColorType, texels, texelLevelCount)) {
-                return nullptr;
+        if (mipLevelCount) {
+            if (texels[0].fPixels) {
+                fStats.incTextureUploads();
             }
-            // Currently if level[1] of mip map has pixel data then so must all other levels.
-            // as enforced by validate_texel_levels.
-            markMipLevelsClean = (texelLevelCount > 1 && !levelClearMask && texels[1].fPixels);
-            fStats.incTextureUploads();
-        } else if (levelClearMask && mipLevelCount > 1) {
-            markMipLevelsClean = true;
         }
-        if (markMipLevelsClean) {
-            tex->texturePriv().markMipMapsClean();
-        }
+        SkASSERT(tex->backendFormat() == format);
+        SkASSERT(!tex || GrRenderable::kNo == renderable || tex->asRenderTarget());
         if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
             SkASSERT(GrRenderable::kYes == renderable);
             tex->asRenderTarget()->setRequiresManualMSAAResolve();
@@ -455,7 +432,7 @@
     }
 
     size_t bpp = GrColorTypeBytesPerPixel(srcColorType);
-    if (!validate_texel_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
+    if (!validate_levels(width, height, texels, mipLevelCount, bpp, this->caps())) {
         return false;
     }
 
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 80677b9..6b8a45e 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -103,7 +103,7 @@
      *                       If mipLevelCount > 1 and texels[i].fPixels != nullptr for any i > 0
      *                       then all levels must have non-null pixels. All levels must have
      *                       non-null pixels if GrCaps::createTextureMustSpecifyAllLevels() is true.
-     * @param texelLevelCount the number of levels in 'texels'. May be 0, 1, or
+     * @param mipLevelCount  the number of levels in 'texels'. May be 0, 1, or
      *                       floor(max((log2(desc.fWidth), log2(desc.fHeight)))). It must be the
      *                       latter if GrCaps::createTextureMustSpecifyAllLevels() is true.
      * @return  The texture object if successful, otherwise nullptr.
@@ -111,7 +111,7 @@
     sk_sp<GrTexture> createTexture(const GrSurfaceDesc& desc, const GrBackendFormat& format,
                                    GrRenderable renderable, int renderTargetSampleCnt, SkBudgeted,
                                    GrProtected isProtected, const GrMipLevel texels[],
-                                   int texelLevelCount);
+                                   int mipLevelCount);
 
     /**
      * Simplified createTexture() interface for when there is no initial texel data to upload.
@@ -546,17 +546,15 @@
     virtual void xferBarrier(GrRenderTarget*, GrXferBarrierType) = 0;
 
     // overridden by backend-specific derived class to create objects.
-    // Texture size, renderablility, format support, sample count will have already been validated
-    // in base class before onCreateTexture is called.
-    // If the ith bit is set in levelClearMask then the ith MIP level should be cleared.
+    // Texture size and sample size will have already been validated in base class before
+    // onCreateTexture is called.
     virtual sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&,
                                              const GrBackendFormat&,
                                              GrRenderable,
                                              int renderTargetSampleCnt,
-                                             SkBudgeted,
-                                             GrProtected,
-                                             int mipLevelCoont,
-                                             uint32_t levelClearMask) = 0;
+                                             SkBudgeted, GrProtected,
+                                             const GrMipLevel[],
+                                             int mipLevelCount) = 0;
     virtual sk_sp<GrTexture> onCreateCompressedTexture(int width, int height,
                                                        const GrBackendFormat&,
                                                        SkImage::CompressionType, SkBudgeted,
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 29a616f..214b24d 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -45,11 +45,18 @@
 // Ensures the row bytes are populated (not 0) and makes a copy to a temporary
 // to make the row bytes tight if necessary. Returns false if the input row bytes are invalid.
 static bool prepare_level(const GrMipLevel& inLevel, size_t bpp, int w, int h, bool rowBytesSupport,
-                          GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
+                          bool mustInitializeAllLevels, GrMipLevel* outLevel,
+                          std::unique_ptr<char[]>* data) {
     size_t minRB = w * bpp;
     if (!inLevel.fPixels) {
-        outLevel->fPixels = nullptr;
-        outLevel->fRowBytes = 0;
+        if (mustInitializeAllLevels) {
+            data->reset(new char[minRB * h]());
+            outLevel->fPixels = data->get();
+            outLevel->fRowBytes = minRB;
+        } else {
+            outLevel->fPixels = nullptr;
+            outLevel->fRowBytes = 0;
+        }
         return true;
     }
     size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
@@ -90,6 +97,7 @@
                                       renderTargetSampleCnt, mipMapped)) {
         return nullptr;
     }
+    bool mustInitializeAllLevels = this->caps()->createTextureMustSpecifyAllLevels();
     bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
     SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
@@ -100,8 +108,8 @@
         int h = desc.fHeight;
         size_t bpp = GrBytesPerPixel(desc.fConfig);
         for (int i = 0; i < mipLevelCount; ++i) {
-            if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, &tmpTexels[i],
-                               &tmpDatas[i])) {
+            if (!prepare_level(texels[i], bpp, w, h, rowBytesSupport, mustInitializeAllLevels,
+                               &tmpTexels[i], &tmpDatas[i])) {
                 return nullptr;
             }
             w = std::max(w / 2, 1);
@@ -154,13 +162,14 @@
     GrContext* context = fGpu->getContext();
     GrProxyProvider* proxyProvider = context->priv().proxyProvider();
 
+    bool mustInitialize = this->caps()->createTextureMustSpecifyAllLevels();
     bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
 
     size_t bpp = GrBytesPerPixel(desc.fConfig);
     std::unique_ptr<char[]> tmpData;
     GrMipLevel tmpLevel;
-    if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, &tmpLevel,
-                       &tmpData)) {
+    if (!prepare_level(mipLevel, bpp, desc.fWidth, desc.fHeight, rowBytesSupport, mustInitialize,
+                       &tmpLevel, &tmpData)) {
         return nullptr;
     }
 
@@ -230,6 +239,17 @@
         }
     }
 
+    if (fCaps->createTextureMustSpecifyAllLevels()) {
+        size_t rowBytes = GrBytesPerPixel(desc.fConfig) * desc.fWidth;
+        size_t size = rowBytes * desc.fHeight;
+        std::unique_ptr<char[]> zeros(new char[size]());
+        GrMipLevel level;
+        level.fRowBytes = rowBytes;
+        level.fPixels = zeros.get();
+        return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
+                                   isProtected, &level, 1);
+    }
+
     return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
                                isProtected);
 }
@@ -300,6 +320,16 @@
         return tex;
     }
 
+    if (this->caps()->createTextureMustSpecifyAllLevels()) {
+        size_t rowBytes = GrBytesPerPixel(copyDesc->fConfig) * copyDesc->fWidth;
+        size_t size = rowBytes * copyDesc->fHeight;
+        std::unique_ptr<char[]> zeros(new char[size]());
+        GrMipLevel level;
+        level.fRowBytes = rowBytes;
+        level.fPixels = zeros.get();
+        return fGpu->createTexture(*copyDesc, format, renderable, renderTargetSampleCnt,
+                                   SkBudgeted::kYes, isProtected, &level, 1);
+    }
     return fGpu->createTexture(*copyDesc, format, renderable, renderTargetSampleCnt,
                                SkBudgeted::kYes, isProtected);
 }
diff --git a/src/gpu/dawn/GrDawnCaps.cpp b/src/gpu/dawn/GrDawnCaps.cpp
index b53feca..106068b 100644
--- a/src/gpu/dawn/GrDawnCaps.cpp
+++ b/src/gpu/dawn/GrDawnCaps.cpp
@@ -175,6 +175,10 @@
     return get_swizzle(format, colorType, false);
 }
 
+bool GrDawnCaps::canClearTextureOnCreation() const {
+    return true;
+}
+
 GrSwizzle GrDawnCaps::getOutputSwizzle(const GrBackendFormat& format, GrColorType colorType) const
 {
     return get_swizzle(format, colorType, true);
diff --git a/src/gpu/dawn/GrDawnCaps.h b/src/gpu/dawn/GrDawnCaps.h
index 123bc3b..41ca2a2 100644
--- a/src/gpu/dawn/GrDawnCaps.h
+++ b/src/gpu/dawn/GrDawnCaps.h
@@ -48,6 +48,8 @@
 
     GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
 
+    bool canClearTextureOnCreation() const override;
+
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
 
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index 403202b..447d10d 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -1195,12 +1195,12 @@
         writer->beginObject(nullptr, false);
         writer->appendHexU32("flags", fFormatTable[i].fFlags);
         writer->appendHexU32("f_type", (uint32_t)fFormatTable[i].fFormatType);
+        writer->appendHexU32("b_internal", fFormatTable[i].fBaseInternalFormat);
+        writer->appendHexU32("s_internal", fFormatTable[i].fSizedInternalFormat);
         writer->appendHexU32("c_internal", fFormatTable[i].fCompressedInternalFormat);
-        writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImageOrStorage);
+        writer->appendHexU32("i_for_teximage", fFormatTable[i].fInternalFormatForTexImage);
         writer->appendHexU32("i_for_renderbuffer", fFormatTable[i].fInternalFormatForRenderbuffer);
-        writer->appendHexU32("default_ex_format", fFormatTable[i].fDefaultExternalFormat);
         writer->appendHexU32("default_ex_type", fFormatTable[i].fDefaultExternalType);
-        writer->appendHexU64("z_bpp", fFormatTable[i].fTexSubImageZeroDataBpp);
 
         writer->beginArray("surface color types");
         for (int j = 0; j < fFormatTable[i].fColorTypeInfoCount; ++j) {
@@ -1233,28 +1233,12 @@
 void GrGLCaps::onDumpJSON(SkJSONWriter* writer) const { }
 #endif
 
-void GrGLCaps::getTexImageExternalFormatAndType(GrGLFormat surfaceFormat, GrGLenum* externalFormat,
-                                                GrGLenum* externalType) const {
-    const auto& info = this->getFormatInfo(surfaceFormat);
-    *externalType = info.fDefaultExternalType;
-    *externalFormat = info.fDefaultExternalFormat;
-}
-
-void GrGLCaps::getTexSubImageZeroFormatTypeAndBpp(GrGLFormat format, GrGLenum* externalFormat,
-                                                  GrGLenum* externalType, size_t* bpp) const {
-    const auto& info = this->getFormatInfo(format);
-    *externalType = info.fDefaultExternalType;
-    *externalFormat = info.fDefaultExternalFormat;
-    *bpp = info.fTexSubImageZeroDataBpp;
-}
-
-void GrGLCaps::getTexSubImageExternalFormatAndType(GrGLFormat surfaceFormat,
-                                                   GrColorType surfaceColorType,
-                                                   GrColorType memoryColorType,
-                                                   GrGLenum* externalFormat,
-                                                   GrGLenum* externalType) const {
+void GrGLCaps::getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
+                                  GrColorType memoryColorType, GrGLenum* internalFormat,
+                                  GrGLenum* externalFormat, GrGLenum* externalType) const {
     this->getExternalFormat(surfaceFormat, surfaceColorType, memoryColorType,
                             kTexImage_ExternalFormatUsage, externalFormat, externalType);
+    *internalFormat = this->getTexImageInternalFormat(surfaceFormat);
 }
 
 void GrGLCaps::getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
@@ -1433,10 +1417,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_RGBA8;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RGBA8 : GR_GL_RGBA;
         info.fInternalFormatForRenderbuffer = GR_GL_RGBA8;
-        info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 4;
         info.fFlags = FormatInfo::kTexturable_Flag;
         if (GR_IS_GR_GL(standard)) {
             info.fFlags |= msaaRenderFlags;
@@ -1450,11 +1436,7 @@
         }
 
         if (texStorageSupported) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA8;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RGBA8 : GR_GL_RGBA;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         bool supportsBGRAColorType = GR_IS_GR_GL(standard) &&
@@ -1542,21 +1524,19 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kR8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RED;
+        info.fSizedInternalFormat = GR_GL_R8;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_R8 : GR_GL_RED;
         info.fInternalFormatForRenderbuffer = GR_GL_R8;
-        info.fDefaultExternalFormat = GR_GL_RED;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 1;
         if (textureRedSupport) {
             info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
         }
 
         if (texStorageSupported &&
             !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_R8;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_R8 : GR_GL_RED;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (textureRedSupport) {
@@ -1639,6 +1619,8 @@
 
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kALPHA8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_ALPHA;
+        info.fSizedInternalFormat = GR_GL_ALPHA8;
         // GL_EXT_texture_storage adds GL_ALPHA8 for texture storage. However, ES3 has glTexStorage
         // but does not have GL_ALPHA8 (and requires a sized internal format for glTexStorage).
         // WebGL never has GL_ALPHA8.
@@ -1646,6 +1628,14 @@
                 alpha8IsValidForGL ||
                 (alpha8IsValidForGLES && ctxInfo.hasExtension("GL_EXT_texture_storage"));
         bool alpha8TexStorageSupported = alpha8SizedEnumSupported && texStorageSupported;
+        // Even if GL_ALPHA8 is added by GL_EXT_texture_storage it doesn't become legal for
+        // glTexImage2D.
+        if (!GR_IS_GR_GL_ES(standard) && texImageSupportsSizedInternalFormat &&
+            alpha8SizedEnumSupported) {
+            info.fInternalFormatForTexImage = GR_GL_ALPHA8;
+        } else {
+            info.fInternalFormatForTexImage = GR_GL_ALPHA;
+        }
 
         bool alpha8IsRenderable = false;
         if (!formatWorkarounds.fDisableAlpha8Renderable) {
@@ -1657,9 +1647,8 @@
             }
         }
         info.fInternalFormatForRenderbuffer = GR_GL_ALPHA8;
-        info.fDefaultExternalFormat = GR_GL_ALPHA;
+
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 1;
         if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
             info.fFlags = FormatInfo::kTexturable_Flag;
         }
@@ -1669,17 +1658,7 @@
             info.fFlags |= msaaRenderFlags;
         }
         if (alpha8TexStorageSupported) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA8;
-        } else {
-            // Even if GL_ALPHA8 is added to ES by GL_EXT_texture_storage it doesn't become legal
-            // for glTexImage2D.
-            if (!GR_IS_GR_GL_ES(standard) && texImageSupportsSizedInternalFormat &&
-                alpha8SizedEnumSupported) {
-                info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA8;
-            } else {
-                info.fInternalFormatForTexImageOrStorage = GR_GL_ALPHA;
-            }
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (alpha8IsValidForGL || alpha8IsValidForGLES || alpha8IsValidForWebGL) {
@@ -1730,10 +1709,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_LUMINANCE;
+        info.fSizedInternalFormat = GR_GL_LUMINANCE8;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE8 : GR_GL_LUMINANCE;
         info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE8;
-        info.fDefaultExternalFormat = GR_GL_LUMINANCE;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 1;
         bool supportsLum = (GR_IS_GR_GL(standard) && version <= GR_GL_VER(3, 0)) ||
                            (GR_IS_GR_GL_ES(standard) && version < GR_GL_VER(3, 0)) ||
                            (GR_IS_GR_WEBGL(standard));
@@ -1743,11 +1724,7 @@
         if (texStorageSupported &&
             !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2 &&
             !formatWorkarounds.fDisableNonRedSingleChannelTexStorageForANGLEGL) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE8;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE8 : GR_GL_LUMINANCE;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
         // We are not enabling attaching to an FBO for LUMINANCE8 mostly because of confusion in the
         // spec. For GLES it does not seem to ever support LUMINANCE8 being color-renderable. For GL
@@ -1803,6 +1780,23 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kBGRA8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_BGRA;
+        info.fSizedInternalFormat = GR_GL_BGRA8;
+        // If BGRA is supported as an internal format it must always be specified to glTex[Sub]Image
+        // as a base format. Which base format depends on which extension is used.
+        if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
+            // GL_APPLE_texture_format_BGRA8888:
+            //     ES 2.0: the extension makes BGRA an external format but not an internal format.
+            //     ES 3.0: the extension explicitly states GL_BGRA8 is not a valid internal format
+            //             for glTexImage (just for glTexStorage).
+            info.fInternalFormatForTexImage = GR_GL_RGBA;
+        } else {
+            // GL_EXT_texture_format_BGRA8888:
+            //      This extension adds GL_BGRA as an unsized internal format. However, it is
+            //      written against ES 2.0 and therefore doesn't define a GL_BGRA8 as ES 2.0 doesn't
+            //      have sized internal formats.
+            info.fInternalFormatForTexImage = GR_GL_BGRA;
+        }
 
         // We currently only use the renderbuffer format when allocating msaa renderbuffers, so we
         // are making decisions here based on that use case. The GL_EXT_texture_format_BGRA8888
@@ -1825,28 +1819,7 @@
             info.fInternalFormatForRenderbuffer = GR_GL_BGRA8;
         }
 
-        info.fDefaultExternalFormat = GR_GL_BGRA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 4;
-
-        GrGLenum bgraTexImageFormat;
-        // If BGRA is supported as an internal format it must always be specified to glTex[Sub]Image
-        // as a base format. Which base format depends on which extension is used.
-        if (ctxInfo.hasExtension("GL_APPLE_texture_format_BGRA8888")) {
-            // GL_APPLE_texture_format_BGRA8888:
-            //     ES 2.0: the extension makes BGRA an external format but not an internal format.
-            //     ES 3.0: the extension explicitly states GL_BGRA8 is not a valid internal format
-            //             for glTexImage (just for glTexStorage).
-            bgraTexImageFormat = GR_GL_RGBA;
-        } else {
-            // GL_EXT_texture_format_BGRA8888:
-            //      This extension adds GL_BGRA as an unsized internal format. However, it is
-            //      written against ES 2.0 and therefore doesn't define a GL_BGRA8 as ES 2.0 doesn't
-            //      have sized internal formats. See later where we check for tex storage BGRA8
-            //      support.
-            bgraTexImageFormat = GR_GL_BGRA;
-        }
-
         // TexStorage requires using a sized internal format and BGRA8 is only supported if we have
         // the GL_APPLE_texture_format_BGRA8888 extension or if we have GL_EXT_texture_storage and
         // GL_EXT_texture_format_BGRA8888.
@@ -1856,8 +1829,7 @@
             if (ctxInfo.hasExtension("GL_EXT_texture_format_BGRA8888")) {
                 info.fFlags = FormatInfo::kTexturable_Flag | nonMSAARenderFlags;
                 // GL_EXT_texture storage has defined interactions with
-                // GL_EXT_texture_format_BGRA8888. However, ES3 supports glTexStorage but
-                // without GL_EXT_texture_storage it does not allow the BGRA8 sized internal format.
+                // GL_EXT_texture_format_BGRA8888.
                 if (ctxInfo.hasExtension("GL_EXT_texture_storage") &&
                     !formatWorkarounds.fDisableBGRATextureStorageForIntelWindowsES) {
                     supportsBGRATexStorage = true;
@@ -1880,10 +1852,7 @@
             }
         }
         if (texStorageSupported && supportsBGRATexStorage) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_BGRA8;
-        } else {
-            info.fInternalFormatForTexImageOrStorage = bgraTexImageFormat;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@@ -1927,10 +1896,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB565);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RGB;
+        info.fSizedInternalFormat = GR_GL_RGB565;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RGB565 : GR_GL_RGB;
         info.fInternalFormatForRenderbuffer = GR_GL_RGB565;
-        info.fDefaultExternalFormat = GR_GL_RGB;
         info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_5_6_5;
-        info.fTexSubImageZeroDataBpp = 2;
         if (GR_IS_GR_GL(standard)) {
             if (version >= GR_GL_VER(4, 2) || ctxInfo.hasExtension("GL_ARB_ES2_compatibility")) {
                 info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
@@ -1948,11 +1919,7 @@
         // TODO: As of 4.2, regular GL supports 565. This logic is due for an
         // update.
         if (texStorageSupported && GR_IS_GR_GL_ES(standard)) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_RGB565;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RGB565 : GR_GL_RGB;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@@ -1996,10 +1963,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16F);
         info.fFormatType = FormatType::kFloat;
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_RGBA16F;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RGBA16F : GR_GL_RGBA;
         info.fInternalFormatForRenderbuffer = GR_GL_RGBA16F;
-        info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = halfFloatType;
-        info.fTexSubImageZeroDataBpp = 8;
         if (hasFP16Textures) {
             info.fFlags = FormatInfo::kTexturable_Flag;
             // ES requires 3.2 or EXT_color_buffer_half_float.
@@ -2009,11 +1978,7 @@
         }
         if (texStorageSupported &&
             !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA16F;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RGBA16F : GR_GL_RGBA;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (hasFP16Textures) {
@@ -2090,10 +2055,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16F);
         info.fFormatType = FormatType::kFloat;
+        info.fBaseInternalFormat = GR_GL_RED;
+        info.fSizedInternalFormat = GR_GL_R16F;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_R16F : GR_GL_RED;
         info.fInternalFormatForRenderbuffer = GR_GL_R16F;
-        info.fDefaultExternalFormat = GR_GL_RED;
         info.fDefaultExternalType = halfFloatType;
-        info.fTexSubImageZeroDataBpp = 2;
         if (textureRedSupport && hasFP16Textures) {
             info.fFlags = FormatInfo::kTexturable_Flag;
             if (halfFPRenderTargetSupport == HalfFPRenderTargetSupport::kAll) {
@@ -2102,11 +2069,7 @@
         }
         if (texStorageSupported &&
             !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_R16F;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_R16F : GR_GL_RED;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (textureRedSupport && hasFP16Textures) {
@@ -2174,21 +2137,19 @@
 
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kLUMINANCE16F);
         info.fFormatType = FormatType::kFloat;
+        info.fBaseInternalFormat = GR_GL_LUMINANCE;
+        info.fSizedInternalFormat = GR_GL_LUMINANCE16F;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE16F : GR_GL_LUMINANCE;
         info.fInternalFormatForRenderbuffer = GR_GL_LUMINANCE16F;
-        info.fDefaultExternalFormat = GR_GL_LUMINANCE;
         info.fDefaultExternalType = halfFloatType;
-        info.fTexSubImageZeroDataBpp = 2;
 
         if (lum16FSupported) {
             info.fFlags = FormatInfo::kTexturable_Flag;
 
             if (texStorageSupported &&
                 !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
-                info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-                info.fInternalFormatForTexImageOrStorage = GR_GL_LUMINANCE16F;
-            } else {
-                info.fInternalFormatForTexImageOrStorage =
-                        texImageSupportsSizedInternalFormat ? GR_GL_LUMINANCE16F : GR_GL_LUMINANCE;
+                info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
             }
 
             info.fColorTypeInfoCount = 1;
@@ -2237,10 +2198,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RGB;
+        info.fSizedInternalFormat = GR_GL_RGB8;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RGB8 : GR_GL_RGB;
         info.fInternalFormatForRenderbuffer = GR_GL_RGB8;
-        info.fDefaultExternalFormat = GR_GL_RGB;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 3;
         info.fFlags = FormatInfo::kTexturable_Flag;
         if (GR_IS_GR_GL(standard)) {
             // Even in OpenGL 4.6 GL_RGB8 is required to be color renderable but not required to be
@@ -2261,11 +2224,7 @@
             info.fFlags |= msaaRenderFlags;
         }
         if (texStorageSupported) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_RGB8;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RGB8 : GR_GL_RGB;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
         if (formatWorkarounds.fDisableRGB8ForMali400) {
             info.fFlags = 0;
@@ -2316,22 +2275,20 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RG;
+        info.fSizedInternalFormat = GR_GL_RG8;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RG8 : GR_GL_RG;
         info.fInternalFormatForRenderbuffer = GR_GL_RG8;
-        info.fDefaultExternalFormat = GR_GL_RG;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 2;
         if (textureRedSupport) {
             info.fFlags |= FormatInfo::kTexturable_Flag | msaaRenderFlags;
             if (texStorageSupported &&
                 !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
-                info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-                info.fInternalFormatForTexImageOrStorage = GR_GL_RG8;
+                info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
             }
         }
-        if (!(info.fFlags & FormatInfo::kUseTexStorage_Flag)) {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RG8 : GR_GL_RG;
-        }
+
         if (textureRedSupport) {
             info.fColorTypeInfoCount = 1;
             info.fColorTypeInfos.reset(new ColorTypeInfo[info.fColorTypeInfoCount]());
@@ -2373,10 +2330,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGB10_A2);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_RGB10_A2;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RGB10_A2 : GR_GL_RGBA;
         info.fInternalFormatForRenderbuffer = GR_GL_RGB10_A2;
-        info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_INT_2_10_10_10_REV;
-        info.fTexSubImageZeroDataBpp = 4;
         if (GR_IS_GR_GL(standard) ||
            (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0))) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
@@ -2385,11 +2344,7 @@
             info.fFlags = FormatInfo::kTexturable_Flag;
         } // No WebGL support
         if (texStorageSupported) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_RGB10_A2;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RGB10_A2 : GR_GL_RGBA;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (SkToBool(info.fFlags &FormatInfo::kTexturable_Flag)) {
@@ -2433,10 +2388,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA4);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_RGBA4;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_RGBA4 : GR_GL_RGBA;
         info.fInternalFormatForRenderbuffer = GR_GL_RGBA4;
-        info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT_4_4_4_4;
-        info.fTexSubImageZeroDataBpp = 2;
         info.fFlags = FormatInfo::kTexturable_Flag;
         if (GR_IS_GR_GL(standard)) {
             if (version >= GR_GL_VER(4, 2)) {
@@ -2448,11 +2405,7 @@
             info.fFlags |= msaaRenderFlags;
         }
         if (texStorageSupported) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_RGBA4;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_RGBA4 : GR_GL_RGBA;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         info.fColorTypeInfoCount = 1;
@@ -2494,7 +2447,9 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA32F);
         info.fFormatType = FormatType::kFloat;
-        info.fInternalFormatForTexImageOrStorage =
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_RGBA32F;
+        info.fInternalFormatForTexImage =
                 texImageSupportsSizedInternalFormat ? GR_GL_RGBA32F : GR_GL_RGBA;
         info.fInternalFormatForRenderbuffer = GR_GL_RGBA32F;
         // We don't allow texturing or rendering to this format
@@ -2504,10 +2459,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kSRGB8_ALPHA8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_SRGB8_ALPHA8;
+        info.fInternalFormatForTexImage =
+                texImageSupportsSizedInternalFormat ? GR_GL_SRGB8_ALPHA8 : GR_GL_SRGB_ALPHA;
         info.fInternalFormatForRenderbuffer = GR_GL_SRGB8_ALPHA8;
-        info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_BYTE;
-        info.fTexSubImageZeroDataBpp = 4;
         if (fSRGBSupport) {
             uint32_t srgbRenderFlags =
                     formatWorkarounds.fDisableSRGBRenderWithMSAAForMacAMD ? nonMSAARenderFlags
@@ -2517,11 +2474,7 @@
         }
         if (texStorageSupported &&
             !formatWorkarounds.fDisablePerFormatTextureStorageForCommandBufferES2) {
-            info.fFlags |= FormatInfo::kUseTexStorage_Flag;
-            info.fInternalFormatForTexImageOrStorage = GR_GL_SRGB8_ALPHA8;
-        } else {
-            info.fInternalFormatForTexImageOrStorage =
-                    texImageSupportsSizedInternalFormat ? GR_GL_SRGB8_ALPHA8 : GR_GL_SRGB_ALPHA;
+            info.fFlags |= FormatInfo::kCanUseTexStorage_Flag;
         }
 
         if (fSRGBSupport) {
@@ -2570,7 +2523,8 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_RGB8_ETC2);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
-        info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_RGB8_ETC2;
+        info.fBaseInternalFormat = GR_GL_RGB;
+        info.fInternalFormatForTexImage = GR_GL_COMPRESSED_RGB8_ETC2;
         if (GR_IS_GR_GL(standard)) {
             if (version >= GR_GL_VER(4, 3) || ctxInfo.hasExtension("GL_ARB_ES3_compatibility")) {
                 info.fFlags = FormatInfo::kTexturable_Flag;
@@ -2589,7 +2543,8 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kCOMPRESSED_ETC1_RGB8);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
-        info.fInternalFormatForTexImageOrStorage = GR_GL_COMPRESSED_ETC1_RGB8;
+        info.fBaseInternalFormat = GR_GL_RGB;
+        info.fInternalFormatForTexImage = GR_GL_COMPRESSED_ETC1_RGB8;
         if (GR_IS_GR_GL_ES(standard)) {
             if (ctxInfo.hasExtension("GL_OES_compressed_ETC1_RGB8_texture")) {
                 info.fFlags = FormatInfo::kTexturable_Flag;
@@ -2603,12 +2558,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kR16);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
-        info.fInternalFormatForTexImageOrStorage =
+        info.fBaseInternalFormat = GR_GL_RED;
+        info.fSizedInternalFormat = GR_GL_R16;
+        info.fInternalFormatForTexImage =
                 texImageSupportsSizedInternalFormat ? GR_GL_R16 : GR_GL_RED;
         info.fInternalFormatForRenderbuffer = GR_GL_R16;
-        info.fDefaultExternalFormat = GR_GL_RED;
         info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
-        info.fTexSubImageZeroDataBpp = 2;
         if (r16AndRG1616Supported) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
         }
@@ -2654,12 +2609,12 @@
     {
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
-        info.fInternalFormatForTexImageOrStorage =
+        info.fBaseInternalFormat = GR_GL_RG;
+        info.fSizedInternalFormat = GR_GL_RG16;
+        info.fInternalFormatForTexImage =
                 texImageSupportsSizedInternalFormat ? GR_GL_RG16 : GR_GL_RG;
         info.fInternalFormatForRenderbuffer = GR_GL_RG16;
-        info.fDefaultExternalFormat = GR_GL_RG;
         info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
-        info.fTexSubImageZeroDataBpp = 4;
         if (r16AndRG1616Supported) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
         }
@@ -2724,12 +2679,12 @@
 
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRGBA16);
         info.fFormatType = FormatType::kNormalizedFixedPoint;
-        info.fInternalFormatForTexImageOrStorage =
+        info.fBaseInternalFormat = GR_GL_RGBA;
+        info.fSizedInternalFormat = GR_GL_RGBA16;
+        info.fInternalFormatForTexImage =
                 texImageSupportsSizedInternalFormat ? GR_GL_RGBA16 : GR_GL_RGBA;
         info.fInternalFormatForRenderbuffer = GR_GL_RGBA16;
-        info.fDefaultExternalFormat = GR_GL_RGBA;
         info.fDefaultExternalType = GR_GL_UNSIGNED_SHORT;
-        info.fTexSubImageZeroDataBpp = 8;
         if (rgba16161616Supported) {
             info.fFlags = FormatInfo::kTexturable_Flag | msaaRenderFlags;
         }
@@ -2798,12 +2753,12 @@
 
         FormatInfo& info = this->getFormatInfo(GrGLFormat::kRG16F);
         info.fFormatType = FormatType::kFloat;
-        info.fInternalFormatForTexImageOrStorage =
+        info.fBaseInternalFormat = GR_GL_RG;
+        info.fSizedInternalFormat = GR_GL_RG16F;
+        info.fInternalFormatForTexImage =
                 texImageSupportsSizedInternalFormat ? GR_GL_RG16F : GR_GL_RG;
         info.fInternalFormatForRenderbuffer = GR_GL_RG16F;
-        info.fDefaultExternalFormat = GR_GL_RG;
         info.fDefaultExternalType = halfFloatType;
-        info.fTexSubImageZeroDataBpp = 4;
         if (rg16fTexturesSupported) {
             info.fFlags |= FormatInfo::kTexturable_Flag;
         }
@@ -3661,8 +3616,7 @@
                 return false;
             }
         }
-    }
-    if (auto rt = surface->asRenderTarget()) {
+    }    if (auto rt = surface->asRenderTarget()) {
         if (fUseDrawInsteadOfAllRenderTargetWrites) {
             return false;
         }
@@ -3883,7 +3837,7 @@
 }
 
 bool GrGLCaps::formatSupportsTexStorage(GrGLFormat format) const {
-    return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kUseTexStorage_Flag);
+    return SkToBool(this->getFormatInfo(format).fFlags & FormatInfo::kCanUseTexStorage_Flag);
 }
 
 static GrPixelConfig validate_sized_format(GrGLFormat format,
@@ -4056,12 +4010,12 @@
 
 GrBackendFormat GrGLCaps::onGetDefaultBackendFormat(GrColorType ct,
                                                     GrRenderable renderable) const {
-    // TODO: make use of renderable.
     auto format = this->getFormatFromColorType(ct);
     if (format == GrGLFormat::kUnknown) {
         return GrBackendFormat();
     }
-    return GrBackendFormat::MakeGL(GrGLFormatToEnum(format), GR_GL_TEXTURE_2D);
+    // TODO: plumb 'renderable' into getSizedInternalFormat (or, at least, make use of it)
+    return GrBackendFormat::MakeGL(this->getSizedInternalFormat(format), GR_GL_TEXTURE_2D);
 }
 
 GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType(
@@ -4073,6 +4027,8 @@
     SK_ABORT("Invalid compression type");
 }
 
+bool GrGLCaps::canClearTextureOnCreation() const { return fClearTextureSupport; }
+
 GrSwizzle GrGLCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
     const auto& info = this->getFormatInfo(format.asGLFormat());
     for (int i = 0; i < info.fColorTypeInfoCount; ++i) {
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index d936cc2..24f9f63 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -142,36 +142,13 @@
         return fColorTypeToFormatTable[idx];
     }
 
-    /**
-     * Gets the internal format to use with glTexImage...() and glTexStorage...(). May be sized or
-     * base depending upon the GL. Not applicable to compressed textures.
-     */
-    GrGLenum getTexImageOrStorageInternalFormat(GrGLFormat format) const {
-        return this->getFormatInfo(format).fInternalFormatForTexImageOrStorage;
+    GrGLenum formatSizedInternalFormat(GrGLFormat format) const {
+        return this->getFormatInfo(format).fSizedInternalFormat;
     }
 
-    /**
-     * Gets the external format and type to pass to glTexImage2D with nullptr to create an
-     * uninitialized texture. See getTexImageOrStorageInternalFormat() for the internal format.
-     */
-    void getTexImageExternalFormatAndType(GrGLFormat surfaceFormat, GrGLenum* externalFormat,
-                                          GrGLenum* externalType) const;
-
-    /**
-     * Given a src data color type and a color type interpretation for a texture of a given format
-     * this provides the external GL format and type to use with glTexSubImage2d. The color types
-     * should originate from supportedWritePixelsColorType().
-     */
-    void getTexSubImageExternalFormatAndType(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
-                                             GrColorType memoryColorType, GrGLenum* externalFormat,
-                                             GrGLenum* externalType) const;
-
-    /**
-     * Gets the external format, type, and bytes per pixel to use when uploading zeros via
-     * glTexSubImage...() to clear the texture at creation.
-     */
-    void getTexSubImageZeroFormatTypeAndBpp(GrGLFormat format, GrGLenum* externalFormat,
-                                            GrGLenum* externalType, size_t* bpp) const;
+    void getTexImageFormats(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
+                            GrColorType memoryColorType, GrGLenum* internalFormat,
+                            GrGLenum* externalFormat, GrGLenum* externalType) const;
 
     void getReadPixelsFormat(GrGLFormat surfaceFormat, GrColorType surfaceColorType,
                              GrColorType memoryColorType, GrGLenum* externalFormat,
@@ -189,6 +166,14 @@
     bool formatSupportsTexStorage(GrGLFormat) const;
 
     /**
+     * Gets the internal format to use with glTexImage...() and glTexStorage...(). May be sized or
+     * base depending upon the GL. Not applicable to compressed textures.
+     */
+    GrGLenum getTexImageInternalFormat(GrGLFormat format) const {
+        return this->getFormatInfo(format).fInternalFormatForTexImage;
+    }
+
+    /**
      * Gets the internal format to use with glRenderbufferStorageMultisample...(). May be sized or
      * base depending upon the GL. Not applicable to compressed textures.
      */
@@ -196,6 +181,14 @@
         return this->getFormatInfo(format).fInternalFormatForRenderbuffer;
     }
 
+    GrGLenum getSizedInternalFormat(GrGLFormat format) const {
+        return this->getFormatInfo(format).fSizedInternalFormat;
+    }
+
+    GrGLenum getBaseInternalFormat(GrGLFormat format) const {
+        return this->getFormatInfo(format).fBaseInternalFormat;
+    }
+
     /**
      * Gets the default external type to use with glTex[Sub]Image... when the data pointer is null.
      */
@@ -411,6 +404,8 @@
 
     GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override;
 
+    bool canClearTextureOnCreation() const override;
+
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
 
@@ -623,30 +618,34 @@
                 still attach it to a FBO for blitting or reading pixels. */
             kFBOColorAttachment_Flag         = 0x2,
             kFBOColorAttachmentWithMSAA_Flag = 0x4,
-            kUseTexStorage_Flag              = 0x8,
+            kCanUseTexStorage_Flag           = 0x8,
         };
         uint32_t fFlags = 0;
 
         FormatType fFormatType = FormatType::kUnknown;
 
+        // Both compressed and uncompressed formats have base internal formats.
+        GrGLenum fBaseInternalFormat = 0;
+
+        // Not defined for compressed formats.
+        GrGLenum fSizedInternalFormat = 0;
+
         // Not defined for uncompressed formats. Passed to glCompressedTexImage...
         GrGLenum fCompressedInternalFormat = 0;
 
-        // Value to uses as the "internalformat" argument to glTexImage or glTexStorage. It is
-        // initialized in coordination with the presence/absence of the kUseTexStorage flag. In
-        // other words, it is only guaranteed to be compatible with glTexImage if the flag is not
-        // set and or with glTexStorage if the flag is set.
-        GrGLenum fInternalFormatForTexImageOrStorage = 0;
+        // Value to uses as the "internalformat" argument to glTexImage and glCompressedTexImage...
+        // Usually one of fBaseInternalFormat or fSizedInternalFormat but may vary depending on the
+        // particular format, GL version, extensions.
+        GrGLenum fInternalFormatForTexImage = 0;
 
         // Value to uses as the "internalformat" argument to glRenderbufferStorageMultisample...
+        // Usually one of fBaseInternalFormat or fSizedInternalFormat but may vary depending on the
+        // particular format, GL version, extensions.
         GrGLenum fInternalFormatForRenderbuffer = 0;
 
-        // Default values to use along with fInternalFormatForTexImageOrStorage for function
-        // glTexImage2D when not input providing data (passing nullptr). Not defined for compressed
-        // formats. Also used to upload zeros to initially clear a texture.
-        GrGLenum fDefaultExternalFormat = 0;
+        // Default value to use along with fBaseInternalFormat for functions such as glTexImage2D
+        // when not input providing data (passing nullptr). Not defined for compressed formats.
         GrGLenum fDefaultExternalType = 0;
-        GrGLenum fTexSubImageZeroDataBpp = 0;
 
         enum {
             // This indicates that a stencil format has not yet been determined for the config.
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 0917e79..8cbf08b 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -719,20 +719,22 @@
                                                          GrColorType colorType,
                                                          GrWrapOwnership ownership,
                                                          GrWrapCacheable cacheable) {
-    const GrGLCaps& caps = this->glCaps();
-
     GrGLTexture::Desc desc;
     if (!check_backend_texture(backendTex, colorType, this->glCaps(), &desc)) {
         return nullptr;
     }
-    SkASSERT(caps.isFormatRenderable(desc.fFormat, sampleCnt));
-    SkASSERT(caps.isFormatTexturable(desc.fFormat));
 
     // We don't support rendering to a EXTERNAL texture.
     if (GR_GL_TEXTURE_EXTERNAL == desc.fTarget) {
         return nullptr;
     }
 
+    const GrGLCaps& caps = this->glCaps();
+
+    if (!caps.isFormatRenderable(desc.fFormat, sampleCnt)) {
+        return nullptr;
+    }
+
     if (kBorrow_GrWrapOwnership == ownership) {
         desc.fOwnership = GrBackendObjectOwnership::kBorrowed;
     } else {
@@ -844,8 +846,8 @@
 
     SkASSERT(!GrGLFormatIsCompressed(glTex->format()));
     return this->uploadTexData(glTex->format(), surfaceColorType, glTex->width(), glTex->height(),
-                               glTex->target(), left, top, width, height, srcColorType, texels,
-                               mipLevelCount);
+                               glTex->target(), kWrite_UploadType, left, top,width,
+                               height, srcColorType, texels, mipLevelCount);
 }
 
 bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height,
@@ -894,11 +896,13 @@
     }
 
     GrGLFormat textureFormat = glTex->format();
+    // Internal format comes from the texture desc.
+    GrGLenum internalFormat;
     // External format and type come from the upload data.
     GrGLenum externalFormat = 0;
     GrGLenum externalType = 0;
-    this->glCaps().getTexSubImageExternalFormatAndType(
-            textureFormat, textureColorType, bufferColorType, &externalFormat, &externalType);
+    this->glCaps().getTexImageFormats(textureFormat, textureColorType, bufferColorType,
+                                      &internalFormat, &externalFormat, &externalType);
     if (!externalFormat || !externalType) {
         return false;
     }
@@ -929,6 +933,178 @@
                                           dstColorType, offsetAsPtr, width);
 }
 
+/**
+ * Creates storage space for the texture and fills it with texels.
+ *
+ * @param format         The format of the texture.
+ * @param interface      The GL interface in use.
+ * @param caps           The capabilities of the GL device.
+ * @param target         Which bound texture to target (GR_GL_TEXTURE_2D, e.g.)
+ * @param internalFormat The data format used for the internal storage of the texture. May be sized.
+ * @param internalFormatForTexStorage The data format used for the TexStorage API. Must be sized.
+ * @param externalFormat The data format used for the external storage of the texture.
+ * @param externalType   The type of the data used for the external storage of the texture.
+ * @param dataBpp        The bytes per pixel of the data in texels.
+ * @param texels         The texel data of the texture being created.
+ * @param mipLevelCount  Number of mipmap levels
+ * @param baseWidth      The width of the texture's base mipmap level
+ * @param baseHeight     The height of the texture's base mipmap level
+ */
+static bool allocate_and_populate_texture(GrGLFormat format,
+                                          const GrGLInterface& interface,
+                                          const GrGLCaps& caps,
+                                          GrGLenum target,
+                                          GrGLenum internalFormat,
+                                          GrGLenum internalFormatForTexStorage,
+                                          GrGLenum externalFormat,
+                                          GrGLenum externalType,
+                                          size_t dataBpp,
+                                          const GrMipLevel texels[],
+                                          int mipLevelCount,
+                                          int baseWidth,
+                                          int baseHeight,
+                                          bool* changedUnpackRowLength,
+                                          GrMipMapsStatus* mipMapsStatus) {
+    CLEAR_ERROR_BEFORE_ALLOC(&interface);
+
+    if (caps.formatSupportsTexStorage(format)) {
+        // We never resize or change formats of textures.
+        GL_ALLOC_CALL(&interface,
+                      TexStorage2D(target, SkTMax(mipLevelCount, 1), internalFormatForTexStorage,
+                                   baseWidth, baseHeight));
+        GrGLenum error = CHECK_ALLOC_ERROR(&interface);
+        if (error != GR_GL_NO_ERROR) {
+            return  false;
+        } else {
+            for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+                const void* currentMipData = texels[currentMipLevel].fPixels;
+                if (currentMipData == nullptr) {
+                    if (mipMapsStatus) {
+                        *mipMapsStatus = GrMipMapsStatus::kDirty;
+                    }
+                    continue;
+                }
+                int twoToTheMipLevel = 1 << currentMipLevel;
+                const int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
+                const int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
+
+                if (texels[currentMipLevel].fPixels) {
+                    const size_t trimRowBytes = currentWidth * dataBpp;
+                    const size_t rowBytes = texels[currentMipLevel].fRowBytes;
+                    if (rowBytes != trimRowBytes) {
+                        SkASSERT(caps.writePixelsRowBytesSupport());
+                        GrGLint rowLength = static_cast<GrGLint>(rowBytes / dataBpp);
+                        GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
+                        *changedUnpackRowLength = true;
+                    } else if (*changedUnpackRowLength) {
+                        SkASSERT(caps.writePixelsRowBytesSupport());
+                        GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+                        *changedUnpackRowLength = false;
+                    }
+                }
+
+                GR_GL_CALL(&interface,
+                           TexSubImage2D(target,
+                                         currentMipLevel,
+                                         0, // left
+                                         0, // top
+                                         currentWidth,
+                                         currentHeight,
+                                         externalFormat, externalType,
+                                         currentMipData));
+            }
+            return true;
+        }
+    } else {
+        if (!mipLevelCount) {
+            GL_ALLOC_CALL(&interface,
+                          TexImage2D(target,
+                                     0,
+                                     internalFormat,
+                                     baseWidth,
+                                     baseHeight,
+                                     0, // border
+                                     externalFormat, externalType,
+                                     nullptr));
+            GrGLenum error = CHECK_ALLOC_ERROR(&interface);
+            if (error != GR_GL_NO_ERROR) {
+                return false;
+            }
+        } else {
+            for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+                int twoToTheMipLevel = 1 << currentMipLevel;
+                const int currentWidth = SkTMax(1, baseWidth / twoToTheMipLevel);
+                const int currentHeight = SkTMax(1, baseHeight / twoToTheMipLevel);
+
+                const void* currentMipData = texels[currentMipLevel].fPixels;
+                if (currentMipData) {
+                    const size_t trimRowBytes = currentWidth * dataBpp;
+                    const size_t rowBytes = texels[currentMipLevel].fRowBytes;
+                    if (rowBytes != trimRowBytes) {
+                        SkASSERT(caps.writePixelsRowBytesSupport());
+                        GrGLint rowLength = static_cast<GrGLint>(rowBytes / dataBpp);
+                        GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
+                        *changedUnpackRowLength = true;
+                    } else if (*changedUnpackRowLength) {
+                        SkASSERT(caps.writePixelsRowBytesSupport());
+                        GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+                        *changedUnpackRowLength = false;
+                    }
+                } else if (mipMapsStatus) {
+                    *mipMapsStatus = GrMipMapsStatus::kDirty;
+                }
+
+                // We are considering modifying the interface to GrGpu to no longer allow data to
+                // be provided when creating a texture. To test whether that is feasible for
+                // performance on ES2 GPUs without tex storage we're calling glTexImage2D and then
+                // glTexSubImage2D and hoping we don't get any performance regressions.
+                GL_ALLOC_CALL(&interface,
+                              TexImage2D(target,
+                                         currentMipLevel,
+                                         internalFormat,
+                                         currentWidth,
+                                         currentHeight,
+                                         0, // border
+                                         externalFormat, externalType,
+                                         nullptr));
+                if (currentMipData) {
+                    GR_GL_CALL(&interface,
+                               TexSubImage2D(target,
+                                             currentMipLevel,
+                                             0, 0,
+                                             currentWidth,
+                                             currentHeight,
+                                             externalFormat,
+                                             externalType,
+                                             currentMipData));
+                }
+                GrGLenum error = CHECK_ALLOC_ERROR(&interface);
+                if (error != GR_GL_NO_ERROR) {
+                    return false;
+                }
+            }
+        }
+    }
+    return true;
+}
+
+/**
+ * After a texture is created, any state which was altered during its creation
+ * needs to be restored.
+ *
+ * @param interface          The GL interface to use.
+ * @param caps               The capabilities of the GL device.
+ * @param restoreGLRowLength Should the row length unpacking be restored?
+ * @param glFlipY            Did GL flip the texture vertically?
+ */
+static void restore_pixelstore_state(const GrGLInterface& interface, const GrGLCaps& caps,
+                                     bool restoreGLRowLength) {
+    if (restoreGLRowLength) {
+        SkASSERT(caps.writePixelsRowBytesSupport());
+        GR_GL_CALL(&interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
+    }
+}
+
 void GrGLGpu::unbindCpuToGpuXferBuffer() {
     auto* xferBufferState = this->hwBufferState(GrGpuBufferType::kXferCpuToGpu);
     if (!xferBufferState->fBoundBufferUniqueID.isInvalid()) {
@@ -937,10 +1113,11 @@
     }
 }
 
-bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth,
-                            int texHeight, GrGLenum target, int left, int top, int width,
-                            int height, GrColorType srcColorType, const GrMipLevel texels[],
-                            int mipLevelCount, GrMipMapsStatus* mipMapsStatus) {
+bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType,
+                            int texWidth, int texHeight, GrGLenum target, UploadType uploadType,
+                            int left, int top, int width, int height, GrColorType srcColorType,
+                            const GrMipLevel texels[],int mipLevelCount,
+                            GrMipMapsStatus* mipMapsStatus) {
     // If we're uploading compressed data then we should be using uploadCompressedTexData
     SkASSERT(!GrGLFormatIsCompressed(textureFormat));
 
@@ -964,15 +1141,19 @@
         return false;
     }
 
+    // Internal format comes from the texture desc.
+    GrGLenum internalFormat;
     // External format and type come from the upload data.
     GrGLenum externalFormat;
     GrGLenum externalType;
-    this->glCaps().getTexSubImageExternalFormatAndType(
-            textureFormat, textureColorType, srcColorType, &externalFormat, &externalType);
+    this->glCaps().getTexImageFormats(textureFormat, textureColorType, srcColorType,
+                                      &internalFormat, &externalFormat, &externalType);
     if (!externalFormat || !externalType) {
         return false;
     }
 
+    GrGLenum internalFormatForTexStorage = this->glCaps().getSizedInternalFormat(textureFormat);
+
     /*
      *  Check whether to allocate a temporary buffer for flipping y or
      *  because our srcData has extra bytes past each row. If so, we need
@@ -981,40 +1162,61 @@
      */
     bool restoreGLRowLength = false;
 
+    // in case we need a temporary, trimmed copy of the src pixels
+    SkAutoSMalloc<128 * 128> tempStorage;
+
     if (mipMapsStatus) {
         *mipMapsStatus = (mipLevelCount > 1) ?
                 GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated;
     }
 
-    GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+    if (mipLevelCount) {
+        GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
+    }
 
-    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
-        if (!texels[currentMipLevel].fPixels) {
-            if (mipMapsStatus) {
-                *mipMapsStatus = GrMipMapsStatus::kDirty;
+    bool succeeded = true;
+    if (kNewTexture_UploadType == uploadType) {
+        if (0 == left && 0 == top && texWidth == width && texHeight == height) {
+            succeeded = allocate_and_populate_texture(
+                    textureFormat, *interface, caps, target, internalFormat,
+                    internalFormatForTexStorage, externalFormat, externalType, bpp, texels,
+                    mipLevelCount, width, height, &restoreGLRowLength, mipMapsStatus);
+        } else {
+            succeeded = false;
+        }
+    } else {
+        for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+            if (!texels[currentMipLevel].fPixels) {
+                if (mipMapsStatus) {
+                    *mipMapsStatus = GrMipMapsStatus::kDirty;
+                }
+                continue;
             }
-            continue;
-        }
-        int twoToTheMipLevel = 1 << currentMipLevel;
-        const int currentWidth = SkTMax(1, width / twoToTheMipLevel);
-        const int currentHeight = SkTMax(1, height / twoToTheMipLevel);
-        const size_t trimRowBytes = currentWidth * bpp;
-        const size_t rowBytes = texels[currentMipLevel].fRowBytes;
+            int twoToTheMipLevel = 1 << currentMipLevel;
+            const int currentWidth = SkTMax(1, width / twoToTheMipLevel);
+            const int currentHeight = SkTMax(1, height / twoToTheMipLevel);
+            const size_t trimRowBytes = currentWidth * bpp;
+            const size_t rowBytes = texels[currentMipLevel].fRowBytes;
 
-        if (caps.writePixelsRowBytesSupport() && (rowBytes != trimRowBytes || restoreGLRowLength)) {
-            GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
-            GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
-            restoreGLRowLength = true;
-        }
+            if (caps.writePixelsRowBytesSupport() && rowBytes != trimRowBytes) {
+                GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp);
+                GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength));
+                restoreGLRowLength = true;
+            }
 
-        GL_CALL(TexSubImage2D(target, currentMipLevel, left, top, currentWidth, currentHeight,
-                              externalFormat, externalType, texels[currentMipLevel].fPixels));
+            GL_CALL(TexSubImage2D(target,
+                                  currentMipLevel,
+                                  left, top,
+                                  currentWidth,
+                                  currentHeight,
+                                  externalFormat, externalType,
+                                  texels[currentMipLevel].fPixels));
+        }
     }
-    if (restoreGLRowLength) {
-        SkASSERT(caps.writePixelsRowBytesSupport());
-        GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0));
-    }
-    return true;
+
+    restore_pixelstore_state(*interface, caps, restoreGLRowLength);
+
+    return succeeded;
 }
 
 bool GrGLGpu::uploadCompressedTexData(GrGLFormat format,
@@ -1026,7 +1228,7 @@
     const GrGLCaps& caps = this->glCaps();
 
     // We only need the internal format for compressed 2D textures.
-    GrGLenum internalFormat = caps.getTexImageOrStorageInternalFormat(format);
+    GrGLenum internalFormat = caps.getTexImageInternalFormat(format);
     if (!internalFormat) {
         return 0;
     }
@@ -1225,17 +1427,16 @@
                                           int renderTargetSampleCnt,
                                           SkBudgeted budgeted,
                                           GrProtected isProtected,
-                                          int mipLevelCount,
-                                          uint32_t levelClearMask) {
+                                          const GrMipLevel texels[],
+                                          int mipLevelCount) {
     // We don't support protected textures in GL.
     if (isProtected == GrProtected::kYes) {
         return nullptr;
     }
     SkASSERT(GrGLCaps::kNone_MSFBOType != this->glCaps().msFBOType() || renderTargetSampleCnt == 1);
 
-    SkASSERT(mipLevelCount > 0);
-    GrMipMapsStatus mipMapsStatus =
-            mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+
+    GrMipMapsStatus mipMapsStatus;
     GrGLTextureParameters::SamplerOverriddenState initialState;
     GrGLTexture::Desc texDesc;
     texDesc.fSize = {desc.fWidth, desc.fHeight};
@@ -1246,8 +1447,18 @@
     SkASSERT(texDesc.fFormat != GrGLFormat::kUnknown);
     SkASSERT(!GrGLFormatIsCompressed(texDesc.fFormat));
 
-    texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, texDesc.fFormat, renderable,
-                                        &initialState, mipLevelCount);
+    // TODO: Take these as parameters.
+    auto textureColorType = GrPixelConfigToColorType(desc.fConfig);
+    auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
+    texDesc.fID = this->createTexture2D({desc.fWidth, desc.fHeight},
+                                        texDesc.fFormat,
+                                        renderable,
+                                        &initialState,
+                                        textureColorType,
+                                        srcColorType,
+                                        texels,
+                                        mipLevelCount,
+                                        &mipMapsStatus);
 
     if (!texDesc.fID) {
         return return_null_texture();
@@ -1272,49 +1483,16 @@
     // The non-sampler params are still at their default values.
     tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(),
                            fResetTimestampForTextureParameters);
-    if (levelClearMask) {
-        GrGLenum externalFormat, externalType;
-        size_t bpp;
-        this->glCaps().getTexSubImageZeroFormatTypeAndBpp(texDesc.fFormat, &externalFormat,
-                                                          &externalType, &bpp);
-        if (this->glCaps().clearTextureSupport()) {
-            for (int i = 0; i < mipLevelCount; ++i) {
-                if (levelClearMask & (1U << i)) {
-                    GL_CALL(ClearTexImage(tex->textureID(), i, externalFormat, externalType,
-                                          nullptr));
-                }
-            }
-        } else if (this->glCaps().canFormatBeFBOColorAttachment(format.asGLFormat()) &&
-                   !this->glCaps().performColorClearsAsDraws()) {
-            this->disableScissor();
-            this->disableWindowRectangles();
-            this->flushColorWrite(true);
-            this->flushClearColor(0, 0, 0, 0);
-            for (int i = 0; i < mipLevelCount; ++i) {
-                if (levelClearMask & (1U << i)) {
-                    this->bindSurfaceFBOForPixelOps(tex.get(), i, GR_GL_FRAMEBUFFER,
-                                                    kDst_TempFBOTarget);
-                    GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT));
-                    this->unbindSurfaceFBOForPixelOps(tex.get(), i, GR_GL_FRAMEBUFFER);
-                }
-            }
-        } else {
-            std::unique_ptr<char[]> zeros;
-            GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1));
-            for (int i = 0; i < mipLevelCount; ++i) {
-                if (levelClearMask & (1U << i)) {
-                    int levelWidth  = SkTMax(1, texDesc.fSize.width()  >> i);
-                    int levelHeight = SkTMax(1, texDesc.fSize.height() >> i);
-                    // Levels only get smaller as we proceed. Once we create a zeros use it for all
-                    // smaller levels that need clearing.
-                    if (!zeros) {
-                        size_t size = levelWidth * levelHeight * bpp;
-                        zeros.reset(new char[size]());
-                    }
-                    this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, tex->textureID());
-                    GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, i, 0, 0, levelWidth, levelHeight,
-                                          externalFormat, externalType, zeros.get()));
-                }
+    bool clearLevelsWithoutData =
+            this->caps()->shouldInitializeTextures() && this->glCaps().clearTextureSupport();
+
+    if (clearLevelsWithoutData) {
+        static constexpr uint32_t kZero = 0;
+        int levelCnt = SkTMax(1, tex->texturePriv().maxMipMapLevel());
+        for (int i = 0; i < levelCnt; ++i) {
+            if (i >= mipLevelCount || !texels[i].fPixels) {
+                GL_CALL(ClearTexImage(tex->textureID(), i, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE,
+                                      &kZero));
             }
         }
     }
@@ -1378,11 +1556,46 @@
         // Default to unsupported, set this if we find a stencil format that works.
         int firstWorkingStencilFormatIndex = -1;
 
-        GrGLuint colorID =
-                this->createTexture2D({kSize, kSize}, format, GrRenderable::kYes, nullptr, 1);
-        if (!colorID) {
+        // Create color texture
+        GrGLuint colorID = 0;
+        GL_CALL(GenTextures(1, &colorID));
+        this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
+        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+                              GR_GL_TEXTURE_MAG_FILTER,
+                              GR_GL_NEAREST));
+        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+                              GR_GL_TEXTURE_MIN_FILTER,
+                              GR_GL_NEAREST));
+        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+                              GR_GL_TEXTURE_WRAP_S,
+                              GR_GL_CLAMP_TO_EDGE));
+        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+                              GR_GL_TEXTURE_WRAP_T,
+                              GR_GL_CLAMP_TO_EDGE));
+
+        GrGLenum internalFormat = this->glCaps().getTexImageInternalFormat(format);
+        GrGLenum externalFormat = this->glCaps().getBaseInternalFormat(format);
+        GrGLenum externalType   = this->glCaps().getFormatDefaultExternalType(format);
+        if (!internalFormat || !externalFormat || !externalType) {
             return -1;
         }
+
+        this->unbindCpuToGpuXferBuffer();
+        CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
+        GL_ALLOC_CALL(this->glInterface(), TexImage2D(GR_GL_TEXTURE_2D,
+                                                      0,
+                                                      internalFormat,
+                                                      kSize,
+                                                      kSize,
+                                                      0,
+                                                      externalFormat,
+                                                      externalType,
+                                                      nullptr));
+        if (GR_GL_NO_ERROR != CHECK_ALLOC_ERROR(this->glInterface())) {
+            GL_CALL(DeleteTextures(1, &colorID));
+            return -1;
+        }
+
         // unbind the texture from the texture unit before binding it to the frame buffer
         GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
 
@@ -1478,7 +1691,11 @@
                                   GrGLFormat format,
                                   GrRenderable renderable,
                                   GrGLTextureParameters::SamplerOverriddenState* initialState,
-                                  int mipLevelCount) {
+                                  GrColorType textureColorType,
+                                  GrColorType srcColorType,
+                                  const GrMipLevel texels[],
+                                  int mipLevelCount,
+                                  GrMipMapsStatus* mipMapsStatus) {
     SkASSERT(format != GrGLFormat::kUnknown);
     SkASSERT(!GrGLFormatIsCompressed(format));
 
@@ -1496,46 +1713,25 @@
         GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_USAGE, GR_GL_FRAMEBUFFER_ATTACHMENT));
     }
 
-    if (initialState) {
-        *initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
-    } else {
-        set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
-    }
+    *initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D);
 
-    GrGLenum internalFormat = this->glCaps().getTexImageOrStorageInternalFormat(format);
-
-    bool success = false;
-    if (internalFormat) {
-        CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
-        if (this->glCaps().formatSupportsTexStorage(format)) {
-            GL_ALLOC_CALL(this->glInterface(),
-                          TexStorage2D(GR_GL_TEXTURE_2D, SkTMax(mipLevelCount, 1), internalFormat,
-                                       size.width(), size.height()));
-            success = (GR_GL_NO_ERROR == CHECK_ALLOC_ERROR(this->glInterface()));
-        } else {
-            GrGLenum externalFormat, externalType;
-            this->glCaps().getTexImageExternalFormatAndType(format, &externalFormat, &externalType);
-            GrGLenum error = GR_GL_NO_ERROR;
-            if (externalFormat && externalType) {
-                for (int level = 0; level < mipLevelCount && error == GR_GL_NO_ERROR; level++) {
-                    const int twoToTheMipLevel = 1 << level;
-                    const int currentWidth = SkTMax(1, size.width() / twoToTheMipLevel);
-                    const int currentHeight = SkTMax(1, size.height() / twoToTheMipLevel);
-                    GL_ALLOC_CALL(
-                            this->glInterface(),
-                            TexImage2D(GR_GL_TEXTURE_2D, level, internalFormat, currentWidth,
-                                       currentHeight, 0, externalFormat, externalType, nullptr));
-                    error = CHECK_ALLOC_ERROR(this->glInterface());
-                }
-                success = (GR_GL_NO_ERROR == error);
-            }
-        }
+    if (!this->uploadTexData(format,
+                             textureColorType,
+                             size.width(), size.height(),
+                             GR_GL_TEXTURE_2D,
+                             kNewTexture_UploadType,
+                             0,
+                             0,
+                             size.width(),
+                             size.height(),
+                             srcColorType,
+                             texels,
+                             mipLevelCount,
+                             mipMapsStatus)) {
+        GL_CALL(DeleteTextures(1, &id));
+        return 0;
     }
-    if (success) {
-        return id;
-    }
-    GL_CALL(DeleteTextures(1, &id));
-    return 0;
+    return id;
 }
 
 GrStencilAttachment* GrGLGpu::createStencilAttachmentForRenderTarget(
@@ -1965,7 +2161,7 @@
         }
     } else {
         // Use a temporary FBO.
-        this->bindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
+        this->bindSurfaceFBOForPixelOps(surface, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
         fHWBoundRenderTargetUniqueID.makeInvalid();
     }
 
@@ -2006,7 +2202,7 @@
     }
 
     if (!renderTarget) {
-        this->unbindSurfaceFBOForPixelOps(surface, 0, GR_GL_FRAMEBUFFER);
+        this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, surface);
     }
     return true;
 }
@@ -2819,10 +3015,10 @@
 }
 
 // If a temporary FBO was created, its non-zero ID is returned.
-void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
+void GrGLGpu::bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
                                         TempFBOTarget tempFBOTarget) {
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
-    if (!rt || mipLevel > 0) {
+    if (!rt) {
         SkASSERT(surface->asTexture());
         GrGLTexture* texture = static_cast<GrGLTexture*>(surface->asTexture());
         GrGLuint texID = texture->textureID();
@@ -2835,20 +3031,20 @@
         }
 
         this->bindFramebuffer(fboTarget, *tempFBOID);
-        GR_GL_CALL(
-                this->glInterface(),
-                FramebufferTexture2D(fboTarget, GR_GL_COLOR_ATTACHMENT0, target, texID, mipLevel));
-        if (mipLevel == 0) {
-            texture->baseLevelWasBoundToFBO();
-        }
+        GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
+                                                             GR_GL_COLOR_ATTACHMENT0,
+                                                             target,
+                                                             texID,
+                                                             0));
+        texture->baseLevelWasBoundToFBO();
     } else {
         this->bindFramebuffer(fboTarget, rt->renderFBOID());
     }
 }
 
-void GrGLGpu::unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget) {
+void GrGLGpu::unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface) {
     // bindSurfaceFBOForPixelOps temporarily binds textures that are not render targets to
-    if (mipLevel > 0 || !surface->asRenderTarget()) {
+    if (!surface->asRenderTarget()) {
         SkASSERT(surface->asTexture());
         GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target();
         GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
@@ -3230,7 +3426,7 @@
     int h = srcRect.height();
     // We don't swizzle at all in our copies.
     this->bindTexture(0, GrSamplerState::ClampNearest(), GrSwizzle::RGBA(), srcTex);
-    this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget);
+    this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, kDst_TempFBOTarget);
     this->flushViewport(dst->width(), dst->height());
     fHWBoundRenderTargetUniqueID.makeInvalid();
     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
@@ -3273,7 +3469,7 @@
         this->flushFramebufferSRGB(true);
     }
     GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
-    this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_FRAMEBUFFER);
+    this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, dst);
     // The rect is already in device space so we pass in kTopLeft so no flip is done.
     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
     return true;
@@ -3282,7 +3478,7 @@
 void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
                                            const SkIPoint& dstPoint) {
     SkASSERT(can_copy_texsubimage(dst, src, this->glCaps()));
-    this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
+    this->bindSurfaceFBOForPixelOps(src, GR_GL_FRAMEBUFFER, kSrc_TempFBOTarget);
     GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture());
     SkASSERT(dstTex);
     // We modified the bound FBO
@@ -3293,7 +3489,7 @@
                               dstPoint.fX, dstPoint.fY,
                               srcRect.fLeft, srcRect.fTop,
                               srcRect.width(), srcRect.height()));
-    this->unbindSurfaceFBOForPixelOps(src, 0, GR_GL_FRAMEBUFFER);
+    this->unbindTextureFBOForPixelOps(GR_GL_FRAMEBUFFER, src);
     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
                                         srcRect.width(), srcRect.height());
     // The rect is already in device space so we pass in kTopLeft so no flip is done.
@@ -3311,8 +3507,8 @@
         }
     }
 
-    this->bindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
-    this->bindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
+    this->bindSurfaceFBOForPixelOps(dst, GR_GL_DRAW_FRAMEBUFFER, kDst_TempFBOTarget);
+    this->bindSurfaceFBOForPixelOps(src, GR_GL_READ_FRAMEBUFFER, kSrc_TempFBOTarget);
     // We modified the bound FBO
     fHWBoundRenderTargetUniqueID.makeInvalid();
 
@@ -3329,8 +3525,8 @@
                             dstRect.fRight,
                             dstRect.fBottom,
                             GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
-    this->unbindSurfaceFBOForPixelOps(dst, 0, GR_GL_DRAW_FRAMEBUFFER);
-    this->unbindSurfaceFBOForPixelOps(src, 0, GR_GL_READ_FRAMEBUFFER);
+    this->unbindTextureFBOForPixelOps(GR_GL_DRAW_FRAMEBUFFER, dst);
+    this->unbindTextureFBOForPixelOps(GR_GL_READ_FRAMEBUFFER, src);
 
     // The rect is already in device space so we pass in kTopLeft so no flip is done.
     this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
@@ -3568,7 +3764,8 @@
     GrGLTextureInfo info;
     GrGLTextureParameters::SamplerOverriddenState initialState;
 
-    SkTDArray<GrMipLevel> texels;
+    int mipLevelCount = 0;
+    SkAutoTMalloc<GrMipLevel> texels;
     SkAutoMalloc pixelStorage;
     SkImage::CompressionType compressionType;
     if (GrGLFormatToCompressionType(glFormat, &compressionType)) {
@@ -3594,15 +3791,16 @@
         info.fTarget = GR_GL_TEXTURE_2D;
     } else {
         if (srcPixels) {
-            texels.append(1);
-            texels[0] = {srcPixels, rowBytes};
+            mipLevelCount = 1;
+            texels.reset(mipLevelCount);
+            texels.get()[0] = {srcPixels, rowBytes};
         } else if (color) {
-            int mipLevelCount = 1;
+            mipLevelCount = 1;
             if (GrMipMapped::kYes == mipMapped) {
                 mipLevelCount = SkMipMap::ComputeLevelCount(w, h) + 1;
             }
 
-            texels.append(mipLevelCount);
+            texels.reset(mipLevelCount);
             SkTArray<size_t> individualMipOffsets(mipLevelCount);
 
             size_t bytesPerPixel = GrBytesPerPixel(config);
@@ -3619,7 +3817,7 @@
                 int twoToTheMipLevel = 1 << i;
                 int currentWidth = SkTMax(1, w / twoToTheMipLevel);
 
-                texels[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
+                texels.get()[i] = {&(tmpPixels[offset]), currentWidth * bytesPerPixel};
             }
         }
         GrSurfaceDesc desc;
@@ -3629,19 +3827,20 @@
 
         info.fTarget = GR_GL_TEXTURE_2D;
         info.fFormat = GrGLFormatToEnum(glFormat);
-        info.fID = this->createTexture2D({desc.fWidth, desc.fHeight}, glFormat, renderable,
-                                         &initialState, SkTMax(1, texels.count()));
+        // TODO: Take these as parameters.
+        auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
+        info.fID = this->createTexture2D({desc.fWidth, desc.fHeight},
+                                         glFormat,
+                                         renderable,
+                                         &initialState,
+                                         textureColorType,
+                                         srcColorType,
+                                         texels,
+                                         mipLevelCount,
+                                         nullptr);
         if (!info.fID) {
             return GrBackendTexture();  // invalid
         }
-        auto srcColorType = GrPixelConfigToColorType(desc.fConfig);
-        if (!texels.empty() &&
-            !this->uploadTexData(glFormat, textureColorType, desc.fWidth, desc.fHeight,
-                                 GR_GL_TEXTURE_2D, 0, 0, desc.fWidth, desc.fHeight, srcColorType,
-                                 texels.begin(), texels.count())) {
-            GL_CALL(DeleteTextures(1, &info.fID));
-            return GrBackendTexture();
-        }
     }
 
     // unbind the texture from the texture unit to avoid asserts
@@ -3689,7 +3888,17 @@
     if (!this->glCaps().isFormatRenderable(format, 1)) {
         return {};
     }
-    bool useTexture = format == GrGLFormat::kBGRA8;
+    bool useTexture = false;
+    GrGLenum colorBufferFormat;
+    GrGLenum externalFormat = 0, externalType = 0;
+    if (format == GrGLFormat::kBGRA8) {
+        // BGRA render buffers are not supported.
+        this->glCaps().getTexImageFormats(format, colorType, colorType, &colorBufferFormat,
+                                          &externalFormat, &externalType);
+        useTexture = true;
+    } else {
+        colorBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
+    }
     int sFormatIdx = this->getCompatibleStencilIndex(format);
     if (sFormatIdx < 0) {
         return {};
@@ -3722,7 +3931,7 @@
 
     GrGLFramebufferInfo info;
     info.fFBOID = 0;
-    info.fFormat = GrGLFormatToEnum(format);
+    info.fFormat = this->glCaps().formatSizedInternalFormat(format);
     GL_CALL(GenFramebuffers(1, &info.fFBOID));
     if (!info.fFBOID) {
         deleteIDs();
@@ -3733,19 +3942,15 @@
 
     this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID);
     if (useTexture) {
-        GrGLTextureParameters::SamplerOverriddenState initialState;
-        colorID = this->createTexture2D({w, h}, format, GrRenderable::kYes, &initialState, 1);
-        if (!colorID) {
-            deleteIDs();
-            return {};
-        }
+        this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, colorID);
+        GL_CALL(TexImage2D(GR_GL_TEXTURE_2D, 0, colorBufferFormat, w, h, 0, externalFormat,
+                           externalType, nullptr));
         GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0, GR_GL_TEXTURE_2D,
                                      colorID, 0));
     } else {
-        GrGLenum renderBufferFormat = this->glCaps().getRenderbufferInternalFormat(format);
         GL_CALL(BindRenderbuffer(GR_GL_RENDERBUFFER, colorID));
         GL_ALLOC_CALL(this->glInterface(),
-                      RenderbufferStorage(GR_GL_RENDERBUFFER, renderBufferFormat, w, h));
+                      RenderbufferStorage(GR_GL_RENDERBUFFER, colorBufferFormat, w, h));
         GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER, GR_GL_COLOR_ATTACHMENT0,
                                         GR_GL_RENDERBUFFER, colorID));
     }
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 908ba5d..efacc32 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -195,8 +195,8 @@
                                      int renderTargetSampleCnt,
                                      SkBudgeted,
                                      GrProtected,
-                                     int mipLevelCount,
-                                     uint32_t levelClearMask) override;
+                                     const GrMipLevel[],
+                                     int mipLevelCount) override;
     sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
                                                SkImage::CompressionType compression, SkBudgeted,
                                                const void* data) override;
@@ -228,7 +228,11 @@
                              GrGLFormat format,
                              GrRenderable,
                              GrGLTextureParameters::SamplerOverriddenState* initialState,
-                             int mipLevelCount);
+                             GrColorType textureColorType,
+                             GrColorType srcColorType,
+                             const GrMipLevel texels[],
+                             int mipLevelCount,
+                             GrMipMapsStatus* mipMapsStatus);
 
     GrGLuint createCompressedTexture2D(const SkISize& size, GrGLFormat format,
                                        SkImage::CompressionType compression,
@@ -373,9 +377,15 @@
 
     void flushFramebufferSRGB(bool enable);
 
-    bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth,
-                       int texHeight, GrGLenum target, int left, int top, int width, int height,
-                       GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount,
+    // helper for onCreateTexture and writeTexturePixels
+    enum UploadType {
+        kNewTexture_UploadType,   // we are creating a new texture
+        kWrite_UploadType,        // we are using TexSubImage2D to copy data to an existing texture
+    };
+    bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType,
+                       int texWidth, int texHeight, GrGLenum target, UploadType uploadType,
+                       int left, int top, int width, int height, GrColorType srcColorType,
+                       const GrMipLevel texels[], int mipLevelCount,
                        GrMipMapsStatus* mipMapsStatus = nullptr);
 
     // Helper for onCreateCompressedTexture. Compressed textures are read-only so we only use this
@@ -398,11 +408,11 @@
     // Binds a surface as a FBO for copying, reading, or clearing. If the surface already owns an
     // FBO ID then that ID is bound. If not the surface is temporarily bound to a FBO and that FBO
     // is bound. This must be paired with a call to unbindSurfaceFBOForPixelOps().
-    void bindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget,
+    void bindSurfaceFBOForPixelOps(GrSurface* surface, GrGLenum fboTarget,
                                    TempFBOTarget tempFBOTarget);
 
     // Must be called if bindSurfaceFBOForPixelOps was used to bind a surface for copying.
-    void unbindSurfaceFBOForPixelOps(GrSurface* surface, int mipLevel, GrGLenum fboTarget);
+    void unbindTextureFBOForPixelOps(GrGLenum fboTarget, GrSurface* surface);
 
 #ifdef SK_ENABLE_DUMP_GPU
     void onDumpJSON(SkJSONWriter*) const override;
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
index 9a6148cc..911f571 100644
--- a/src/gpu/mock/GrMockCaps.h
+++ b/src/gpu/mock/GrMockCaps.h
@@ -132,6 +132,8 @@
         return {};
     }
 
+    bool canClearTextureOnCreation() const override { return true; }
+
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override {
         return GrSwizzle();
     }
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
index bc91c75..817bb08 100644
--- a/src/gpu/mock/GrMockGpu.cpp
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -137,8 +137,8 @@
                                             int renderTargetSampleCnt,
                                             SkBudgeted budgeted,
                                             GrProtected isProtected,
-                                            int mipLevelCount,
-                                            uint32_t levelClearMask) {
+                                            const GrMipLevel texels[],
+                                            int mipLevelCount) {
     if (fMockOptions.fFailTextureAllocations) {
         return nullptr;
     }
@@ -146,8 +146,14 @@
     GrColorType ct = format.asMockColorType();
     SkASSERT(ct != GrColorType::kUnknown);
 
-    GrMipMapsStatus mipMapsStatus =
-            mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+    GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid
+                                                      : GrMipMapsStatus::kNotAllocated;
+    for (int i = 0; i < mipLevelCount; ++i) {
+        if (!texels[i].fPixels) {
+            mipMapsStatus = GrMipMapsStatus::kDirty;
+            break;
+        }
+    }
     GrMockTextureInfo texInfo(ct, NextInternalTextureID());
     if (renderable == GrRenderable::kYes) {
         GrMockRenderTargetInfo rtInfo(ct, NextInternalRenderTargetID());
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index 7fec665..7334591 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -63,8 +63,8 @@
                                      int renderTargetSampleCnt,
                                      SkBudgeted,
                                      GrProtected,
-                                     int mipLevelCount,
-                                     uint32_t levelClearMask) override;
+                                     const GrMipLevel[],
+                                     int mipLevelCount) override;
 
     sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
                                                SkImage::CompressionType, SkBudgeted,
diff --git a/src/gpu/mtl/GrMtlCaps.h b/src/gpu/mtl/GrMtlCaps.h
index d56f3a2..b557008 100644
--- a/src/gpu/mtl/GrMtlCaps.h
+++ b/src/gpu/mtl/GrMtlCaps.h
@@ -78,6 +78,8 @@
         return fColorTypeToFormatTable[idx];
     }
 
+    bool canClearTextureOnCreation() const override { return true; }
+
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
 
diff --git a/src/gpu/mtl/GrMtlGpu.h b/src/gpu/mtl/GrMtlGpu.h
index 0027956..a944349 100644
--- a/src/gpu/mtl/GrMtlGpu.h
+++ b/src/gpu/mtl/GrMtlGpu.h
@@ -139,8 +139,8 @@
                                      int renderTargetSampleCnt,
                                      SkBudgeted budgeted,
                                      GrProtected,
-                                     int mipLevelCount,
-                                     uint32_t levelClearMask) override;
+                                     const GrMipLevel texels[],
+                                     int mipLevelCount) override;
     sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
                                                SkImage::CompressionType, SkBudgeted,
                                                const void* data) override {
diff --git a/src/gpu/mtl/GrMtlGpu.mm b/src/gpu/mtl/GrMtlGpu.mm
index 37bd80a..37fd1a8 100644
--- a/src/gpu/mtl/GrMtlGpu.mm
+++ b/src/gpu/mtl/GrMtlGpu.mm
@@ -400,13 +400,13 @@
                                            int renderTargetSampleCnt,
                                            SkBudgeted budgeted,
                                            GrProtected isProtected,
-                                           int mipLevelCount,
-                                           uint32_t levelClearMask) {
+                                           const GrMipLevel texels[],
+                                           int mipLevelCount) {
     // We don't support protected textures in Metal.
     if (isProtected == GrProtected::kYes) {
         return nullptr;
     }
-    SkASSERT(mipLevelCount > 0);
+    int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
 
     MTLPixelFormat mtlPixelFormat = GrBackendFormatAsMTLPixelFormat(format);
     SkASSERT(mtlPixelFormat != MTLPixelFormatInvalid);
@@ -422,7 +422,7 @@
     texDesc.width = desc.fWidth;
     texDesc.height = desc.fHeight;
     texDesc.depth = 1;
-    texDesc.mipmapLevelCount = mipLevelCount;
+    texDesc.mipmapLevelCount = mipLevels;
     texDesc.sampleCount = 1;
     texDesc.arrayLength = 1;
     // Make all textures have private gpu only access. We can use transfer buffers or textures
@@ -431,8 +431,17 @@
     texDesc.usage = MTLTextureUsageShaderRead;
     texDesc.usage |= (renderable == GrRenderable::kYes) ? MTLTextureUsageRenderTarget : 0;
 
-    GrMipMapsStatus mipMapsStatus =
-            mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+    GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated;
+    if (mipLevels > 1) {
+        mipMapsStatus = GrMipMapsStatus::kValid;
+        for (int i = 0; i < mipLevels; ++i) {
+            if (!texels[i].fPixels) {
+                mipMapsStatus = GrMipMapsStatus::kDirty;
+                break;
+            }
+        }
+    }
+
     if (renderable == GrRenderable::kYes) {
         tex = GrMtlTextureRenderTarget::MakeNewTextureRenderTarget(this, budgeted,
                                                                    desc, renderTargetSampleCnt,
@@ -445,9 +454,24 @@
         return nullptr;
     }
 
-    if (levelClearMask) {
-        auto colorType = GrPixelConfigToColorType(desc.fConfig);
-        this->clearTexture(tex.get(), colorType, levelClearMask);
+    auto colorType = GrPixelConfigToColorType(desc.fConfig);
+    if (mipLevelCount && texels[0].fPixels) {
+        if (!this->uploadToTexture(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType, texels,
+                                   mipLevelCount)) {
+            tex->unref();
+            return nullptr;
+        }
+    }
+
+    if (this->caps()->shouldInitializeTextures()) {
+        uint32_t levelMask = ~0;
+        SkASSERT(mipLevelCount < 32);
+        for (int i = 0; i < mipLevelCount; ++i) {
+            if (!texels[i].fPixels) {
+                levelMask &= ~(1 << i);
+            }
+        }
+        this->clearTexture(tex.get(), colorType, levelMask);
     }
 
     return tex;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 8881ed8..f15ee7d 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -1610,6 +1610,8 @@
     SK_ABORT("Invalid compression type");
 }
 
+bool GrVkCaps::canClearTextureOnCreation() const { return true; }
+
 GrSwizzle GrVkCaps::getTextureSwizzle(const GrBackendFormat& format, GrColorType colorType) const {
     VkFormat vkFormat;
     SkAssertResult(format.asVkFormat(&vkFormat));
diff --git a/src/gpu/vk/GrVkCaps.h b/src/gpu/vk/GrVkCaps.h
index 7141aaa..c781d51 100644
--- a/src/gpu/vk/GrVkCaps.h
+++ b/src/gpu/vk/GrVkCaps.h
@@ -171,6 +171,8 @@
         return fColorTypeToFormatTable[idx];
     }
 
+    bool canClearTextureOnCreation() const override;
+
     GrSwizzle getTextureSwizzle(const GrBackendFormat&, GrColorType) const override;
     GrSwizzle getOutputSwizzle(const GrBackendFormat&, GrColorType) const override;
 
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 7b68e4d..a0d49ff 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -953,8 +953,8 @@
                                           int renderTargetSampleCnt,
                                           SkBudgeted budgeted,
                                           GrProtected isProtected,
-                                          int mipLevelCount,
-                                          uint32_t levelClearMask) {
+                                          const GrMipLevel texels[],
+                                          int mipLevelCount) {
     VkFormat pixelFormat;
     SkAssertResult(format.asVkFormat(&pixelFormat));
     SkASSERT(!GrVkFormatIsCompressed(pixelFormat));
@@ -975,20 +975,28 @@
     // This ImageDesc refers to the texture that will be read by the client. Thus even if msaa is
     // requested, this ImageDesc describes the resolved texture. Therefore we always have samples set
     // to 1.
-    SkASSERT(mipLevelCount > 0);
+    int mipLevels = !mipLevelCount ? 1 : mipLevelCount;
     GrVkImage::ImageDesc imageDesc;
     imageDesc.fImageType = VK_IMAGE_TYPE_2D;
     imageDesc.fFormat = pixelFormat;
     imageDesc.fWidth = desc.fWidth;
     imageDesc.fHeight = desc.fHeight;
-    imageDesc.fLevels = mipLevelCount;
+    imageDesc.fLevels = mipLevels;
     imageDesc.fSamples = 1;
     imageDesc.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
     imageDesc.fUsageFlags = usageFlags;
     imageDesc.fIsProtected = isProtected;
 
-    GrMipMapsStatus mipMapsStatus =
-            mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
+    GrMipMapsStatus mipMapsStatus = GrMipMapsStatus::kNotAllocated;
+    if (mipLevels > 1) {
+        mipMapsStatus = GrMipMapsStatus::kValid;
+        for (int i = 0; i < mipLevels; ++i) {
+            if (!texels[i].fPixels) {
+                mipMapsStatus = GrMipMapsStatus::kDirty;
+                break;
+            }
+        }
+    }
 
     sk_sp<GrVkTexture> tex;
     if (renderable == GrRenderable::kYes) {
@@ -1002,11 +1010,20 @@
         return nullptr;
     }
 
-    if (levelClearMask) {
+    auto colorType = GrPixelConfigToColorType(desc.fConfig);
+    if (mipLevelCount) {
+        if (!this->uploadTexDataOptimal(tex.get(), 0, 0, desc.fWidth, desc.fHeight, colorType,
+                                        texels, mipLevelCount)) {
+            tex->unref();
+            return nullptr;
+        }
+    }
+
+    if (this->caps()->shouldInitializeTextures()) {
         SkSTArray<1, VkImageSubresourceRange> ranges;
         bool inRange = false;
         for (uint32_t i = 0; i < tex->mipLevels(); ++i) {
-            if (levelClearMask & (1U << i)) {
+            if (i >= static_cast<uint32_t>(mipLevelCount) || !texels[i].fPixels) {
                 if (inRange) {
                     ranges.back().levelCount++;
                 } else {
@@ -1022,12 +1039,15 @@
                 inRange = false;
             }
         }
-        SkASSERT(!ranges.empty());
-        static constexpr VkClearColorValue kZeroClearColor = {};
-        tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
-                            VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, false);
-        this->currentCommandBuffer()->clearColorImage(this, tex.get(), &kZeroClearColor,
-                                                      ranges.count(), ranges.begin());
+
+        if (!ranges.empty()) {
+            static constexpr VkClearColorValue kZeroClearColor = {};
+            tex->setImageLayout(this, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
+                                false);
+            this->currentCommandBuffer()->clearColorImage(this, tex.get(), &kZeroClearColor,
+                                                          ranges.count(), ranges.begin());
+        }
     }
     return tex;
 }
diff --git a/src/gpu/vk/GrVkGpu.h b/src/gpu/vk/GrVkGpu.h
index 4863445..f7af80f 100644
--- a/src/gpu/vk/GrVkGpu.h
+++ b/src/gpu/vk/GrVkGpu.h
@@ -196,8 +196,8 @@
                                      int renderTargetSampleCnt,
                                      SkBudgeted,
                                      GrProtected,
-                                     int mipLevelCount,
-                                     uint32_t levelClearMask) override;
+                                     const GrMipLevel[],
+                                     int mipLevelCount) override;
     sk_sp<GrTexture> onCreateCompressedTexture(int width, int height, const GrBackendFormat&,
                                                SkImage::CompressionType, SkBudgeted,
                                                const void* data) override;
diff --git a/tools/gpu/gl/angle/GLTestContext_angle.cpp b/tools/gpu/gl/angle/GLTestContext_angle.cpp
index c7c9149..59430ca 100644
--- a/tools/gpu/gl/angle/GLTestContext_angle.cpp
+++ b/tools/gpu/gl/angle/GLTestContext_angle.cpp
@@ -499,7 +499,7 @@
 }
 
 std::unique_ptr<GLTestContext> MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version,
-                                                    GLTestContext* shareContext, void* display) {
+                                                    GLTestContext* shareContext, void* display){
 #if defined(SK_BUILD_FOR_WIN) && defined(_M_ARM64)
     // Windows-on-ARM only has D3D11. This will fail correctly, but it produces huge amounts of
     // debug output for every unit test from both ANGLE and our context factory.