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/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));
     }