Move incomplete texture logic to shared helper.

The incomplete texture handling is similar between the D3D and Vulkan
back-ends. We create 1x1 textures, initialize them to black, and bind
them when we detect incomplete textures. We would also bind incomplete
textures when we detect feedback loops. In the GL back-end, we
wouldn't detect feedback loops, and would allow the driver to handle
incompleteness.

Instead implement this in a shared helper class, and do the feedback
loop detection in the front-end for every back-end. This makes our
behaviour more consistent between back-ends, and prevents undefined
behaviour.

Because initializing multisample textures is tricky (they
can't be updated with TexImage calls) we do a bit of a workaround so
the back-end can clear the incomplete multisample texture initially.

This progresses the initial Vulkan textures implementation.

BUG=angleproject:2167

Change-Id: I79ddcc0711fcc986f2578a52ac6f701231d241ac
Reviewed-on: https://chromium-review.googlesource.com/700993
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 47b844c..0589f68 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -1648,7 +1648,7 @@
                              &mDirtyStencilAttachmentBinding, type, binding, textureIndex,
                              attachmentObj, numViews, baseViewIndex, multiviewLayout,
                              viewportOffsets);
-            return;
+            break;
         }
 
         case GL_DEPTH:
@@ -1690,6 +1690,8 @@
         }
         break;
     }
+
+    mAttachedTextures.reset();
 }
 
 void Framebuffer::updateAttachment(const Context *context,
@@ -2144,4 +2146,35 @@
     }
 }
 
+bool Framebuffer::hasTextureAttachment(const Texture *texture) const
+{
+    if (!mAttachedTextures.valid())
+    {
+        std::set<const FramebufferAttachmentObject *> attachedTextures;
+
+        for (const auto &colorAttachment : mState.mColorAttachments)
+        {
+            if (colorAttachment.isAttached() && colorAttachment.type() == GL_TEXTURE)
+            {
+                attachedTextures.insert(colorAttachment.getResource());
+            }
+        }
+
+        if (mState.mDepthAttachment.isAttached() && mState.mDepthAttachment.type() == GL_TEXTURE)
+        {
+            attachedTextures.insert(mState.mDepthAttachment.getResource());
+        }
+
+        if (mState.mStencilAttachment.isAttached() &&
+            mState.mStencilAttachment.type() == GL_TEXTURE)
+        {
+            attachedTextures.insert(mState.mStencilAttachment.getResource());
+        }
+
+        mAttachedTextures = std::move(attachedTextures);
+    }
+
+    return (mAttachedTextures.value().count(texture) > 0);
+}
+
 }  // namespace gl