Check for scratch textures in GrResourceProvider.

Restores scratch pool checks that were accidentally removed here:
https://skia.googlesource.com/skia/+/a90382fcf6759d4e13c20cf542ab5440ffd4f02d

Also enables checking scratch pool for mip-mapped textures, which was not
previously done.

Consolidates level prep and write-pixels code.

Bug: chromium:1005237
Change-Id: I6f23ce15299290ca5b666f910dc5fc85541ec316
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/243038
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrResourceProvider.cpp b/src/gpu/GrResourceProvider.cpp
index 82a0d12..e2a149e 100644
--- a/src/gpu/GrResourceProvider.cpp
+++ b/src/gpu/GrResourceProvider.cpp
@@ -42,35 +42,6 @@
     fCaps = sk_ref_sp(fGpu->caps());
 }
 
-// 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, int w, int h, bool rowBytesSupport,
-                          GrColorType origColorType, GrColorType allowedColorType,
-                          GrMipLevel* outLevel, std::unique_ptr<char[]>* data) {
-    if (!inLevel.fPixels) {
-        outLevel->fPixels = nullptr;
-        outLevel->fRowBytes = 0;
-        return true;
-    }
-    size_t minRB = w * GrColorTypeBytesPerPixel(origColorType);
-    size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
-    if (actualRB < minRB) {
-        return false;
-    }
-    if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
-        outLevel->fRowBytes = actualRB;
-        outLevel->fPixels = inLevel.fPixels;
-        return true;
-    }
-    auto tempRB = w * GrColorTypeBytesPerPixel(allowedColorType);
-    data->reset(new char[tempRB * h]);
-    outLevel->fPixels = data->get();
-    outLevel->fRowBytes = minRB;
-    GrPixelInfo srcInfo(origColorType,    kUnpremul_SkAlphaType, nullptr, w, h);
-    GrPixelInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, w, h);
-    return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
-}
-
 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
                                                    const GrBackendFormat& format,
                                                    GrColorType colorType,
@@ -93,30 +64,30 @@
                                       renderTargetSampleCnt, mipMapped)) {
         return nullptr;
     }
-    auto allowedColorType =
-            this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
-    if (allowedColorType == GrColorType::kUnknown) {
-        return nullptr;
+    // Current rule is that you can provide no level data, just the base, or all the levels.
+    bool hasPixels = mipLevelCount && texels[0].fPixels;
+    auto scratch = this->getExactScratch(desc, format, renderable, renderTargetSampleCnt, budgeted,
+                                         mipMapped, isProtected);
+    if (scratch) {
+        if (!hasPixels) {
+            return scratch;
+        }
+        return this->writePixels(std::move(scratch), colorType, {desc.fWidth, desc.fHeight}, texels,
+                                 mipLevelCount);
     }
-    bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
     SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
     SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
-    if (mipLevelCount > 0 && texels) {
-        tmpTexels.reset(mipLevelCount);
-        tmpDatas.reset(mipLevelCount);
-        int w = desc.fWidth;
-        int h = desc.fHeight;
-        for (int i = 0; i < mipLevelCount; ++i) {
-            if (!prepare_level(texels[i], w, h, rowBytesSupport, colorType, allowedColorType,
-                               &tmpTexels[i], &tmpDatas[i])) {
-                return nullptr;
-            }
-            w = std::max(w / 2, 1);
-            h = std::max(h / 2, 1);
+    GrColorType tempColorType = GrColorType::kUnknown;
+    if (hasPixels) {
+        tempColorType = this->prepareLevels(format, colorType, {desc.fWidth, desc.fHeight}, texels,
+                                            mipLevelCount, &tmpTexels, &tmpDatas);
+        if (tempColorType == GrColorType::kUnknown) {
+            return nullptr;
         }
     }
     return fGpu->createTexture(desc, format, renderable, renderTargetSampleCnt, budgeted,
-                               isProtected, colorType, colorType, tmpTexels.get(), mipLevelCount);
+                               isProtected, colorType, tempColorType, tmpTexels.get(),
+                               mipLevelCount);
 }
 
 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
@@ -146,47 +117,26 @@
                                                    const GrMipLevel& mipLevel) {
     ASSERT_SINGLE_OWNER
 
-    if (this->isAbandoned()) {
-        return nullptr;
-    }
-
     if (!mipLevel.fPixels) {
         return nullptr;
     }
 
-    if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig, renderable,
-                                      renderTargetSampleCnt, GrMipMapped::kNo)) {
-        return nullptr;
-    }
-
-    GrContext* context = fGpu->getContext();
-    GrProxyProvider* proxyProvider = context->priv().proxyProvider();
-
-    sk_sp<GrTexture> tex;
     if (SkBackingFit::kApprox == fit) {
-        tex = this->createApproxTexture(desc, format, renderable, renderTargetSampleCnt,
-                                        isProtected);
+        if (this->isAbandoned()) {
+            return nullptr;
+        }
+        if (!fCaps->validateSurfaceParams({desc.fWidth, desc.fHeight}, format, desc.fConfig,
+                                          renderable, renderTargetSampleCnt, GrMipMapped::kNo)) {
+            return nullptr;
+        }
+
+        auto tex = this->createApproxTexture(desc, format, renderable, renderTargetSampleCnt,
+                                             isProtected);
         if (!tex) {
             return nullptr;
         }
-        sk_sp<GrTextureProxy> proxy = proxyProvider->createWrapped(
-                tex, colorType, kTopLeft_GrSurfaceOrigin, GrSurfaceProxy::UseAllocator::kYes);
-        if (!proxy) {
-            return nullptr;
-        }
-        // Here we don't really know the alpha type of the data we want to upload. All we really
-        // care about is that it is not converted. So we use the same alpha type for the data
-        // and the surface context.
-        static constexpr auto kAlphaType = kUnpremul_SkAlphaType;
-        auto sContext =
-                context->priv().makeWrappedSurfaceContext(std::move(proxy), colorType, kAlphaType);
-        if (!sContext) {
-            return nullptr;
-        }
-        GrPixelInfo srcInfo(colorType, kAlphaType, nullptr, desc.fWidth, desc.fHeight);
-        SkAssertResult(
-                sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, {0, 0}));
-        return tex;
+        return this->writePixels(std::move(tex), colorType, {desc.fWidth, desc.fHeight}, &mipLevel,
+                                 1);
     } else {
         return this->createTexture(desc, format, colorType, renderable, renderTargetSampleCnt,
                                    budgeted, isProtected, &mipLevel, 1);
@@ -548,3 +498,86 @@
                                                                       wrapType,
                                                                       ownership);
 }
+
+// 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,
+                          const SkISize& size,
+                          bool rowBytesSupport,
+                          GrColorType origColorType,
+                          GrColorType allowedColorType,
+                          GrMipLevel* outLevel,
+                          std::unique_ptr<char[]>* data) {
+    if (!inLevel.fPixels) {
+        outLevel->fPixels = nullptr;
+        outLevel->fRowBytes = 0;
+        return true;
+    }
+    size_t minRB = size.fWidth * GrColorTypeBytesPerPixel(origColorType);
+    size_t actualRB = inLevel.fRowBytes ? inLevel.fRowBytes : minRB;
+    if (actualRB < minRB) {
+        return false;
+    }
+    if (origColorType == allowedColorType && (actualRB == minRB || rowBytesSupport)) {
+        outLevel->fRowBytes = actualRB;
+        outLevel->fPixels = inLevel.fPixels;
+        return true;
+    }
+    auto tempRB = size.fWidth * GrColorTypeBytesPerPixel(allowedColorType);
+    data->reset(new char[tempRB * size.fHeight]);
+    outLevel->fPixels = data->get();
+    outLevel->fRowBytes = tempRB;
+    GrPixelInfo srcInfo(origColorType,    kUnpremul_SkAlphaType, nullptr, size);
+    GrPixelInfo dstInfo(allowedColorType, kUnpremul_SkAlphaType, nullptr, size);
+    return GrConvertPixels(dstInfo, data->get(), tempRB, srcInfo, inLevel.fPixels, actualRB);
+}
+
+GrColorType GrResourceProvider::prepareLevels(const GrBackendFormat& format,
+                                              GrColorType colorType,
+                                              const SkISize& baseSize,
+                                              const GrMipLevel texels[],
+                                              int mipLevelCount,
+                                              TempLevels* tempLevels,
+                                              TempLevelDatas* tempLevelDatas) const {
+    SkASSERT(mipLevelCount && texels && texels[0].fPixels);
+
+    auto allowedColorType =
+            this->caps()->supportedWritePixelsColorType(colorType, format, colorType).fColorType;
+    if (allowedColorType == GrColorType::kUnknown) {
+        return GrColorType::kUnknown;
+    }
+    bool rowBytesSupport = this->caps()->writePixelsRowBytesSupport();
+    tempLevels->reset(mipLevelCount);
+    tempLevelDatas->reset(mipLevelCount);
+    auto size = baseSize;
+    for (int i = 0; i < mipLevelCount; ++i) {
+        if (!prepare_level(texels[i], size, rowBytesSupport, colorType, allowedColorType,
+                           &(*tempLevels)[i], &(*tempLevelDatas)[i])) {
+            return GrColorType::kUnknown;
+        }
+        size = {std::max(size.fWidth / 2, 1), std::max(size.fHeight / 2, 1)};
+    }
+    return allowedColorType;
+}
+
+sk_sp<GrTexture> GrResourceProvider::writePixels(sk_sp<GrTexture> texture,
+                                                 GrColorType colorType,
+                                                 const SkISize& baseSize,
+                                                 const GrMipLevel texels[],
+                                                 int mipLevelCount) const {
+    SkASSERT(!this->isAbandoned());
+    SkASSERT(texture);
+    SkASSERT(colorType != GrColorType::kUnknown);
+    SkASSERT(mipLevelCount && texels && texels[0].fPixels);
+
+    SkAutoSTMalloc<14, GrMipLevel> tmpTexels;
+    SkAutoSTArray<14, std::unique_ptr<char[]>> tmpDatas;
+    auto tempColorType = this->prepareLevels(texture->backendFormat(), colorType, baseSize, texels,
+                                             mipLevelCount, &tmpTexels, &tmpDatas);
+    if (tempColorType == GrColorType::kUnknown) {
+        return nullptr;
+    }
+    SkAssertResult(fGpu->writePixels(texture.get(), 0, 0, baseSize.fWidth, baseSize.fHeight,
+                                     colorType, tempColorType, tmpTexels.get(), mipLevelCount));
+    return texture;
+}