Implement support for framebufferOnly render targets.

This reflects Dawn and Metal functionality.
Implement a FramebufferOnly flag on GrSurface and GrBackendRenderTarget.
Forward the state from GrBackendRenderTarget to GrSurface.
Check the GrSurface flag in GrGpu::readPixels() and GrGpu::writePixels()
and early-return.

Change-Id: I27d3c9c912b366791bfd0e1db49638d8925742f3
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/262802
Reviewed-by: Greg Daniel <egdaniel@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Stephen White <senorblanco@chromium.org>
diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h
index 1254f88..8531340 100644
--- a/include/gpu/GrBackendSurface.h
+++ b/include/gpu/GrBackendSurface.h
@@ -49,6 +49,7 @@
     GrBackendRenderTarget() {}
 
     bool isValid() const { return false; }
+    bool isFramebufferOnly() const { return false; }
 };
 #else
 
@@ -371,6 +372,7 @@
     int sampleCnt() const { return fSampleCnt; }
     int stencilBits() const { return fStencilBits; }
     GrBackendApi backend() const {return fBackend; }
+    bool isFramebufferOnly() const { return fFramebufferOnly; }
 
     // If the backend API is GL, copies a snapshot of the GrGLFramebufferInfo struct into the passed
     // in pointer and returns true. Otherwise returns false if the backend API is not GL.
@@ -427,6 +429,7 @@
     void cleanup();
 
     bool fIsValid;
+    bool fFramebufferOnly = false;
     int fWidth;         //<! width in pixels
     int fHeight;        //<! height in pixels
 
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index cd0d456..791ca36 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -81,9 +81,18 @@
      */
     bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
 
+    bool framebufferOnly() const {
+        return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly;
+    }
+
     // Returns true if we are working with protected content.
     bool isProtected() const { return fIsProtected == GrProtected::kYes; }
 
+    void setFramebufferOnly() {
+        SkASSERT(this->asRenderTarget());
+        fSurfaceFlags |= GrInternalSurfaceFlags::kFramebufferOnly;
+    }
+
 protected:
     void setGLRTFBOIDIs0() {
         SkASSERT(!this->requiresManualMSAAResolve());
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index 73733e1..0e91874 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -701,6 +701,10 @@
     // (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,
+
+    // This means the pixels in the render target are write-only. This is used for Dawn and Metal
+    // swap chain targets which can be rendered to, but not read or copied.
+    kFramebufferOnly                = 1 << 3,
 };
 
 GR_MAKE_BITFIELD_CLASS_OPS(GrInternalSurfaceFlags)
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 3986afd..f45b457 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -665,6 +665,7 @@
                                              int stencilBits,
                                              const GrDawnImageInfo& dawnInfo)
         : fIsValid(true)
+        , fFramebufferOnly(true)
         , fWidth(width)
         , fHeight(height)
         , fSampleCnt(sampleCnt)
@@ -715,6 +716,7 @@
                                              int sampleCnt,
                                              const GrMtlTextureInfo& mtlInfo)
         : fIsValid(true)
+        , fFramebufferOnly(false) // TODO: set this from mtlInfo.fTexture->framebufferOnly
         , fWidth(width)
         , fHeight(height)
         , fSampleCnt(SkTMax(1, sampleCnt))
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index 0356651..3c0e808 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -380,7 +380,11 @@
         return nullptr;
     }
 
-    return this->onWrapBackendRenderTarget(backendRT, colorType);
+    sk_sp<GrRenderTarget> rt = this->onWrapBackendRenderTarget(backendRT, colorType);
+    if (backendRT.isFramebufferOnly()) {
+        rt->setFramebufferOnly();
+    }
+    return rt;
 }
 
 sk_sp<GrRenderTarget> GrGpu::wrapBackendTextureAsRenderTarget(const GrBackendTexture& backendTex,
@@ -432,6 +436,7 @@
                         const SkIPoint& dstPoint) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(dst && src);
+    SkASSERT(!src->framebufferOnly());
 
     if (dst->readOnly()) {
         return false;
@@ -447,6 +452,7 @@
                        size_t rowBytes) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
+    SkASSERT(!surface->framebufferOnly());
     SkASSERT(this->caps()->isFormatTexturable(surface->backendFormat()));
 
     auto subRect = SkIRect::MakeXYWH(left, top, width, height);
@@ -480,6 +486,7 @@
                         const GrMipLevel texels[], int mipLevelCount, bool prepForTexSampling) {
     TRACE_EVENT0("skia.gpu", TRACE_FUNC);
     SkASSERT(surface);
+    SkASSERT(!surface->framebufferOnly());
     SkASSERT(this->caps()->isFormatTexturableAndUploadable(surfaceColorType,
                                                            surface->backendFormat()));
 
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 69d10da..bab4d1db 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -1688,6 +1688,10 @@
         callback(context, nullptr);
         return;
     }
+    if (this->asRenderTargetProxy()->framebufferOnly()) {
+        callback(context, nullptr);
+        return;
+    }
     auto dstCT = SkColorTypeToGrColorType(info.colorType());
     if (dstCT == GrColorType::kUnknown) {
         callback(context, nullptr);
@@ -1933,6 +1937,10 @@
         callback(context, nullptr);
         return;
     }
+    if (this->asRenderTargetProxy()->framebufferOnly()) {
+        callback(context, nullptr);
+        return;
+    }
     if (this->asSurfaceProxy()->isProtected() == GrProtected::kYes) {
         callback(context, nullptr);
         return;
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index f41d168..dc4860b 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -157,6 +157,10 @@
 
     GrSurfaceProxy* srcProxy = this->asSurfaceProxy();
 
+    if (srcProxy->framebufferOnly()) {
+        return false;
+    }
+
     // MDB TODO: delay this instantiation until later in the method
     if (!srcProxy->instantiate(direct->priv().resourceProvider())) {
         return false;
@@ -315,6 +319,11 @@
     }
 
     GrSurfaceProxy* dstProxy = this->asSurfaceProxy();
+
+    if (dstProxy->framebufferOnly()) {
+        return false;
+    }
+
     if (!dstProxy->instantiate(direct->priv().resourceProvider())) {
         return false;
     }
@@ -484,6 +493,10 @@
     SkASSERT(src->textureSwizzle() == this->asSurfaceProxy()->textureSwizzle());
     SkASSERT(src->backendFormat() == this->asSurfaceProxy()->backendFormat());
 
+    if (this->asSurfaceProxy()->framebufferOnly()) {
+        return false;
+    }
+
     if (!caps->canCopySurface(this->asSurfaceProxy(), src, srcRect, dstPoint)) {
         return false;
     }
@@ -508,6 +521,10 @@
         return nullptr;
     }
 
+    if (this->asSurfaceProxy()->framebufferOnly()) {
+        return nullptr;
+    }
+
     // We rescale by drawing and don't currently support drawing to a kUnpremul destination.
     if (info.alphaType() == kUnpremul_SkAlphaType) {
         return nullptr;
diff --git a/src/gpu/GrSurfaceProxy.h b/src/gpu/GrSurfaceProxy.h
index 79ac4b4..f9f2197 100644
--- a/src/gpu/GrSurfaceProxy.h
+++ b/src/gpu/GrSurfaceProxy.h
@@ -245,6 +245,9 @@
      * assignment in GrResourceAllocator.
      */
     bool readOnly() const { return fSurfaceFlags & GrInternalSurfaceFlags::kReadOnly; }
+    bool framebufferOnly() const {
+        return fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly;
+    }
 
     /**
      * This means surface is a multisampled render target, and internally holds a non-msaa texture
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index a6b0e9e..6b5d3f0 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -32,7 +32,9 @@
         , fMipMapped(mipMapped)
         , fMipMapsStatus(mipMapsStatus) SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus))
         , fProxyProvider(nullptr)
-        , fDeferredUploader(nullptr) {}
+        , fDeferredUploader(nullptr) {
+    SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly));
+}
 
 // Lazy-callback version
 GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback,
@@ -52,7 +54,9 @@
         , fMipMapped(mipMapped)
         , fMipMapsStatus(mipMapsStatus) SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus))
         , fProxyProvider(nullptr)
-        , fDeferredUploader(nullptr) {}
+        , fDeferredUploader(nullptr) {
+    SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly));
+}
 
 // Wrapped version
 GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf,