Change intermediate image sizes in GrSurfaceContext::rescale

Change-Id: Ia4a044b458a3cda6beb5edca76f30d7289262385
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/291362
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 3549e1a..3e8aa6b 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -504,7 +504,7 @@
 std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(
         const GrImageInfo& info,
         GrSurfaceOrigin origin,
-        const SkIRect& srcRect,
+        SkIRect srcRect,
         SkSurface::RescaleGamma rescaleGamma,
         SkFilterQuality rescaleQuality) {
     auto rtProxy = this->asRenderTargetProxy();
@@ -521,10 +521,6 @@
         return nullptr;
     }
 
-    int srcW = srcRect.width();
-    int srcH = srcRect.height();
-    int srcX = srcRect.fLeft;
-    int srcY = srcRect.fTop;
     GrSurfaceProxyView texView = this->readSurfaceView();
     SkAlphaType srcAlphaType = this->colorInfo().alphaType();
     if (!texView.asTextureProxy()) {
@@ -534,25 +530,9 @@
             return nullptr;
         }
         SkASSERT(texView.asTextureProxy());
-        srcX = 0;
-        srcY = 0;
+        srcRect = SkIRect::MakeSize(srcRect.size());
     }
 
-    float sx = (float)info.width() / srcW;
-    float sy = (float)info.height() / srcH;
-
-    // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
-    int stepsX;
-    int stepsY;
-    if (rescaleQuality > kNone_SkFilterQuality) {
-        stepsX = static_cast<int>((sx > 1.f) ? ceil(log2f(sx)) : floor(log2f(sx)));
-        stepsY = static_cast<int>((sy > 1.f) ? ceil(log2f(sy)) : floor(log2f(sy)));
-    } else {
-        stepsX = sx != 1.f;
-        stepsY = sy != 1.f;
-    }
-    SkASSERT(stepsX || stepsY);
-
     // Within a rescaling pass A is the input (if not null) and B is the output. At the end of the
     // pass B is moved to A. If 'this' is the input on the first pass then tempA is null.
     std::unique_ptr<GrRenderTargetContext> tempA;
@@ -567,7 +547,7 @@
                                              kPremul_SkAlphaType);
         // We'll fall back to kRGBA_8888 if half float not supported.
         auto linearRTC = GrRenderTargetContext::MakeWithFallback(
-                fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kApprox, {srcW, srcH}, 1,
+                fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kApprox, srcRect.size(), 1,
                 GrMipMapped::kNo, GrProtected::kNo, origin);
         if (!linearRTC) {
             return nullptr;
@@ -575,42 +555,35 @@
         // 1-to-1 draw can always be kFast.
         linearRTC->drawTexture(GrNoClip(), std::move(texView), srcAlphaType,
                                GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
-                               SK_PMColor4fWHITE, SkRect::Make(srcRect), SkRect::MakeWH(srcW, srcH),
-                               GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
-                               SkMatrix::I(), std::move(xform));
+                               SK_PMColor4fWHITE, SkRect::Make(srcRect),
+                               SkRect::Make(srcRect.size()), GrAA::kNo, GrQuadAAFlags::kNone,
+                               SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), std::move(xform));
         texView = linearRTC->readSurfaceView();
         SkASSERT(texView.asTextureProxy());
         tempA = std::move(linearRTC);
-        srcX = 0;
-        srcY = 0;
+        srcRect = SkIRect::MakeSize(srcRect.size());
     }
-    while (stepsX || stepsY) {
-        int nextW = info.width();
-        int nextH = info.height();
-        if (stepsX < 0) {
-            nextW = info.width() << (-stepsX - 1);
-            stepsX++;
-        } else if (stepsX != 0) {
-            if (stepsX > 1) {
-                nextW = srcW * 2;
+
+    while (srcRect.size() != info.dimensions()) {
+        SkISize nextDims = info.dimensions();
+        if (rescaleQuality != kNone_SkFilterQuality) {
+            if (srcRect.width() > info.width()) {
+                nextDims.fWidth = std::max((srcRect.width() + 1)/2, info.width());
+            } else if (srcRect.width() < info.width()) {
+                nextDims.fWidth = std::min(srcRect.width()*2, info.width());
             }
-            --stepsX;
-        }
-        if (stepsY < 0) {
-            nextH = info.height() << (-stepsY - 1);
-            stepsY++;
-        } else if (stepsY != 0) {
-            if (stepsY > 1) {
-                nextH = srcH * 2;
+            if (srcRect.height() > info.height()) {
+                nextDims.fHeight = std::max((srcRect.height() + 1)/2, info.height());
+            } else if (srcRect.height() < info.height()) {
+                nextDims.fHeight = std::min(srcRect.height()*2, info.height());
             }
-            --stepsY;
         }
         auto input = tempA ? tempA.get() : this;
         GrColorType colorType = input->colorInfo().colorType();
         auto cs = input->colorInfo().refColorSpace();
         sk_sp<GrColorSpaceXform> xform;
         auto prevAlphaType = input->colorInfo().alphaType();
-        if (!stepsX && !stepsY) {
+        if (nextDims == info.dimensions()) {
             // Might as well fold conversion to final info in the last step.
             cs = info.refColorSpace();
             xform = GrColorSpaceXform::Make(input->colorInfo().colorSpace(),
@@ -618,26 +591,28 @@
                                             info.alphaType());
         }
         tempB = GrRenderTargetContext::MakeWithFallback(fContext, colorType, std::move(cs),
-                                                        SkBackingFit::kApprox, {nextW, nextH}, 1,
+                                                        SkBackingFit::kApprox, nextDims, 1,
                                                         GrMipMapped::kNo, GrProtected::kNo, origin);
         if (!tempB) {
             return nullptr;
         }
-        auto dstRect = SkRect::MakeWH(nextW, nextH);
+        auto dstRect = SkRect::Make(nextDims);
         if (rescaleQuality == kHigh_SkFilterQuality) {
             SkMatrix matrix;
-            matrix.setScaleTranslate((float)srcW / nextW, (float)srcH / nextH, srcX, srcY);
+            matrix.setScaleTranslate((float)srcRect.width()/nextDims.width(),
+                                     (float)srcRect.height()/nextDims.height(),
+                                     srcRect.x(),
+                                     srcRect.y());
             std::unique_ptr<GrFragmentProcessor> fp;
             auto dir = GrBicubicEffect::Direction::kXY;
-            if (nextW == srcW) {
+            if (nextDims.width() == srcRect.width()) {
                 dir = GrBicubicEffect::Direction::kY;
-            } else if (nextH == srcH) {
+            } else if (nextDims.height() == srcRect.height()) {
                 dir = GrBicubicEffect::Direction::kX;
             }
             static constexpr GrSamplerState::WrapMode kWM = GrSamplerState::WrapMode::kClamp;
-            auto subset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH);
             fp = GrBicubicEffect::MakeSubset(std::move(texView), prevAlphaType, matrix, kWM, kWM,
-                                             subset, dir, *this->caps());
+                                             SkRect::Make(srcRect), dir, *this->caps());
             if (xform) {
                 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
             }
@@ -645,25 +620,23 @@
             paint.addColorFragmentProcessor(std::move(fp));
             paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
             tempB->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect,
-                                    dstRect);
+                                  dstRect);
         } else {
             auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest
                                                                   : GrSamplerState::Filter::kBilerp;
-            auto srcSubset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH);
             // Minimizing draw with integer coord src and dev rects can always be kFast.
             auto constraint = SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint;
-            if (nextW <= srcW && nextH <= srcH) {
+            if (nextDims.width() <= srcRect.width() && nextDims.height() <= srcRect.height()) {
                 constraint = SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint;
             }
             tempB->drawTexture(GrNoClip(), std::move(texView), srcAlphaType, filter,
-                               SkBlendMode::kSrc, SK_PMColor4fWHITE, srcSubset, dstRect, GrAA::kNo,
-                               GrQuadAAFlags::kNone, constraint, SkMatrix::I(), std::move(xform));
+                               SkBlendMode::kSrc, SK_PMColor4fWHITE, SkRect::Make(srcRect), dstRect,
+                               GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(),
+                               std::move(xform));
         }
         texView = tempB->readSurfaceView();
         tempA = std::move(tempB);
-        srcX = srcY = 0;
-        srcW = nextW;
-        srcH = nextH;
+        srcRect = SkIRect::MakeSize(nextDims);
     }
     SkASSERT(tempA);
     return tempA;
diff --git a/src/gpu/GrSurfaceContext.h b/src/gpu/GrSurfaceContext.h
index 27b99e6..8e3394c 100644
--- a/src/gpu/GrSurfaceContext.h
+++ b/src/gpu/GrSurfaceContext.h
@@ -123,7 +123,7 @@
      */
     std::unique_ptr<GrRenderTargetContext> rescale(const GrImageInfo& info,
                                                    GrSurfaceOrigin,
-                                                   const SkIRect& srcRect,
+                                                   SkIRect srcRect,
                                                    SkSurface::RescaleGamma,
                                                    SkFilterQuality);