Make copySurface work in more situations.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1693923002

Review URL: https://codereview.chromium.org/1693923002
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index c2ace6c..79bb22e 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -54,6 +54,8 @@
     fRGBA8888PixelsOpsAreSlow = false;
     fPartialFBOReadIsSlow = false;
 
+    fBlitFramebufferSupport = kNone_BlitFramebufferSupport;
+
     fShaderCaps.reset(new GrGLSLCaps(contextOptions));
 
     this->init(contextOptions, ctxInfo, glInterface);
@@ -766,15 +768,28 @@
         } else if (ctxInfo.hasExtension("GL_APPLE_framebuffer_multisample")) {
             fMSFBOType = kES_Apple_MSFBOType;
         }
+
+        // Above determined the preferred MSAA approach, now decide whether glBlitFramebuffer
+        // is available.
+        if (ctxInfo.version() >= GR_GL_VER(3, 0)) {
+            fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
+        } else if (ctxInfo.hasExtension("GL_CHROMIUM_framebuffer_multisample")) {
+            // The CHROMIUM extension uses the ANGLE version of glBlitFramebuffer and includes its
+            // limitations.
+            fBlitFramebufferSupport = kNoScalingNoMirroring_BlitFramebufferSupport;
+        }
     } else {
         if (fUsesMixedSamples) {
             fMSFBOType = kMixedSamples_MSFBOType;
+            fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
         } else if ((ctxInfo.version() >= GR_GL_VER(3,0)) ||
             ctxInfo.hasExtension("GL_ARB_framebuffer_object")) {
             fMSFBOType = GrGLCaps::kDesktop_ARB_MSFBOType;
+            fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
         } else if (ctxInfo.hasExtension("GL_EXT_framebuffer_multisample") &&
                    ctxInfo.hasExtension("GL_EXT_framebuffer_blit")) {
             fMSFBOType = GrGLCaps::kDesktop_EXT_MSFBOType;
+            fBlitFramebufferSupport = kFull_BlitFramebufferSupport;
         }
     }
 }
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index abfcc28..fc29615 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -77,10 +77,20 @@
         kLast_MSFBOType = kMixedSamples_MSFBOType
     };
 
+    enum BlitFramebufferSupport {
+        kNone_BlitFramebufferSupport,
+        /**
+         * ANGLE exposes a limited blit framebuffer extension that does not allow for stretching
+         * or mirroring.
+         */
+        kNoScalingNoMirroring_BlitFramebufferSupport,
+        kFull_BlitFramebufferSupport
+    };
+
     enum InvalidateFBType {
         kNone_InvalidateFBType,
         kDiscard_InvalidateFBType,       //<! glDiscardFramebuffer()
-        kInvalidate_InvalidateFBType,     //<! glInvalidateFramebuffer()
+        kInvalidate_InvalidateFBType,    //<! glInvalidateFramebuffer()
 
         kLast_InvalidateFBType = kInvalidate_InvalidateFBType
     };
@@ -202,7 +212,7 @@
     MSFBOType msFBOType() const { return fMSFBOType; }
 
     /**
-     * Does the supported MSAA FBO extension have MSAA renderbuffers?
+     * Does the preferred MSAA FBO extension have MSAA renderbuffers?
      */
     bool usesMSAARenderBuffers() const {
         return kNone_MSFBOType != fMSFBOType &&
@@ -212,6 +222,11 @@
     }
 
     /**
+     * What functionality is supported by glBlitFramebuffer.
+     */
+    BlitFramebufferSupport blitFramebufferSupport() const { return fBlitFramebufferSupport; }
+
+    /**
      * Is the MSAA FBO extension one where the texture is multisampled when bound to an FBO and
      * then implicitly resolved when read.
      */
@@ -403,6 +418,8 @@
     bool fRectangleTextureSupport : 1;
     bool fTextureSwizzleSupport : 1;
 
+    BlitFramebufferSupport fBlitFramebufferSupport;
+
     /** Number type of the components (with out considering number of bits.) */
     enum FormatType {
         kNormalizedFixedPoint_FormatType,
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index e29a7f8..b9a5ee9 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2438,7 +2438,7 @@
     }
 }
 
-void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bound) {
+void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds) {
     SkASSERT(target);
 
     uint32_t rtID = target->getUniqueID();
@@ -2459,11 +2459,7 @@
         }
 #endif
         fHWBoundRenderTargetUniqueID = rtID;
-        const GrGLIRect& vp = target->getViewport();
-        if (fHWViewport != vp) {
-            vp.pushToGLViewport(this->glInterface());
-            fHWViewport = vp;
-        }
+        this->flushViewport(target->getViewport());
         if (this->glCaps().srgbWriteControl()) {
             bool enableSRGBWrite = GrPixelConfigIsSRGB(target->config());
             if (enableSRGBWrite && kYes_TriState != fHWSRGBFramebuffer) {
@@ -2475,11 +2471,24 @@
             }
         }
     }
+    this->didWriteToSurface(target, bounds);
+}
 
+void GrGLGpu::flushViewport(const GrGLIRect& viewport) {
+    if (fHWViewport != viewport) {
+        viewport.pushToGLViewport(this->glInterface());
+        fHWViewport = viewport;
+    }
+}
+
+void GrGLGpu::didWriteToSurface(GrSurface* surface, const SkIRect* bounds) const {
+    SkASSERT(surface);
     // Mark any MIP chain and resolve buffer as dirty if and only if there is a non-empty bounds.
-    if (nullptr == bound || !bound->isEmpty()) {
-        target->flagAsNeedingResolve(bound);
-        if (GrTexture *texture = target->asTexture()) {
+    if (nullptr == bounds || !bounds->isEmpty()) {
+        if (GrRenderTarget* target = surface->asRenderTarget()) {
+            target->flagAsNeedingResolve(bounds);
+        }
+        if (GrTexture* texture = surface->asTexture()) {
             texture->texturePriv().dirtyMipMaps(true);
         }
     }
@@ -2759,6 +2768,8 @@
 }
 
 void GrGLGpu::flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled) {
+    // rt is only optional if useHWAA is false.
+    SkASSERT(rt || !useHWAA);
     SkASSERT(!useHWAA || rt->isStencilBufferMultisampled());
 
     if (this->glCaps().multisampleDisableSupport()) {
@@ -3068,8 +3079,19 @@
                                         const GrSurface* src,
                                         const GrGLGpu* gpu) {
     if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) &&
-        gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
-        gpu->glCaps().usesMSAARenderBuffers()) {
+        gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0)) {
+        switch (gpu->glCaps().blitFramebufferSupport()) {
+            case GrGLCaps::kNone_BlitFramebufferSupport:
+                return false;
+            case GrGLCaps::kNoScalingNoMirroring_BlitFramebufferSupport:
+                // Our copy surface doesn't support scaling so just check for mirroring.
+                if (dst->origin() != src->origin()) {
+                    return false;
+                }
+                break;
+            case GrGLCaps::kFull_BlitFramebufferSupport:
+                break;
+        }
         // ES3 doesn't allow framebuffer blits when the src has MSAA and the configs don't match
         // or the rects are not the same (not just the same size but have the same edges).
         if (GrGLCaps::kES_3_0_MSFBOType == gpu->glCaps().msFBOType() &&
@@ -3140,7 +3162,7 @@
 void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
                                     TempFBOTarget tempFBOTarget) {
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
-    if (nullptr == rt) {
+    if (!rt) {
         SkASSERT(surface->asTexture());
         GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
         GrGLenum target = static_cast<GrGLTexture*>(surface->asTexture())->target();
@@ -3250,7 +3272,9 @@
         this->glCaps().glslCaps()->configOutputSwizzle(dst->config())) {
         return false;
     }
-    if (src->asTexture() && dst->asRenderTarget()) {
+    // Don't prefer copying as a draw if the dst doesn't already have a FBO object.
+    bool preferCopy = SkToBool(dst->asRenderTarget());
+    if (preferCopy && src->asTexture()) {
         this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
         return true;
     }
@@ -3264,6 +3288,11 @@
         return this->copySurfaceAsBlitFramebuffer(dst, src, srcRect, dstPoint);
     }
 
+    if (!preferCopy && src->asTexture()) {
+        this->copySurfaceAsDraw(dst, src, srcRect, dstPoint);
+        return true;
+    }
+
     return false;
 }
 
@@ -3560,9 +3589,12 @@
     GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
     this->bindTexture(0, params, srcTex);
 
-    GrGLRenderTarget* dstRT = static_cast<GrGLRenderTarget*>(dst->asRenderTarget());
+    GrGLIRect dstVP;
+    this->bindSurfaceFBOForCopy(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget);
+    this->flushViewport(dstVP);
+    fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
+
     SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
-    this->flushRenderTarget(dstRT, &dstRect);
 
     int progIdx = TextureTargetToCopyProgramIdx(srcTex->target());
 
@@ -3618,13 +3650,16 @@
     this->flushBlend(blendInfo, GrSwizzle::RGBA());
     this->flushColorWrite(true);
     this->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
-    this->flushHWAAState(dstRT, false, false);
+    this->flushHWAAState(nullptr, false, false);
     this->disableScissor();
     GrStencilSettings stencil;
     stencil.setDisabled();
     this->flushStencil(stencil);
 
     GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4));
+    this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, dst);
+    this->didWriteToSurface(dst, &dstRect);
+
 }
 
 void GrGLGpu::copySurfaceAsCopyTexSubImage(GrSurface* dst,
@@ -3634,7 +3669,7 @@
     SkASSERT(can_copy_texsubimage(dst, src, this));
     GrGLIRect srcVP;
     this->bindSurfaceFBOForCopy(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
-    GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
+    GrGLTexture* dstTex = static_cast<GrGLTexture *>(dst->asTexture());
     SkASSERT(dstTex);
     // We modified the bound FBO
     fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
@@ -3655,10 +3690,13 @@
         dstY = dstPoint.fY;
     }
     GL_CALL(CopyTexSubImage2D(dstTex->target(), 0,
-                                dstPoint.fX, dstY,
-                                srcGLRect.fLeft, srcGLRect.fBottom,
-                                srcGLRect.fWidth, srcGLRect.fHeight));
+                              dstPoint.fX, dstY,
+                              srcGLRect.fLeft, srcGLRect.fBottom,
+                              srcGLRect.fWidth, srcGLRect.fHeight));
     this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, src);
+    SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
+                                        srcRect.width(), srcRect.height());
+    this->didWriteToSurface(dst, &dstRect);
 }
 
 bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst,
@@ -3719,6 +3757,7 @@
                             GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
     this->unbindTextureFBOForCopy(GR_GL_DRAW_FRAMEBUFFER, dst);
     this->unbindTextureFBOForCopy(GR_GL_READ_FRAMEBUFFER, src);
+    this->didWriteToSurface(dst, &dstRect);
     return true;
 }
 
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index ce2f95e..48645ca 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -317,11 +317,18 @@
     // ensures that such operations don't negatively interact with tracking bound textures.
     void setScratchTextureUnit();
 
-    // bounds is region that may be modified and therefore has to be resolved.
+    // bounds is region that may be modified.
     // nullptr means whole target. Can be an empty rect.
     void flushRenderTarget(GrGLRenderTarget*, const SkIRect* bounds);
+    // Handles cases where a surface will be updated without a call to flushRenderTarget
+    void didWriteToSurface(GrSurface*, const SkIRect* bounds) const;
+
+    // Need not be called if flushRenderTarget is used.
+    void flushViewport(const GrGLIRect&);
 
     void flushStencil(const GrStencilSettings&);
+
+    // rt is used only if useHWAA is true.
     void flushHWAAState(GrRenderTarget* rt, bool useHWAA, bool stencilEnabled);
 
     // helper for onCreateTexture and writeTexturePixels