In ES3, validate that depth and stencil are the same image

BUG=605775

Change-Id: I9508c70a588270dae871dde79fea1df1c3fd1558
Reviewed-on: https://chromium-review.googlesource.com/341440
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index 010c9b9..f2adc4f 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -575,6 +575,13 @@
         {
             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
         }
+
+        // Starting from ES 3.0 stencil and depth, if present, should be the same image
+        if (data.clientVersion >= 3 && depthAttachment.isAttached() &&
+            stencilAttachment != depthAttachment)
+        {
+            return GL_FRAMEBUFFER_UNSUPPORTED;
+        }
     }
 
     // we need to have at least one attachment to be complete
diff --git a/src/libANGLE/FramebufferAttachment.cpp b/src/libANGLE/FramebufferAttachment.cpp
index 352a326..649295a 100644
--- a/src/libANGLE/FramebufferAttachment.cpp
+++ b/src/libANGLE/FramebufferAttachment.cpp
@@ -205,4 +205,24 @@
     return rx::GetAs<egl::Surface>(mResource);
 }
 
+bool FramebufferAttachment::operator==(const FramebufferAttachment &other) const
+{
+    if (mResource != other.mResource || mType != other.mType)
+    {
+        return false;
+    }
+
+    if (mType == GL_TEXTURE && getTextureImageIndex() != other.getTextureImageIndex())
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool FramebufferAttachment::operator!=(const FramebufferAttachment &other) const
+{
+    return !(*this == other);
+}
+
 }
diff --git a/src/libANGLE/FramebufferAttachment.h b/src/libANGLE/FramebufferAttachment.h
index 33196f5..8bdd918 100644
--- a/src/libANGLE/FramebufferAttachment.h
+++ b/src/libANGLE/FramebufferAttachment.h
@@ -136,6 +136,9 @@
         return error;
     }
 
+    bool operator==(const FramebufferAttachment &other) const;
+    bool operator!=(const FramebufferAttachment &other) const;
+
   private:
     gl::Error getRenderTarget(rx::FramebufferAttachmentRenderTarget **rtOut) const;
 
diff --git a/src/libANGLE/ImageIndex.cpp b/src/libANGLE/ImageIndex.cpp
index c84e7c5..9eb641c 100644
--- a/src/libANGLE/ImageIndex.cpp
+++ b/src/libANGLE/ImageIndex.cpp
@@ -78,6 +78,16 @@
     }
 }
 
+bool ImageIndex::operator==(const ImageIndex &other) const
+{
+    return (type == other.type) && (mipIndex == other.mipIndex) && (layerIndex == other.layerIndex);
+}
+
+bool ImageIndex::operator!=(const ImageIndex &other) const
+{
+    return !(*this == other);
+}
+
 ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn)
     : type(typeIn),
       mipIndex(mipIndexIn),
diff --git a/src/libANGLE/ImageIndex.h b/src/libANGLE/ImageIndex.h
index b527c7c..6f96b40 100644
--- a/src/libANGLE/ImageIndex.h
+++ b/src/libANGLE/ImageIndex.h
@@ -40,6 +40,8 @@
     static const GLint ENTIRE_LEVEL = static_cast<GLint>(-1);
 
     bool operator<(const ImageIndex &other) const;
+    bool operator==(const ImageIndex &other) const;
+    bool operator!=(const ImageIndex &other) const;
 
   private:
     friend class ImageIndexIterator;