Revert "Revert "Update GrBitmapTextureMaker for handling mipped requests""

This reverts commit 8b059bd946d9f14607f6d2e8b966267dd8e5a54d.

Reason for revert: <INSERT REASONING HERE>

Original change's description:
> Revert "Update GrBitmapTextureMaker for handling mipped requests"
> 
> This reverts commit d1935c16e889b6707a522f711e79c75353caa343.
> 
> Reason for revert: breaking lots of GMs, especially on gles
> 
> Original change's description:
> > Update GrBitmapTextureMaker for handling mipped requests
> > 
> > Specifically this updates the case when we are requesting to use mip
> > maps but there is already an unmipped version in the cache. Previously
> > we just grabbed the unmipped.
> > 
> > Now we will create a new mipped resource. Upload the cpu data to all
> > the levels besides the base, copy the base level on GPU from the
> > original resource to the mipped one. Then the mipped resource will
> > take over the originals unique key.
> > 
> > Bug: skia:
> > Change-Id: I38e9725c93280dc2460a0be8a7a229e7f20e1614
> > Reviewed-on: https://skia-review.googlesource.com/43840
> > Commit-Queue: Greg Daniel <egdaniel@google.com>
> > Reviewed-by: Robert Phillips <robertphillips@google.com>
> 
> TBR=egdaniel@google.com,robertphillips@google.com,brianosman@google.com
> 
> Change-Id: Id82e8b6e8ab69e46ff018bb07ae5d1f6ea8d7e76
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/52901
> Reviewed-by: Greg Daniel <egdaniel@google.com>
> Commit-Queue: Greg Daniel <egdaniel@google.com>

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

Bug: skia:
Change-Id: Ie5b9553aa67def6f9c5a61f9b6b065b9fce3ff76
Reviewed-on: https://skia-review.googlesource.com/53240
Reviewed-by: Brian Osman <brianosman@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrBitmapTextureMaker.cpp b/src/gpu/GrBitmapTextureMaker.cpp
index 6654901..00dd48d 100644
--- a/src/gpu/GrBitmapTextureMaker.cpp
+++ b/src/gpu/GrBitmapTextureMaker.cpp
@@ -8,10 +8,13 @@
 #include "GrBitmapTextureMaker.h"
 
 #include "GrContext.h"
+#include "GrContextPriv.h"
 #include "GrGpuResourcePriv.h"
 #include "GrResourceProvider.h"
+#include "GrSurfaceContext.h"
 #include "SkBitmap.h"
 #include "SkGr.h"
+#include "SkMipMap.h"
 #include "SkPixelRef.h"
 
 static bool bmp_is_alpha_only(const SkBitmap& bm) { return kAlpha_8_SkColorType == bm.colorType(); }
@@ -34,17 +37,25 @@
         return nullptr;
     }
 
-    sk_sp<GrTextureProxy> proxy;
+    sk_sp<GrTextureProxy> originalProxy;
 
     if (fOriginalKey.isValid()) {
-        proxy = this->context()->resourceProvider()->findOrCreateProxyByUniqueKey(
-                                                          fOriginalKey, kTopLeft_GrSurfaceOrigin);
-        if (proxy) {
-            return proxy;
+        originalProxy = this->context()->resourceProvider()->findOrCreateProxyByUniqueKey(
+                                                            fOriginalKey, kTopLeft_GrSurfaceOrigin);
+        if (originalProxy && (!willBeMipped || originalProxy->isMipMapped())) {
+            return originalProxy;
         }
     }
+
+    sk_sp<GrTextureProxy> proxy;
     if (willBeMipped) {
-        proxy = GrGenerateMipMapsAndUploadToTextureProxy(this->context(), fBitmap, dstColorSpace);
+        if (!originalProxy) {
+            proxy = GrGenerateMipMapsAndUploadToTextureProxy(this->context(), fBitmap,
+                                                             dstColorSpace);
+        } else {
+            proxy = GrCopyBaseMipMapToTextureProxy(this->context(), originalProxy.get(),
+                                                   dstColorSpace);
+        }
     }
     if (!proxy) {
         proxy = GrUploadBitmapToTextureProxy(this->context()->resourceProvider(), fBitmap,
@@ -52,6 +63,15 @@
     }
     if (proxy && fOriginalKey.isValid()) {
         SkASSERT(proxy->origin() == kTopLeft_GrSurfaceOrigin);
+        if (originalProxy) {
+            // In this case we are stealing the key from the original proxy which should only happen
+            // when we have just generated mipmaps for an originally unmipped proxy/texture. This
+            // means that all future uses of the key will access the mipmapped version. The texture
+            // backing the unmipped version will remain in the resource cache until the last texture
+            // proxy referencing it is deleted at which time it too will be deleted or recycled.
+            this->context()->resourceProvider()->removeUniqueKeyFromProxy(fOriginalKey,
+                                                                          originalProxy.get());
+        }
         this->context()->resourceProvider()->assignUniqueKeyToProxy(fOriginalKey, proxy.get());
         GrInstallBitmapUniqueKeyInvalidator(fOriginalKey, fBitmap.pixelRef());
     }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index c83d982..31939bc 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -114,11 +114,6 @@
         }
     }
 
-    for (int i = 0; i < mipLevelCount; ++i) {
-        if (!texels[i].fPixels) {
-            return false;
-        }
-    }
     return true;
 }
 
diff --git a/src/gpu/GrSurfaceProxy.cpp b/src/gpu/GrSurfaceProxy.cpp
index d9711e2..2ef3846 100644
--- a/src/gpu/GrSurfaceProxy.cpp
+++ b/src/gpu/GrSurfaceProxy.cpp
@@ -303,21 +303,36 @@
             return nullptr;
         }
         return GrSurfaceProxy::MakeDeferred(resourceProvider, desc, budgeted, nullptr, 0);
-    } else if (1 == mipLevelCount) {
-        if (!texels) {
-            return nullptr;
-        }
+    }
+    if (!texels) {
+        return nullptr;
+    }
+
+    if (1 == mipLevelCount) {
         return resourceProvider->createTextureProxy(desc, budgeted, texels[0]);
     }
 
-    for (int i = 0; i < mipLevelCount; ++i) {
-        if (!texels[i].fPixels) {
-            return nullptr;
+#ifdef SK_DEBUG
+    // There are only three states we want to be in when uploading data to a mipped surface.
+    // 1) We have data to upload to all layers
+    // 2) We are not uploading data to any layers
+    // 3) We are only uploading data to the base layer
+    // We check here to make sure we do not have any other state.
+    bool firstLevelHasData = SkToBool(texels[0].fPixels);
+    bool allOtherLevelsHaveData = true, allOtherLevelsLackData = true;
+    for  (int i = 1; i < mipLevelCount; ++i) {
+        if (texels[i].fPixels) {
+            allOtherLevelsLackData = false;
+        } else {
+            allOtherLevelsHaveData = false;
         }
     }
+    SkASSERT((firstLevelHasData && allOtherLevelsHaveData) || allOtherLevelsLackData);
+#endif
 
     sk_sp<GrTexture> tex(resourceProvider->createTexture(desc, budgeted,
-                                                         texels, mipLevelCount, mipColorMode));
+                                                         texels, mipLevelCount,
+                                                         mipColorMode));
     if (!tex) {
         return nullptr;
     }
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 5c26877..e26de49 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -10,6 +10,7 @@
 #include "GrBitmapTextureMaker.h"
 #include "GrCaps.h"
 #include "GrContext.h"
+#include "GrContextPriv.h"
 #include "GrGpuResourcePriv.h"
 #include "GrRenderTargetContext.h"
 #include "GrResourceProvider.h"
@@ -217,6 +218,51 @@
                                               colorMode);
 }
 
+sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext* ctx,
+                                                     GrTextureProxy* baseProxy,
+                                                     SkColorSpace* dstColorSpace) {
+    SkASSERT(baseProxy);
+
+    SkDestinationSurfaceColorMode colorMode = dstColorSpace
+        ? SkDestinationSurfaceColorMode::kGammaAndColorSpaceAware
+        : SkDestinationSurfaceColorMode::kLegacy;
+
+    // SkMipMap doesn't include the base level in the level count so we have to add 1
+    int mipLevelCount = SkMipMap::ComputeLevelCount(baseProxy->width(), baseProxy->height()) + 1;
+
+    std::unique_ptr<GrMipLevel[]> texels(new GrMipLevel[mipLevelCount]);
+
+    // We don't want to upload any texel data
+    for (int i = 0; i < mipLevelCount; i++) {
+        texels[i].fPixels = nullptr;
+        texels[i].fRowBytes = 0;
+    }
+
+    GrSurfaceDesc desc;
+    desc.fFlags = kNone_GrSurfaceFlags;
+    desc.fOrigin = baseProxy->origin();
+    desc.fWidth = baseProxy->width();
+    desc.fHeight = baseProxy->height();
+    desc.fConfig = baseProxy->config();
+    desc.fSampleCnt = 0;
+
+    sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferredMipMap(ctx->resourceProvider(),
+                                                                     desc,
+                                                                     SkBudgeted::kYes, texels.get(),
+                                                                     mipLevelCount, colorMode);
+    if (!proxy) {
+        return nullptr;
+    }
+
+    // Copy the base layer to our proxy
+    sk_sp<GrSurfaceContext> sContext = ctx->contextPriv().makeWrappedSurfaceContext(proxy, nullptr);
+    SkASSERT(sContext);
+    SkAssertResult(sContext->copy(baseProxy));
+
+    return proxy;
+}
+
+
 sk_sp<GrTextureProxy> GrUploadMipMapToTextureProxy(GrContext* ctx, const SkImageInfo& info,
                                                    const GrMipLevel texels[],
                                                    int mipLevelCount,
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index 7ecec96..20110a5 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -225,6 +225,13 @@
                                                    const SkPixmap&, SkBudgeted, SkColorSpace*);
 
 /**
+ * Creates a new texture with mipmap levels and copies the baseProxy into the base layer.
+ */
+sk_sp<GrTextureProxy> GrCopyBaseMipMapToTextureProxy(GrContext*,
+                                                     GrTextureProxy* baseProxy,
+                                                     SkColorSpace* dstColorSpace);
+
+/**
  * Creates a new texture populated with the mipmap levels.
  */
 sk_sp<GrTextureProxy> GrUploadMipMapToTextureProxy(GrContext*, const SkImageInfo&,
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index ff19bb6..8190206 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -1033,10 +1033,6 @@
         memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
     }
 
-    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
-        SkASSERT(texelsShallowCopy[currentMipLevel].fPixels);
-    }
-
     const GrGLInterface* interface = this->glInterface();
     const GrGLCaps& caps = this->glCaps();
 
@@ -1081,19 +1077,27 @@
 
     // find the combined size of all the mip levels and the relative offset of
     // each into the collective buffer
-    size_t combined_buffer_size = 0;
-    SkTArray<size_t> individual_mip_offsets(mipLevelCount);
+    size_t combinedBufferSize = 0;
+    SkTArray<size_t> individualMipOffsets(mipLevelCount);
     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
-        int twoToTheMipLevel = 1 << currentMipLevel;
-        int currentWidth = SkTMax(1, width / twoToTheMipLevel);
-        int currentHeight = SkTMax(1, height / twoToTheMipLevel);
-        const size_t trimmedSize = currentWidth * bpp * currentHeight;
-        individual_mip_offsets.push_back(combined_buffer_size);
-        combined_buffer_size += trimmedSize;
+        if (texelsShallowCopy[currentMipLevel].fPixels) {
+            int twoToTheMipLevel = 1 << currentMipLevel;
+            int currentWidth = SkTMax(1, width / twoToTheMipLevel);
+            int currentHeight = SkTMax(1, height / twoToTheMipLevel);
+            const size_t trimmedSize = currentWidth * bpp * currentHeight;
+            individualMipOffsets.push_back(combinedBufferSize);
+            combinedBufferSize += trimmedSize;
+        } else {
+            individualMipOffsets.push_back(0);
+        }
+
     }
-    char* buffer = (char*)tempStorage.reset(combined_buffer_size);
+    char* buffer = (char*)tempStorage.reset(combinedBufferSize);
 
     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+        if (!texelsShallowCopy[currentMipLevel].fPixels) {
+            continue;
+        }
         int twoToTheMipLevel = 1 << currentMipLevel;
         int currentWidth = SkTMax(1, width / twoToTheMipLevel);
         int currentHeight = SkTMax(1, height / twoToTheMipLevel);
@@ -1107,9 +1111,9 @@
          */
         restoreGLRowLength = false;
 
-        const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes ?
-                                texelsShallowCopy[currentMipLevel].fRowBytes :
-                                trimRowBytes;
+        const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes
+                ? texelsShallowCopy[currentMipLevel].fRowBytes
+                : trimRowBytes;
 
         // TODO: This optimization should be enabled with or without mips.
         // For use with mips, we must set GR_GL_UNPACK_ROW_LENGTH once per
@@ -1128,7 +1132,7 @@
             if (swFlipY && currentHeight >= 1) {
                 src += (currentHeight - 1) * rowBytes;
             }
-            char* dst = buffer + individual_mip_offsets[currentMipLevel];
+            char* dst = buffer + individualMipOffsets[currentMipLevel];
             for (int y = 0; y < currentHeight; y++) {
                 memcpy(dst, src, trimRowBytes);
                 if (swFlipY) {
@@ -1140,7 +1144,7 @@
             }
             // now point data to our copied version
             texelsShallowCopy[currentMipLevel].fPixels = buffer +
-                individual_mip_offsets[currentMipLevel];
+                individualMipOffsets[currentMipLevel];
             texelsShallowCopy[currentMipLevel].fRowBytes = trimRowBytes;
         }
     }
@@ -1167,6 +1171,9 @@
             top = texHeight - (top + height);
         }
         for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
+            if (!texelsShallowCopy[currentMipLevel].fPixels) {
+                continue;
+            }
             int twoToTheMipLevel = 1 << currentMipLevel;
             int currentWidth = SkTMax(1, width / twoToTheMipLevel);
             int currentHeight = SkTMax(1, height / twoToTheMipLevel);
diff --git a/src/gpu/vk/GrVkGpu.cpp b/src/gpu/vk/GrVkGpu.cpp
index 6617318..e9adb4d 100644
--- a/src/gpu/vk/GrVkGpu.cpp
+++ b/src/gpu/vk/GrVkGpu.cpp
@@ -661,10 +661,6 @@
         memcpy(texelsShallowCopy.get(), texels, mipLevelCount*sizeof(GrMipLevel));
     }
 
-    for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; ++currentMipLevel) {
-        SkASSERT(texelsShallowCopy[currentMipLevel].fPixels);
-    }
-
     // Determine whether we need to flip when we copy into the buffer
     bool flipY = (kBottomLeft_GrSurfaceOrigin == texOrigin && mipLevelCount);
 
@@ -673,6 +669,10 @@
     size_t combinedBufferSize = width * bpp * height;
     int currentWidth = width;
     int currentHeight = height;
+    if (mipLevelCount > 0  && !texelsShallowCopy[0].fPixels) {
+        combinedBufferSize = 0;
+    }
+
     // The alignment must be at least 4 bytes and a multiple of the bytes per pixel of the image
     // config. This works with the assumption that the bytes in pixel config is always a power of 2.
     SkASSERT((bpp & (bpp - 1)) == 0);
@@ -681,13 +681,21 @@
         currentWidth = SkTMax(1, currentWidth/2);
         currentHeight = SkTMax(1, currentHeight/2);
 
-        const size_t trimmedSize = currentWidth * bpp * currentHeight;
-        const size_t alignmentDiff = combinedBufferSize & alignmentMask;
-        if (alignmentDiff != 0) {
-           combinedBufferSize += alignmentMask - alignmentDiff + 1;
+        if (texelsShallowCopy[currentMipLevel].fPixels) {
+            const size_t trimmedSize = currentWidth * bpp * currentHeight;
+            const size_t alignmentDiff = combinedBufferSize & alignmentMask;
+            if (alignmentDiff != 0) {
+                combinedBufferSize += alignmentMask - alignmentDiff + 1;
+            }
+            individualMipOffsets.push_back(combinedBufferSize);
+            combinedBufferSize += trimmedSize;
+        } else {
+            individualMipOffsets.push_back(0);
         }
-        individualMipOffsets.push_back(combinedBufferSize);
-        combinedBufferSize += trimmedSize;
+    }
+    if (0 == combinedBufferSize) {
+        // We don't actually have any data to upload so just return success
+        return true;
     }
 
     // allocate buffer to hold our mip data
@@ -704,35 +712,36 @@
     currentHeight = height;
     int layerHeight = tex->height();
     for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
-        SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
-        const size_t trimRowBytes = currentWidth * bpp;
-        const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes ?
-                                texelsShallowCopy[currentMipLevel].fRowBytes :
-                                trimRowBytes;
+        if (texelsShallowCopy[currentMipLevel].fPixels) {
+            SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
+            const size_t trimRowBytes = currentWidth * bpp;
+            const size_t rowBytes = texelsShallowCopy[currentMipLevel].fRowBytes
+                                    ? texelsShallowCopy[currentMipLevel].fRowBytes
+                                    : trimRowBytes;
 
-        // copy data into the buffer, skipping the trailing bytes
-        char* dst = buffer + individualMipOffsets[currentMipLevel];
-        const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels;
-        if (flipY) {
-            src += (currentHeight - 1) * rowBytes;
-            for (int y = 0; y < currentHeight; y++) {
-                memcpy(dst, src, trimRowBytes);
-                src -= rowBytes;
-                dst += trimRowBytes;
+            // copy data into the buffer, skipping the trailing bytes
+            char* dst = buffer + individualMipOffsets[currentMipLevel];
+            const char* src = (const char*)texelsShallowCopy[currentMipLevel].fPixels;
+            if (flipY) {
+                src += (currentHeight - 1) * rowBytes;
+                for (int y = 0; y < currentHeight; y++) {
+                    memcpy(dst, src, trimRowBytes);
+                    src -= rowBytes;
+                    dst += trimRowBytes;
+                }
+            } else {
+                SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
             }
-        } else {
-            SkRectMemcpy(dst, trimRowBytes, src, rowBytes, trimRowBytes, currentHeight);
+
+            VkBufferImageCopy& region = regions.push_back();
+            memset(&region, 0, sizeof(VkBufferImageCopy));
+            region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
+            region.bufferRowLength = currentWidth;
+            region.bufferImageHeight = currentHeight;
+            region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
+            region.imageOffset = { left, flipY ? layerHeight - top - currentHeight : top, 0 };
+            region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
         }
-
-        VkBufferImageCopy& region = regions.push_back();
-        memset(&region, 0, sizeof(VkBufferImageCopy));
-        region.bufferOffset = transferBuffer->offset() + individualMipOffsets[currentMipLevel];
-        region.bufferRowLength = currentWidth;
-        region.bufferImageHeight = currentHeight;
-        region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, SkToU32(currentMipLevel), 0, 1 };
-        region.imageOffset = { left, flipY ? layerHeight - top - currentHeight : top, 0 };
-        region.imageExtent = { (uint32_t)currentWidth, (uint32_t)currentHeight, 1 };
-
         currentWidth = SkTMax(1, currentWidth/2);
         currentHeight = SkTMax(1, currentHeight/2);
         layerHeight = currentHeight;
@@ -822,7 +831,6 @@
     }
 
     if (mipLevelCount) {
-        SkASSERT(texels[0].fPixels);
         if (!this->uploadTexDataOptimal(tex.get(), desc.fOrigin, 0, 0, desc.fWidth, desc.fHeight,
                                         desc.fConfig, texels, mipLevelCount)) {
             tex->unref();
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index d3a1865..356b800 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -922,6 +922,13 @@
     if (!ctx) {
         return nullptr;
     }
+    // For images where the client is passing the mip data we require that all the mip levels have
+    // valid data.
+    for (int i = 0; i < mipLevelCount; ++i) {
+        if (!texels[i].fPixels) {
+            return nullptr;
+        }
+    }
     sk_sp<GrTextureProxy> proxy(GrUploadMipMapToTextureProxy(ctx, info, texels, mipLevelCount,
                                                              colorMode));
     if (!proxy) {