Add InternalSurfaceFlag so we know if RenderTargetProxys and RenderTargets use GL FBO 0.

Bug: skia:7748
Change-Id: I2fda3cde12ccdef19fe06ff287a8024b58d28ef0
Reviewed-on: https://skia-review.googlesource.com/124048
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/core/SkDeferredDisplayListRecorder.cpp b/src/core/SkDeferredDisplayListRecorder.cpp
index 8a89068..d390228 100644
--- a/src/core/SkDeferredDisplayListRecorder.cpp
+++ b/src/core/SkDeferredDisplayListRecorder.cpp
@@ -80,6 +80,14 @@
 
     auto proxyProvider = fContext->contextPriv().proxyProvider();
 
+    bool usesGLFBO0 = fCharacterization.usesGLFBO0();
+    if (usesGLFBO0) {
+        if (kOpenGL_GrBackend != fContext->contextPriv().getBackend() ||
+            fCharacterization.isTextureable()) {
+            return false;
+        }
+    }
+
     GrSurfaceDesc desc;
     desc.fFlags = kRenderTarget_GrSurfaceFlag;
     desc.fWidth = fCharacterization.width();
@@ -94,12 +102,17 @@
     // DDL is being replayed into.
 
     GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone;
-    if (fContext->caps()->usesMixedSamples() && desc.fSampleCnt > 1) {
+    if (fContext->caps()->usesMixedSamples() && desc.fSampleCnt > 1 && !usesGLFBO0) {
+        // In GL, FBO 0 never supports mixed samples
         surfaceFlags |= GrInternalSurfaceFlags::kMixedSampled;
     }
-    if (fContext->caps()->maxWindowRectangles() > 0) {
+    if (fContext->caps()->maxWindowRectangles() > 0 && !usesGLFBO0) {
+        // In GL, FBO 0 never supports window rectangles
         surfaceFlags |= GrInternalSurfaceFlags::kWindowRectsSupport;
     }
+    if (usesGLFBO0) {
+        surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0;
+    }
 
     sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy(
             [lazyProxyData](GrResourceProvider* resourceProvider) {
diff --git a/src/core/SkSurfaceCharacterization.cpp b/src/core/SkSurfaceCharacterization.cpp
index b82f2a6..930e96f 100644
--- a/src/core/SkSurfaceCharacterization.cpp
+++ b/src/core/SkSurfaceCharacterization.cpp
@@ -25,6 +25,7 @@
            fStencilCnt == other.fStencilCnt &&
            fIsTextureable == other.fIsTextureable &&
            fIsMipMapped == other.fIsMipMapped &&
+           fUsesGLFBO0 == other.fUsesGLFBO0 &&
            fSurfaceProps == other.fSurfaceProps;
 }
 
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index bade6e3..7b0ab71 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -172,11 +172,16 @@
                                      const SkImageInfo& ii, const GrBackendFormat& backendFormat,
                                      int sampleCnt, GrSurfaceOrigin origin,
                                      const SkSurfaceProps& surfaceProps,
-                                     bool isMipMapped) {
+                                     bool isMipMapped, bool willUseGLFBO0) {
     if (!backendFormat.isValid()) {
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
 
+    if (kOpenGL_GrBackend != backendFormat.backend() && willUseGLFBO0) {
+        // The willUseGLFBO0 flags can only be used for a GL backend.
+        return SkSurfaceCharacterization(); // return an invalid characterization
+    }
+
     if (!fCaps->mipMapSupport()) {
         isMipMapped = false;
     }
@@ -211,6 +216,7 @@
                                      origin, config, FSAAType, sampleCnt,
                                      SkSurfaceCharacterization::Textureable(true),
                                      SkSurfaceCharacterization::MipMapped(isMipMapped),
+                                     SkSurfaceCharacterization::UsesGLFBO0(willUseGLFBO0),
                                      surfaceProps);
 }
 
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp
index c5d096d..5488625 100644
--- a/src/gpu/GrRenderTargetProxy.cpp
+++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -113,11 +113,9 @@
     SkASSERT(surface->asRenderTarget());
     SkASSERT(surface->asRenderTarget()->numStencilSamples() == this->numStencilSamples());
 
-    // DDL TODO: re-enable this after skbug.com/7748 (Add FBO-0-ness to SkSurfaceCharacterization)
-    // is fixed.
-    // GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
-    // GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
-    // SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
-    //          (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
+    GrInternalSurfaceFlags proxyFlags = fSurfaceFlags;
+    GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
+    SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
+             (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
 }
 #endif
diff --git a/src/gpu/GrRenderTargetProxyPriv.h b/src/gpu/GrRenderTargetProxyPriv.h
new file mode 100644
index 0000000..7c80099
--- /dev/null
+++ b/src/gpu/GrRenderTargetProxyPriv.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrRenderTargetProxyPriv_DEFINED
+#define GrRenderTargetProxyPriv_DEFINED
+
+#include "GrRenderTargetProxy.h"
+
+/**
+ * This class hides the more specialized capabilities of GrRenderTargetProxy.
+ */
+class GrRenderTargetProxyPriv {
+public:
+    void setGLRTFBOIDIs0() {
+        fRenderTargetProxy->setGLRTFBOIDIs0();
+    }
+
+    bool glRTFBOIDIs0() const {
+        return fRenderTargetProxy->glRTFBOIDIs0();
+    }
+
+private:
+    explicit GrRenderTargetProxyPriv(GrRenderTargetProxy* renderTargetProxy)
+            : fRenderTargetProxy(renderTargetProxy) {}
+    GrRenderTargetProxyPriv(const GrRenderTargetProxyPriv&) {} // unimpl
+    GrRenderTargetProxyPriv& operator=(const GrRenderTargetProxyPriv&); // unimpl
+
+    // No taking addresses of this type.
+    const GrRenderTargetProxyPriv* operator&() const;
+    GrRenderTargetProxyPriv* operator&();
+
+    GrRenderTargetProxy* fRenderTargetProxy;
+
+    friend class GrRenderTargetProxy;  // to construct/copy this type.
+};
+
+inline GrRenderTargetProxyPriv GrRenderTargetProxy::rtPriv() {
+    return GrRenderTargetProxyPriv(this);
+}
+
+inline const GrRenderTargetProxyPriv GrRenderTargetProxy::rtPriv() const {
+    return GrRenderTargetProxyPriv(const_cast<GrRenderTargetProxy*>(this));
+}
+
+#endif
+
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp
index dfc3d13..95d5543 100644
--- a/src/gpu/GrTextureRenderTargetProxy.cpp
+++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -125,10 +125,8 @@
     GrInternalSurfaceFlags surfaceFlags = surface->surfacePriv().flags();
     SkASSERT((proxyFlags & GrInternalSurfaceFlags::kTextureMask) ==
              (surfaceFlags & GrInternalSurfaceFlags::kTextureMask));
-    // DDL TODO: re-enable this after skbug.com/7748 (Add FBO-0-ness to SkSurfaceCharacterization)
-    // is fixed.
-    // SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
-    //          (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
+    SkASSERT((proxyFlags & GrInternalSurfaceFlags::kRenderTargetMask) ==
+             (surfaceFlags & GrInternalSurfaceFlags::kRenderTargetMask));
 }
 #endif
 
diff --git a/src/gpu/gl/GrGLRenderTarget.cpp b/src/gpu/gl/GrGLRenderTarget.cpp
index 5513e8a..382457d 100644
--- a/src/gpu/gl/GrGLRenderTarget.cpp
+++ b/src/gpu/gl/GrGLRenderTarget.cpp
@@ -46,6 +46,9 @@
     if (glCaps.maxWindowRectangles() > 0 && idDesc.fRTFBOID) {
         this->setSupportsWindowRects();
     }
+    if (!idDesc.fRTFBOID) {
+        this->setGLRTFBOIDIs0();
+    }
 }
 
 void GrGLRenderTarget::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index e9ae910..21ed1f9 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -11,6 +11,7 @@
 #include "GrContextPriv.h"
 #include "GrRenderTarget.h"
 #include "GrRenderTargetContextPriv.h"
+#include "GrRenderTargetProxyPriv.h"
 #include "GrTexture.h"
 
 #include "SkCanvas.h"
@@ -203,13 +204,19 @@
         return false;
     }
 
+    bool usesGLFBO0 = rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0();
+    // We should never get in the situation where we have a texture render target that is also
+    // backend by FBO 0.
+    SkASSERT(!usesGLFBO0 || !SkToBool(rtc->asTextureProxy()));
+
     SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType,
                                        rtc->colorSpaceInfo().refColorSpace());
 
     characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, rtc->origin(),
                           rtc->colorSpaceInfo().config(), rtc->fsaaType(), rtc->numStencilSamples(),
                           SkSurfaceCharacterization::Textureable(SkToBool(rtc->asTextureProxy())),
-                          SkSurfaceCharacterization::MipMapped(mipmapped), this->props());
+                          SkSurfaceCharacterization::MipMapped(mipmapped),
+                          SkSurfaceCharacterization::UsesGLFBO0(usesGLFBO0), this->props());
 
     return true;
 }
@@ -245,6 +252,10 @@
         }
     }
 
+    if (characterization.usesGLFBO0() != rtc->asRenderTargetProxy()->rtPriv().glRTFBOIDIs0()) {
+        return false;
+    }
+
     // TODO: the addition of colorType to the surfaceContext should remove this calculation
     SkColorType rtcColorType;
     if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &rtcColorType)) {
@@ -318,6 +329,11 @@
         return nullptr;
     }
 
+    if (c.usesGLFBO0()) {
+        // If we are making the surface we will never use FBO0.
+        return nullptr;
+    }
+
     if (!SkSurface_Gpu::Valid(context->caps(), c.config(), c.colorSpace())) {
         return nullptr;
     }