Take into accout the GrBackendFormat when deciding if we can chain textures together.

Bug: skia:
Change-Id: I8c26bed1bb18318f96d248c227e3b33b190d2a05
Reviewed-on: https://skia-review.googlesource.com/c/173320
Commit-Queue: Greg Daniel <egdaniel@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/include/gpu/GrBackendSurface.h b/include/gpu/GrBackendSurface.h
index e50f222..c72283e 100644
--- a/include/gpu/GrBackendSurface.h
+++ b/include/gpu/GrBackendSurface.h
@@ -66,6 +66,9 @@
         return GrBackendFormat(config);
     }
 
+    bool operator==(const GrBackendFormat& that) const;
+    bool operator!=(const GrBackendFormat& that) const { return !(*this == that); }
+
     GrBackendApi backend() const { return fBackend; }
     GrTextureType textureType() const { return fTextureType; }
 
diff --git a/include/gpu/vk/GrVkTypes.h b/include/gpu/vk/GrVkTypes.h
index c76c878..ec88a5f 100644
--- a/include/gpu/vk/GrVkTypes.h
+++ b/include/gpu/vk/GrVkTypes.h
@@ -93,9 +93,15 @@
             , fChromaFilter(chromaFilter)
             , fForceExplicitReconstruction(forceExplicitReconstruction)
             , fExternalFormat(externalFormat)
-            , fExternalFormatFeatures(externalFormatFeatures) {}
+            , fExternalFormatFeatures(externalFormatFeatures) {
+        SkASSERT(fExternalFormat);
+    }
 
     bool operator==(const GrVkYcbcrConversionInfo& that) const {
+        // Invalid objects are not required to have all other fields intialized or matching.
+        if (!this->isValid() && !that.isValid()) {
+            return true;
+        }
         return this->fYcbcrModel == that.fYcbcrModel &&
                this->fYcbcrRange == that.fYcbcrRange &&
                this->fXChromaOffset == that.fXChromaOffset &&
@@ -106,6 +112,7 @@
         // We don't check fExternalFormatFeatures here since all matching external formats must have
         // the same format features at least in terms of how they effect ycbcr sampler conversion.
     }
+    bool operator!=(const GrVkYcbcrConversionInfo& that) const { return !(*this == that); }
 
     bool isValid() const { return fExternalFormat != 0; }
 
diff --git a/include/private/GrTextureProxy.h b/include/private/GrTextureProxy.h
index cdfd07a..0926f16 100644
--- a/include/private/GrTextureProxy.h
+++ b/include/private/GrTextureProxy.h
@@ -44,6 +44,12 @@
     bool hasRestrictedSampling() const {
         return GrTextureTypeHasRestrictedSampling(this->textureType());
     }
+
+    // Returns true if the passed in proxies can be used as dynamic state together when flushing
+    // draws to the gpu.
+    static bool ProxiesAreCompatibleAsDynamicState(const GrTextureProxy* first,
+                                                   const GrTextureProxy* second);
+
     /**
      * Return the texture proxy's unique key. It will be invalid if the proxy doesn't have one.
      */
diff --git a/src/gpu/GrBackendSurface.cpp b/src/gpu/GrBackendSurface.cpp
index 72f4fb4..c512c0a 100644
--- a/src/gpu/GrBackendSurface.cpp
+++ b/src/gpu/GrBackendSurface.cpp
@@ -135,6 +135,38 @@
     return copy;
 }
 
+bool GrBackendFormat::operator==(const GrBackendFormat& that) const {
+    // Invalid GrBackendFormats are never equal to anything.
+    if (!fValid || !that.fValid) {
+        return false;
+    }
+
+    if (fBackend != that.fBackend) {
+        return false;
+    }
+
+    switch (fBackend) {
+        case GrBackendApi::kOpenGL:
+            return fGLFormat == that.fGLFormat;
+        case GrBackendApi::kVulkan:
+#ifdef SK_VULKAN
+            return fVk.fFormat == that.fVk.fFormat &&
+                   fVk.fYcbcrConversionInfo == that.fVk.fYcbcrConversionInfo;
+#endif
+            break;
+#ifdef SK_METAL
+        case GrBackendApi::kMetal:
+            return fMtlFormat == that.fMtlFormat;
+#endif
+            break;
+        case GrBackendApi::kMock:
+            return fMockFormat == that.fMockFormat;
+        default:
+            SK_ABORT("Unknown GrBackend");
+    }
+    return false;
+}
+
 GrBackendTexture::GrBackendTexture(int width,
                                    int height,
                                    const GrVkImageInfo& vkInfo)
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index 517b832..854ed17 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -138,6 +138,13 @@
                                   this->proxyMipMapped(), !this->priv().isExact());
 }
 
+bool GrTextureProxy::ProxiesAreCompatibleAsDynamicState(const GrTextureProxy* first,
+                                                        const GrTextureProxy* second) {
+    return first->config() == second->config() &&
+           first->textureType() == second->textureType() &&
+           first->backendFormat() == second->backendFormat();
+}
+
 void GrTextureProxy::setUniqueKey(GrProxyProvider* proxyProvider, const GrUniqueKey& key) {
     SkASSERT(key.isValid());
     SkASSERT(!fUniqueKey.isValid()); // proxies can only ever get one uniqueKey
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 088d693..1ca23df 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1509,8 +1509,8 @@
         textures[i].fAlpha = set[i].fAlpha;
         textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags);
         if (n > 0 &&
-            (textures[i].fProxy->textureType() != textures[base].fProxy->textureType() ||
-             textures[i].fProxy->config() != textures[base].fProxy->config() ||
+            (!GrTextureProxy::ProxiesAreCompatibleAsDynamicState(textures[i].fProxy.get(),
+                                                                 textures[base].fProxy.get()) ||
              set[i].fImage->alphaType() != set[base].fImage->alphaType() ||
              !SkColorSpace::Equals(set[i].fImage->colorSpace(), set[base].fImage->colorSpace()))) {
             draw();
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 987d65a..11f996b 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -556,8 +556,7 @@
         if (fProxyCnt > 1 || that->fProxyCnt > 1 ||
             thisProxy->uniqueID() != thatProxy->uniqueID()) {
             // We can't merge across different proxies. Check if 'this' can be chained with 'that'.
-            if (thisProxy->config() == thatProxy->config() &&
-                thisProxy->textureType() == thatProxy->textureType() &&
+            if (GrTextureProxy::ProxiesAreCompatibleAsDynamicState(thisProxy, thatProxy) &&
                 caps.dynamicStateArrayGeometryProcessorTextureSupport()) {
                 return CombineResult::kMayChain;
             }