Add kRequiresManualMSAAResolve to GrInternalSurfaceFlags

We will use this flag to check whether a proxy needs manual msaa
resolve, and if so, install a render task to do just that when it is
dirty and about to be read from.

For the time being, we are leaving GrRenderTarget::getResovleType in
place. This will allow us to assert that requiresManualMSAAResolve
works as expected. Long term, we plan to delete the former in favor of
the latter.

Bug: skia:
Change-Id: I155fa2a6d876edd339232c7c8208015d5da2c8ee
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/234436
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index ab84d65..2b41fec 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -91,6 +91,8 @@
 
 protected:
     void setGLRTFBOIDIs0() {
+        SkASSERT(!this->requiresManualMSAAResolve());
+        SkASSERT(!this->asTexture());
         SkASSERT(this->asRenderTarget());
         fSurfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
     }
@@ -98,6 +100,15 @@
         return fSurfaceFlags & GrInternalSurfaceFlags::kGLRTFBOIDIs0;
     }
 
+    void setRequiresManualMSAAResolve() {
+        SkASSERT(!this->glRTFBOIDis0());
+        SkASSERT(this->asRenderTarget());
+        fSurfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+    }
+    bool requiresManualMSAAResolve() const {
+        return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+    }
+
     void setReadOnly() {
         SkASSERT(!this->asRenderTarget());
         fSurfaceFlags |= GrInternalSurfaceFlags::kReadOnly;
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 8485817..e41d5ac 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -724,23 +724,36 @@
 enum class GrInternalSurfaceFlags {
     kNone                           = 0,
 
-    // Surface-level
     // Texture-level
 
     // Means the pixels in the texture are read-only. Cannot also be a GrRenderTarget[Proxy].
     kReadOnly                       = 1 << 0,
 
-    kTextureMask                    = kReadOnly,
-
     // RT-level
 
     // This flag is for use with GL only. It tells us that the internal render target wraps FBO 0.
-    kGLRTFBOIDIs0                   = 1 << 2,
+    kGLRTFBOIDIs0                   = 1 << 1,
 
-   kRenderTargetMask               = kGLRTFBOIDIs0,
+    // This means the render target is multisampled, and internally holds a non-msaa texture for
+    // resolving into. The render target resolves itself by blitting into this internal texture.
+    // (asTexture() might or might not return the internal texture, but if it does, we always
+    // resolve the render target before accessing this texture's data.)
+    kRequiresManualMSAAResolve      = 1 << 2,
 };
+
 GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags)
 
+// 'GR_MAKE_BITFIELD_CLASS_OPS' defines the & operator on GrInternalSurfaceFlags to return bool.
+// We want to find the bitwise & with these masks, so we declare them as ints.
+constexpr static int kGrInternalTextureFlagsMask = static_cast<int>(
+        GrInternalSurfaceFlags::kReadOnly);
+
+constexpr static int kGrInternalRenderTargetFlagsMask = static_cast<int>(
+        GrInternalSurfaceFlags::kGLRTFBOIDIs0 | GrInternalSurfaceFlags::kRequiresManualMSAAResolve);
+
+constexpr static int kGrInternalTextureRenderTargetFlagsMask =
+        kGrInternalTextureFlagsMask | kGrInternalRenderTargetFlagsMask;
+
 #ifdef SK_DEBUG
 // Takes a pointer to a GrCaps, and will suppress prints if required
 #define GrCapsDebugf(caps, ...)  if (!(caps)->suppressPrints()) SkDebugf(__VA_ARGS__)
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 970c7a3..91c7e41 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -202,6 +202,11 @@
             }
         }
         SkASSERT(tex->backendFormat() == format);
+        SkASSERT(!tex || GrRenderable::kNo == renderable || tex->asRenderTarget());
+        if (renderTargetSampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
+            SkASSERT(GrRenderable::kYes == renderable);
+            tex->asRenderTarget()->setRequiresManualMSAAResolve();
+        }
     }
     return tex;
 }
@@ -285,6 +290,9 @@
     sk_sp<GrTexture> tex = this->onWrapRenderableBackendTexture(backendTex, sampleCnt, colorType,
                                                                 ownership, cacheable);
     SkASSERT(!tex || tex->asRenderTarget());
+    if (tex && sampleCnt > 1 && !caps->msaaResolvesAutomatically()) {
+        tex->asRenderTarget()->setRequiresManualMSAAResolve();
+    }
     return tex;
 }
 
@@ -317,7 +325,11 @@
         return nullptr;
     }
 
-    return this->onWrapBackendTextureAsRenderTarget(backendTex, sampleCnt, colorType);
+    auto rt = this->onWrapBackendTextureAsRenderTarget(backendTex, sampleCnt, colorType);
+    if (rt && sampleCnt > 1 && !this->caps()->msaaResolvesAutomatically()) {
+        rt->setRequiresManualMSAAResolve();
+    }
+    return rt;
 }
 
 sk_sp<GrRenderTarget> GrGpu::wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo& imageInfo,
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp
index 683d84c..734b227 100644
--- a/src/gpu/GrProxyProvider.cpp
+++ b/src/gpu/GrProxyProvider.cpp
@@ -845,9 +845,9 @@
 
     return sk_sp<GrTextureProxy>((renderable == GrRenderable::kYes)
             ? new GrTextureRenderTargetProxy(
-                    std::move(callback), lazyType, format, desc, renderTargetSampleCnt, origin,
-                    mipMapped, mipMapsStatus, texSwizzle, outSwizzle, fit, budgeted, isProtected,
-                    surfaceFlags)
+                    *this->caps(), std::move(callback), lazyType, format, desc,
+                    renderTargetSampleCnt, origin, mipMapped, mipMapsStatus, texSwizzle, outSwizzle,
+                    fit, budgeted, isProtected, surfaceFlags)
             : new GrTextureProxy(
                     std::move(callback), lazyType, format, desc, origin, mipMapped, mipMapsStatus,
                     texSwizzle, fit, budgeted, isProtected, surfaceFlags));
@@ -883,7 +883,7 @@
         // actual VkImage to texture from.
         SkASSERT(!wrapsVkSecondaryCB);
         return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy(
-                std::move(callback), lazyType, format, desc, sampleCnt, origin,
+                *this->caps(), std::move(callback), lazyType, format, desc, sampleCnt, origin,
                 textureInfo->fMipMapped, mipMapsStatus, texSwizzle, outSwizzle, fit, budgeted,
                 isProtected, surfaceFlags));
     }
@@ -919,7 +919,7 @@
 
     return sk_sp<GrTextureProxy>((GrRenderable::kYes == renderable)
             ? new GrTextureRenderTargetProxy(
-                    std::move(callback), LazyInstantiationType::kSingleUse, format, desc,
+                    caps, std::move(callback), LazyInstantiationType::kSingleUse, format, desc,
                     renderTargetSampleCnt, origin, GrMipMapped::kNo, GrMipMapsStatus::kNotAllocated,
                     texSwizzle, outSwizzle, SkBackingFit::kApprox, SkBudgeted::kYes, isProtected,
                     surfaceFlags)
diff --git a/src/gpu/GrRenderTarget.h b/src/gpu/GrRenderTarget.h
index 2c330da..7a6f44c 100644
--- a/src/gpu/GrRenderTarget.h
+++ b/src/gpu/GrRenderTarget.h
@@ -26,6 +26,9 @@
  */
 class GrRenderTarget : virtual public GrSurface {
 public:
+    // Make setRequiresManualMSAAResolve publicly accessible from GrRenderTarget.
+    using GrSurface::setRequiresManualMSAAResolve;
+
     virtual bool alwaysClearStencil() const { return false; }
 
     // GrSurface overrides
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index b827e8d..6d831fa 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -7,8 +7,10 @@
 
 #include "src/gpu/GrRenderTargetProxy.h"
 
+#include "include/gpu/GrContext.h"
 #include "src/core/SkMathPriv.h"
 #include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
 #include "src/gpu/GrGpuResourcePriv.h"
 #include "src/gpu/GrRenderTargetOpList.h"
 #include "src/gpu/GrRenderTargetPriv.h"
@@ -53,6 +55,15 @@
         , fSampleCnt(fTarget->asRenderTarget()->numSamples())
         , fWrapsVkSecondaryCB(wrapsVkSecondaryCB)
         , fOutputSwizzle(outputSwizzle) {
+    // The kRequiresManualMSAAResolve flag better not be set if we are not multisampled or if
+    // MSAA resolve should happen automatically.
+    //
+    // From the other side, we don't know enough about the wrapped surface to assert when
+    // kRequiresManualMSAAResolve *should* be set. e.g., The caller might be wrapping a backend
+    // texture as a render target at this point but we wouldn't know it.
+    SkASSERT(!(this->numSamples() <= 1 ||
+               fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) ||
+             !this->requiresManualMSAAResolve());
 }
 
 int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const {
@@ -125,7 +136,7 @@
 
     GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
     GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
-    SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
-             (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
+    SkASSERT(((int)proxyFlags & kGrInternalRenderTargetFlagsMask) ==
+             ((int)surfaceFlags & kGrInternalRenderTargetFlagsMask));
 }
 #endif
diff --git a/src/gpu/GrRenderTargetProxyPriv.h b/src/gpu/GrRenderTargetProxyPriv.h
index bf2e770..091e4f2 100644
--- a/src/gpu/GrRenderTargetProxyPriv.h
+++ b/src/gpu/GrRenderTargetProxyPriv.h
@@ -16,6 +16,9 @@
 class GrRenderTargetProxyPriv {
 public:
     void setGLRTFBOIDIs0() {
+        // FBO0 should never be wrapped as a texture render target.
+        SkASSERT(!fRenderTargetProxy->requiresManualMSAAResolve());
+        SkASSERT(!fRenderTargetProxy->asTextureProxy());
         fRenderTargetProxy->setGLRTFBOIDIs0();
     }
 
diff --git a/src/gpu/GrSurfaceProxy.h b/src/gpu/GrSurfaceProxy.h
index 7a15059..6447396 100644
--- a/src/gpu/GrSurfaceProxy.h
+++ b/src/gpu/GrSurfaceProxy.h
@@ -269,6 +269,16 @@
      */
     bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
 
+    /**
+     * This means surface is a multisampled render target, and internally holds a non-msaa texture
+     * for resolving into. The render target resolves itself by blitting into this internal texture.
+     * (asTexture() might or might not return the internal texture, but if it does, we always
+     * resolve the render target before accessing this texture's data.)
+     */
+    bool requiresManualMSAAResolve() const {
+        return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+    }
+
     void setLastRenderTask(GrRenderTask*);
     GrRenderTask* getLastRenderTask() { return fLastRenderTask; }
 
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 5c7d304..85c6f58 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -177,8 +177,8 @@
 
     GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
     GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
-    SkASSERT((proxyFlags & GrInternalSurfaceFlags::kTextureMask) ==
-             (surfaceFlags & GrInternalSurfaceFlags::kTextureMask));
+    SkASSERT(((int)proxyFlags & kGrInternalTextureFlagsMask) ==
+             ((int)surfaceFlags & kGrInternalTextureFlagsMask));
 }
 
 #endif
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index 8e91bff..fb54227 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -9,7 +9,9 @@
 
 #include "include/gpu/GrTexture.h"
 #include "src/gpu/GrCaps.h"
+#include "src/gpu/GrContextPriv.h"
 #include "src/gpu/GrRenderTarget.h"
+#include "src/gpu/GrRenderTargetProxyPriv.h"
 #include "src/gpu/GrSurfacePriv.h"
 #include "src/gpu/GrSurfaceProxyPriv.h"
 #include "src/gpu/GrTexturePriv.h"
@@ -37,10 +39,13 @@
         , GrRenderTargetProxy(caps, format, desc, sampleCnt, origin, texSwizzle, outSwizzle, fit,
                               budgeted, isProtected, surfaceFlags)
         , GrTextureProxy(format, desc, origin, mipMapped, mipMapsStatus, texSwizzle, fit, budgeted,
-                         isProtected, surfaceFlags) {}
+                         isProtected, surfaceFlags) {
+    this->initSurfaceFlags(caps);
+}
 
 // Lazy-callback version
-GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(LazyInstantiateCallback&& callback,
+GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps,
+                                                       LazyInstantiateCallback&& callback,
                                                        LazyInstantiationType lazyType,
                                                        const GrBackendFormat& format,
                                                        const GrSurfaceDesc& desc,
@@ -62,7 +67,9 @@
                               texSwizzle, outSwizzle, fit, budgeted, isProtected, surfaceFlags,
                               WrapsVkSecondaryCB::kNo)
         , GrTextureProxy(LazyInstantiateCallback(), lazyType, format, desc, origin, mipMapped,
-                         mipMapsStatus, texSwizzle, fit, budgeted, isProtected, surfaceFlags) {}
+                         mipMapsStatus, texSwizzle, fit, budgeted, isProtected, surfaceFlags) {
+    this->initSurfaceFlags(caps);
+}
 
 // Wrapped version
 // This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and
@@ -76,6 +83,25 @@
         , GrTextureProxy(surf, origin, texSwizzle) {
     SkASSERT(surf->asTexture());
     SkASSERT(surf->asRenderTarget());
+    SkASSERT(fSurfaceFlags == fTarget->surfacePriv().flags());
+    SkASSERT((this->numSamples() <= 1 ||
+              fTarget->getContext()->priv().caps()->msaaResolvesAutomatically()) !=
+             this->requiresManualMSAAResolve());
+}
+
+void GrTextureRenderTargetProxy::initSurfaceFlags(const GrCaps& caps) {
+    // FBO 0 should never be wrapped as a texture render target.
+    SkASSERT(!this->rtPriv().glRTFBOIDIs0());
+    if (this->numSamples() > 1 && !caps.msaaResolvesAutomatically())  {
+        // MSAA texture-render-targets always require manual resolve if we are not using a
+        // multisampled-render-to-texture extension.
+        //
+        // NOTE: This is the only instance where we need to set the manual resolve flag on a proxy.
+        // Any other proxies that require manual resolve (e.g., wrapBackendTextureAsRenderTarget())
+        // will be wrapped, and the wrapped version of the GrSurface constructor will automatically
+        // get the manual resolve flag when copying the target GrSurface's flags.
+        fSurfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve;
+    }
 }
 
 size_t GrTextureRenderTargetProxy::onUninstantiatedGpuMemorySize() const {
@@ -147,10 +173,8 @@
     SkASSERT(!(proxyFlags & GrInternalSurfaceFlags::kReadOnly));
     SkASSERT(!(surfaceFlags & GrInternalSurfaceFlags::kReadOnly));
 
-    SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
-             (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
-    SkASSERT((proxyFlags & GrInternalSurfaceFlags::kTextureMask) ==
-             (surfaceFlags & GrInternalSurfaceFlags::kTextureMask));
+    SkASSERT(((int)proxyFlags & kGrInternalTextureRenderTargetFlagsMask) ==
+             ((int)surfaceFlags & kGrInternalTextureRenderTargetFlagsMask));
 }
 #endif
 
diff --git a/src/gpu/GrTextureRenderTargetProxy.h b/src/gpu/GrTextureRenderTargetProxy.h
index a736793..a31e520 100644
--- a/src/gpu/GrTextureRenderTargetProxy.h
+++ b/src/gpu/GrTextureRenderTargetProxy.h
@@ -34,7 +34,7 @@
                                SkBackingFit, SkBudgeted, GrProtected, GrInternalSurfaceFlags);
 
     // Lazy-callback version
-    GrTextureRenderTargetProxy(LazyInstantiateCallback&&, LazyInstantiationType,
+    GrTextureRenderTargetProxy(const GrCaps&, LazyInstantiateCallback&&, LazyInstantiationType,
                                const GrBackendFormat&, const GrSurfaceDesc& desc, int sampleCnt,
                                GrSurfaceOrigin, GrMipMapped, GrMipMapsStatus,
                                const GrSwizzle& textureSwizzle, const GrSwizzle& outputSwizzle,
@@ -44,6 +44,8 @@
     GrTextureRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin, const GrSwizzle& textureSwizzle,
                                const GrSwizzle& outputSwizzle);
 
+    void initSurfaceFlags(const GrCaps&);
+
     bool instantiate(GrResourceProvider*) override;
     sk_sp<GrSurface> createSurface(GrResourceProvider*) const override;
 
diff --git a/src/gpu/gl/GrGLRenderTarget.h b/src/gpu/gl/GrGLRenderTarget.h
index 1dbaa1e..3f1d016 100644
--- a/src/gpu/gl/GrGLRenderTarget.h
+++ b/src/gpu/gl/GrGLRenderTarget.h
@@ -51,10 +51,13 @@
     // override of GrRenderTarget
     ResolveType getResolveType() const override {
         if (this->numSamples() <= 1 || fRTFBOID == fTexFBOID) {  // Also catches FBO 0.
+            SkASSERT(!this->requiresManualMSAAResolve());
             return kAutoResolves_ResolveType;
         } else if (kUnresolvableFBOID == fTexFBOID) {
+            SkASSERT(!this->requiresManualMSAAResolve());
             return kCantResolve_ResolveType;
         } else {
+            SkASSERT(this->requiresManualMSAAResolve());
             return kCanResolve_ResolveType;
         }
     }
diff --git a/src/gpu/mtl/GrMtlRenderTarget.h b/src/gpu/mtl/GrMtlRenderTarget.h
index e558fa0..abf4c44 100644
--- a/src/gpu/mtl/GrMtlRenderTarget.h
+++ b/src/gpu/mtl/GrMtlRenderTarget.h
@@ -28,8 +28,10 @@
     // override of GrRenderTarget
     ResolveType getResolveType() const override {
         if (this->numSamples() > 1) {
+            SkASSERT(this->requiresManualMSAAResolve());
             return kCanResolve_ResolveType;
         }
+        SkASSERT(!this->requiresManualMSAAResolve());
         return kAutoResolves_ResolveType;
     }
 
diff --git a/src/gpu/vk/GrVkRenderTarget.h b/src/gpu/vk/GrVkRenderTarget.h
index 6341131..2572e65 100644
--- a/src/gpu/vk/GrVkRenderTarget.h
+++ b/src/gpu/vk/GrVkRenderTarget.h
@@ -76,8 +76,10 @@
     // override of GrRenderTarget
     ResolveType getResolveType() const override {
         if (this->numSamples() > 1) {
+            SkASSERT(this->requiresManualMSAAResolve());
             return kCanResolve_ResolveType;
         }
+        SkASSERT(!this->requiresManualMSAAResolve());
         return kAutoResolves_ResolveType;
     }