Implement EGL_ANDROID_image_native_buffer.

BUG=angleproject:2508

Change-Id: I8ef2ce8320edeb336727905055f47bb299dec2ea
Reviewed-on: https://chromium-review.googlesource.com/c/1238886
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Reviewed-by: Yuly Novikov <ynovikov@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/common/utilities.cpp b/src/common/utilities.cpp
index 2f632cf..a94946e 100644
--- a/src/common/utilities.cpp
+++ b/src/common/utilities.cpp
@@ -929,6 +929,18 @@
     return target == EGL_GL_RENDERBUFFER_KHR;
 }
 
+bool IsExternalImageTarget(EGLenum target)
+{
+    switch (target)
+    {
+        case EGL_NATIVE_BUFFER_ANDROID:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
 const char *GetGenericErrorMessage(EGLint error)
 {
     switch (error)
diff --git a/src/common/utilities.h b/src/common/utilities.h
index 648fe2f..673e0c4 100644
--- a/src/common/utilities.h
+++ b/src/common/utilities.h
@@ -150,6 +150,7 @@
 EGLenum LayerIndexToCubeMapTextureTarget(size_t index);
 bool IsTextureTarget(EGLenum target);
 bool IsRenderbufferTarget(EGLenum target);
+bool IsExternalImageTarget(EGLenum target);
 
 const char *GetGenericErrorMessage(EGLint error);
 }  // namespace egl
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 1b495bc..6f3e5b7 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -1356,7 +1356,8 @@
       iosurfaceClientBuffer(false),
       createContextExtensionsEnabled(false),
       presentationTime(false),
-      blobCache(false)
+      blobCache(false),
+      imageNativeBuffer(false)
 {
 }
 
@@ -1405,6 +1406,7 @@
     InsertExtensionString("EGL_ANGLE_create_context_extensions_enabled",         createContextExtensionsEnabled,     &extensionStrings);
     InsertExtensionString("EGL_ANDROID_presentation_time",                       presentationTime,                   &extensionStrings);
     InsertExtensionString("EGL_ANDROID_blob_cache",                              blobCache,                          &extensionStrings);
+    InsertExtensionString("EGL_ANDROID_image_native_buffer",                     imageNativeBuffer,                  &extensionStrings);
     // TODO(jmadill): Enable this when complete.
     //InsertExtensionString("KHR_create_context_no_error",                       createContextNoError,               &extensionStrings);
     // clang-format on
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index e9f5c33..e427009 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -801,6 +801,9 @@
 
     // EGL_ANDROID_blob_cache
     bool blobCache;
+
+    // EGL_ANDROID_image_native_buffer
+    bool imageNativeBuffer;
 };
 
 struct DeviceExtensions
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index df640fe..ffb1066 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -719,6 +719,10 @@
     {
         sibling = context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
     }
+    else if (IsExternalImageTarget(target))
+    {
+        sibling = new ExternalImageSibling(mImplementation, context, target, buffer, attribs);
+    }
     else
     {
         UNREACHABLE();
@@ -1120,11 +1124,19 @@
 Error Display::validateClientBuffer(const Config *configuration,
                                     EGLenum buftype,
                                     EGLClientBuffer clientBuffer,
-                                    const AttributeMap &attribs)
+                                    const AttributeMap &attribs) const
 {
     return mImplementation->validateClientBuffer(configuration, buftype, clientBuffer, attribs);
 }
 
+Error Display::validateImageClientBuffer(const gl::Context *context,
+                                         EGLenum target,
+                                         EGLClientBuffer clientBuffer,
+                                         const egl::AttributeMap &attribs) const
+{
+    return mImplementation->validateImageClientBuffer(context, target, clientBuffer, attribs);
+}
+
 bool Display::isValidDisplay(const egl::Display *display)
 {
     const ANGLEPlatformDisplayMap *anglePlatformDisplayMap = GetANGLEPlatformDisplayMap();
diff --git a/src/libANGLE/Display.h b/src/libANGLE/Display.h
index 86f98e0..4dc8196 100644
--- a/src/libANGLE/Display.h
+++ b/src/libANGLE/Display.h
@@ -125,7 +125,11 @@
     Error validateClientBuffer(const Config *configuration,
                                EGLenum buftype,
                                EGLClientBuffer clientBuffer,
-                               const AttributeMap &attribs);
+                               const AttributeMap &attribs) const;
+    Error validateImageClientBuffer(const gl::Context *context,
+                                    EGLenum target,
+                                    EGLClientBuffer clientBuffer,
+                                    const egl::AttributeMap &attribs) const;
 
     static bool isValidDisplay(const Display *display);
     static bool isValidNativeDisplay(EGLNativeDisplayType display);
diff --git a/src/libANGLE/Image.cpp b/src/libANGLE/Image.cpp
index 2753f2f..5cbdf5a 100644
--- a/src/libANGLE/Image.cpp
+++ b/src/libANGLE/Image.cpp
@@ -25,7 +25,7 @@
 {
 gl::ImageIndex GetImageIndex(EGLenum eglTarget, const egl::AttributeMap &attribs)
 {
-    if (eglTarget == EGL_GL_RENDERBUFFER)
+    if (!IsTextureTarget(eglTarget))
     {
         return gl::ImageIndex();
     }
@@ -131,6 +131,76 @@
     return mTargetOf->isRenderable(context);
 }
 
+ExternalImageSibling::ExternalImageSibling(rx::EGLImplFactory *factory,
+                                           const gl::Context *context,
+                                           EGLenum target,
+                                           EGLClientBuffer buffer,
+                                           const AttributeMap &attribs)
+    : mImplementation(factory->createExternalImageSibling(context, target, buffer, attribs))
+{
+}
+
+gl::Extents ExternalImageSibling::getAttachmentSize(const gl::ImageIndex &imageIndex) const
+{
+    return mImplementation->getSize();
+}
+
+gl::Format ExternalImageSibling::getAttachmentFormat(GLenum binding,
+                                                     const gl::ImageIndex &imageIndex) const
+{
+    return mImplementation->getFormat();
+}
+
+GLsizei ExternalImageSibling::getAttachmentSamples(const gl::ImageIndex &imageIndex) const
+{
+    return mImplementation->getSamples();
+}
+
+bool ExternalImageSibling::isRenderable(const gl::Context *context,
+                                        GLenum binding,
+                                        const gl::ImageIndex &imageIndex) const
+{
+    return mImplementation->isRenderable(context);
+}
+
+bool ExternalImageSibling::isTextureable(const gl::Context *context) const
+{
+    return mImplementation->isTexturable(context);
+}
+
+void ExternalImageSibling::onAttach(const gl::Context *context)
+{
+}
+
+void ExternalImageSibling::onDetach(const gl::Context *context)
+{
+}
+
+GLuint ExternalImageSibling::getId() const
+{
+    UNREACHABLE();
+    return 0;
+}
+
+gl::InitState ExternalImageSibling::initState(const gl::ImageIndex &imageIndex) const
+{
+    return gl::InitState::Initialized;
+}
+
+void ExternalImageSibling::setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState)
+{
+}
+
+rx::ExternalImageSiblingImpl *ExternalImageSibling::getImplementation() const
+{
+    return mImplementation.get();
+}
+
+rx::FramebufferAttachmentObjectImpl *ExternalImageSibling::getAttachmentImpl() const
+{
+    return mImplementation.get();
+}
+
 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
     : label(nullptr),
       imageIndex(GetImageIndex(target, attribs)),
@@ -172,6 +242,13 @@
     if (mState.source != nullptr)
     {
         mState.source->removeImageSource(this);
+
+        // If the source is an external object, delete it
+        if (IsExternalImageTarget(mState.sourceType))
+        {
+            delete mState.source;
+        }
+
         mState.source = nullptr;
     }
 }
@@ -205,6 +282,9 @@
 
     if (mState.source == sibling)
     {
+        // The external source of an image cannot be redefined so it cannot be orpahend.
+        ASSERT(!IsExternalImageTarget(mState.sourceType));
+
         // If the sibling is the source, it cannot be a target.
         ASSERT(mState.targets.find(sibling) == mState.targets.end());
         mState.source = nullptr;
@@ -231,11 +311,16 @@
         return mState.format.info->textureAttachmentSupport(context->getClientVersion(),
                                                             context->getExtensions());
     }
-    if (IsRenderbufferTarget(mState.sourceType))
+    else if (IsRenderbufferTarget(mState.sourceType))
     {
         return mState.format.info->renderbufferSupport(context->getClientVersion(),
                                                        context->getExtensions());
     }
+    else if (IsExternalImageTarget(mState.sourceType))
+    {
+        ASSERT(mState.source != nullptr);
+        return mState.source->isRenderable(context, GL_NONE, gl::ImageIndex());
+    }
 
     UNREACHABLE();
     return false;
@@ -248,10 +333,15 @@
         return mState.format.info->textureSupport(context->getClientVersion(),
                                                   context->getExtensions());
     }
-    if (IsRenderbufferTarget(mState.sourceType))
+    else if (IsRenderbufferTarget(mState.sourceType))
     {
         return true;
     }
+    else if (IsExternalImageTarget(mState.sourceType))
+    {
+        ASSERT(mState.source != nullptr);
+        return rx::GetAs<ExternalImageSibling>(mState.source)->isTextureable(context);
+    }
 
     UNREACHABLE();
     return false;
diff --git a/src/libANGLE/Image.h b/src/libANGLE/Image.h
index f1b52c7..0034ac5 100644
--- a/src/libANGLE/Image.h
+++ b/src/libANGLE/Image.h
@@ -23,6 +23,7 @@
 {
 class EGLImplFactory;
 class ImageImpl;
+class ExternalImageSiblingImpl;
 }
 
 namespace egl
@@ -67,6 +68,41 @@
     BindingPointer<Image> mTargetOf;
 };
 
+// Wrapper for EGLImage sources that are not owned by ANGLE, these often have to do
+// platform-specific queries for format and size information.
+class ExternalImageSibling : public ImageSibling
+{
+  public:
+    ExternalImageSibling(rx::EGLImplFactory *factory,
+                         const gl::Context *context,
+                         EGLenum target,
+                         EGLClientBuffer buffer,
+                         const AttributeMap &attribs);
+
+    gl::Extents getAttachmentSize(const gl::ImageIndex &imageIndex) const override;
+    gl::Format getAttachmentFormat(GLenum binding, const gl::ImageIndex &imageIndex) const override;
+    GLsizei getAttachmentSamples(const gl::ImageIndex &imageIndex) const override;
+    bool isRenderable(const gl::Context *context,
+                      GLenum binding,
+                      const gl::ImageIndex &imageIndex) const override;
+    bool isTextureable(const gl::Context *context) const;
+
+    void onAttach(const gl::Context *context) override;
+    void onDetach(const gl::Context *context) override;
+    GLuint getId() const override;
+
+    gl::InitState initState(const gl::ImageIndex &imageIndex) const override;
+    void setInitState(const gl::ImageIndex &imageIndex, gl::InitState initState) override;
+
+    rx::ExternalImageSiblingImpl *getImplementation() const;
+
+  protected:
+    rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override;
+
+  private:
+    std::unique_ptr<rx::ExternalImageSiblingImpl> mImplementation;
+};
+
 struct ImageState : private angle::NonCopyable
 {
     ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs);
diff --git a/src/libANGLE/renderer/DisplayImpl.cpp b/src/libANGLE/renderer/DisplayImpl.cpp
index 80c044a..cbfc1a8 100644
--- a/src/libANGLE/renderer/DisplayImpl.cpp
+++ b/src/libANGLE/renderer/DisplayImpl.cpp
@@ -44,6 +44,15 @@
     return egl::EglBadDisplay() << "DisplayImpl::validateClientBuffer unimplemented.";
 }
 
+egl::Error DisplayImpl::validateImageClientBuffer(const gl::Context *context,
+                                                  EGLenum target,
+                                                  EGLClientBuffer clientBuffer,
+                                                  const egl::AttributeMap &attribs) const
+{
+    UNREACHABLE();
+    return egl::EglBadDisplay() << "DisplayImpl::validateImageClientBuffer unimplemented.";
+}
+
 const egl::Caps &DisplayImpl::getCaps() const
 {
     if (!mCapsInitialized)
diff --git a/src/libANGLE/renderer/DisplayImpl.h b/src/libANGLE/renderer/DisplayImpl.h
index cb3515d..45bedd9 100644
--- a/src/libANGLE/renderer/DisplayImpl.h
+++ b/src/libANGLE/renderer/DisplayImpl.h
@@ -66,6 +66,10 @@
                                             EGLenum buftype,
                                             EGLClientBuffer clientBuffer,
                                             const egl::AttributeMap &attribs) const;
+    virtual egl::Error validateImageClientBuffer(const gl::Context *context,
+                                                 EGLenum target,
+                                                 EGLClientBuffer clientBuffer,
+                                                 const egl::AttributeMap &attribs) const;
 
     virtual std::string getVendorString() const = 0;
 
diff --git a/src/libANGLE/renderer/EGLImplFactory.h b/src/libANGLE/renderer/EGLImplFactory.h
index 72530f0..181cc01 100644
--- a/src/libANGLE/renderer/EGLImplFactory.h
+++ b/src/libANGLE/renderer/EGLImplFactory.h
@@ -31,6 +31,7 @@
 {
 class ContextImpl;
 class ImageImpl;
+class ExternalImageSiblingImpl;
 class SurfaceImpl;
 
 class EGLImplFactory : angle::NonCopyable
@@ -41,16 +42,16 @@
 
     virtual SurfaceImpl *createWindowSurface(const egl::SurfaceState &state,
                                              EGLNativeWindowType window,
-                                             const egl::AttributeMap &attribs) = 0;
+                                             const egl::AttributeMap &attribs)           = 0;
     virtual SurfaceImpl *createPbufferSurface(const egl::SurfaceState &state,
-                                              const egl::AttributeMap &attribs) = 0;
+                                              const egl::AttributeMap &attribs)          = 0;
     virtual SurfaceImpl *createPbufferFromClientBuffer(const egl::SurfaceState &state,
                                                        EGLenum buftype,
                                                        EGLClientBuffer clientBuffer,
                                                        const egl::AttributeMap &attribs) = 0;
     virtual SurfaceImpl *createPixmapSurface(const egl::SurfaceState &state,
                                              NativePixmapType nativePixmap,
-                                             const egl::AttributeMap &attribs) = 0;
+                                             const egl::AttributeMap &attribs)           = 0;
 
     virtual ImageImpl *createImage(const egl::ImageState &state,
                                    const gl::Context *context,
@@ -65,6 +66,15 @@
     virtual StreamProducerImpl *createStreamProducerD3DTexture(
         egl::Stream::ConsumerType consumerType,
         const egl::AttributeMap &attribs) = 0;
+
+    virtual ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context,
+                                                                 EGLenum target,
+                                                                 EGLClientBuffer buffer,
+                                                                 const egl::AttributeMap &attribs)
+    {
+        UNREACHABLE();
+        return nullptr;
+    }
 };
 
 }  // namespace rx
diff --git a/src/libANGLE/renderer/ImageImpl.h b/src/libANGLE/renderer/ImageImpl.h
index d044639..8f5d720 100644
--- a/src/libANGLE/renderer/ImageImpl.h
+++ b/src/libANGLE/renderer/ImageImpl.h
@@ -11,6 +11,8 @@
 
 #include "common/angleutils.h"
 #include "libANGLE/Error.h"
+#include "libANGLE/formatutils.h"
+#include "libANGLE/renderer/FramebufferAttachmentObjectImpl.h"
 
 namespace gl
 {
@@ -26,6 +28,18 @@
 
 namespace rx
 {
+class ExternalImageSiblingImpl : public FramebufferAttachmentObjectImpl
+{
+  public:
+    virtual ~ExternalImageSiblingImpl() {}
+
+    virtual gl::Format getFormat() const                        = 0;
+    virtual bool isRenderable(const gl::Context *context) const = 0;
+    virtual bool isTexturable(const gl::Context *context) const = 0;
+    virtual gl::Extents getSize() const                         = 0;
+    virtual size_t getSamples() const                           = 0;
+};
+
 class ImageImpl : angle::NonCopyable
 {
   public:
diff --git a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
index 54c8056..e19fa47 100644
--- a/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
+++ b/src/libANGLE/renderer/gl/egl/DisplayEGL.cpp
@@ -131,6 +131,8 @@
     outExtensions->glTexture3DImage      = mEGL->hasExtension("EGL_KHR_gl_texture_3D_image");
     outExtensions->glRenderbufferImage   = mEGL->hasExtension("EGL_KHR_gl_renderbuffer_image");
 
+    outExtensions->imageNativeBuffer = mEGL->hasExtension("EGL_ANDROID_image_native_buffer");
+
     DisplayGL::generateExtensions(outExtensions);
 }
 
diff --git a/src/libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h b/src/libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h
new file mode 100644
index 0000000..17c8631
--- /dev/null
+++ b/src/libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h
@@ -0,0 +1,29 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// ExternalImageSiblingEGL.h: Defines the ExternalImageSiblingEGL interface to abstract all external
+// image siblings in the EGL backend
+
+#ifndef LIBANGLE_RENDERER_GL_EGL_EXTERNALIMAGESIBLINGEGL_H_
+#define LIBANGLE_RENDERER_GL_EGL_EXTERNALIMAGESIBLINGEGL_H_
+
+#include "libANGLE/renderer/ImageImpl.h"
+
+namespace rx
+{
+
+class ExternalImageSiblingEGL : public ExternalImageSiblingImpl
+{
+  public:
+    ExternalImageSiblingEGL() {}
+    virtual ~ExternalImageSiblingEGL() {}
+
+    virtual EGLClientBuffer getBuffer() const = 0;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_GL_EGL_EXTERNALIMAGESIBLINGEGL_H_
diff --git a/src/libANGLE/renderer/gl/egl/ImageEGL.cpp b/src/libANGLE/renderer/gl/egl/ImageEGL.cpp
index 12b5ceb..6a903fa 100644
--- a/src/libANGLE/renderer/gl/egl/ImageEGL.cpp
+++ b/src/libANGLE/renderer/gl/egl/ImageEGL.cpp
@@ -15,6 +15,7 @@
 #include "libANGLE/renderer/gl/StateManagerGL.h"
 #include "libANGLE/renderer/gl/TextureGL.h"
 #include "libANGLE/renderer/gl/egl/ContextEGL.h"
+#include "libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h"
 #include "libANGLE/renderer/gl/egl/FunctionsEGL.h"
 
 namespace rx
@@ -71,6 +72,13 @@
         buffer = gl_egl::GLObjectHandleToEGLClientBuffer(renderbufferGL->getRenderbufferID());
         mNativeInternalFormat = renderbufferGL->getNativeInternalFormat();
     }
+    else if (egl::IsExternalImageTarget(mTarget))
+    {
+        const ExternalImageSiblingEGL *externalImageSibling =
+            GetImplAs<ExternalImageSiblingEGL>(GetAs<egl::ExternalImageSibling>(mState.source));
+        buffer                = externalImageSibling->getBuffer();
+        mNativeInternalFormat = externalImageSibling->getFormat().info->sizedInternalFormat;
+    }
     else
     {
         UNREACHABLE();
diff --git a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
index 3b9459b..f1ddecf 100644
--- a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
+++ b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp
@@ -22,6 +22,7 @@
 #include "libANGLE/renderer/gl/egl/PbufferSurfaceEGL.h"
 #include "libANGLE/renderer/gl/egl/RendererEGL.h"
 #include "libANGLE/renderer/gl/egl/WindowSurfaceEGL.h"
+#include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h"
 #include "libANGLE/renderer/gl/renderergl_utils.h"
 
 namespace
@@ -453,6 +454,37 @@
     return ANativeWindow_getFormat(window) >= 0;
 }
 
+egl::Error DisplayAndroid::validateImageClientBuffer(const gl::Context *context,
+                                                     EGLenum target,
+                                                     EGLClientBuffer clientBuffer,
+                                                     const egl::AttributeMap &attribs) const
+{
+    switch (target)
+    {
+        case EGL_NATIVE_BUFFER_ANDROID:
+            return egl::NoError();
+
+        default:
+            return DisplayEGL::validateImageClientBuffer(context, target, clientBuffer, attribs);
+    }
+}
+
+ExternalImageSiblingImpl *DisplayAndroid::createExternalImageSibling(
+    const gl::Context *context,
+    EGLenum target,
+    EGLClientBuffer buffer,
+    const egl::AttributeMap &attribs)
+{
+    switch (target)
+    {
+        case EGL_NATIVE_BUFFER_ANDROID:
+            return new NativeBufferImageSiblingAndroid(buffer);
+
+        default:
+            return DisplayEGL::createExternalImageSibling(context, target, buffer, attribs);
+    }
+}
+
 DeviceImpl *DisplayAndroid::createDevice()
 {
     UNIMPLEMENTED();
diff --git a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
index cf75d36..e80f507 100644
--- a/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
+++ b/src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h
@@ -54,6 +54,15 @@
     egl::Error restoreLostDevice(const egl::Display *display) override;
 
     bool isValidNativeWindow(EGLNativeWindowType window) const override;
+    egl::Error validateImageClientBuffer(const gl::Context *context,
+                                         EGLenum target,
+                                         EGLClientBuffer clientBuffer,
+                                         const egl::AttributeMap &attribs) const override;
+
+    ExternalImageSiblingImpl *createExternalImageSibling(const gl::Context *context,
+                                                         EGLenum target,
+                                                         EGLClientBuffer buffer,
+                                                         const egl::AttributeMap &attribs) override;
 
     DeviceImpl *createDevice() override;
 
diff --git a/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp b/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp
new file mode 100644
index 0000000..f3125b9
--- /dev/null
+++ b/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp
@@ -0,0 +1,98 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// NativeBufferImageSiblingAndroid.cpp: Implements the NativeBufferImageSiblingAndroid class
+
+#include "libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h"
+
+#include "libANGLE/renderer/gl/egl/android/android_util.h"
+
+// Taken from cutils/native_handle.h:
+// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/cutils/native_handle.h
+typedef struct native_handle
+{
+    int version; /* sizeof(native_handle_t) */
+    int numFds;  /* number of file-descriptors at &data[0] */
+    int numInts; /* number of ints at &data[numFds] */
+    int data[0]; /* numFds + numInts ints */
+} native_handle_t;
+
+// Taken from nativebase/nativebase.h
+// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativebase/include/nativebase/nativebase.h
+typedef const native_handle_t *buffer_handle_t;
+
+typedef struct android_native_base_t
+{
+    /* a magic value defined by the actual EGL native type */
+    int magic;
+    /* the sizeof() of the actual EGL native type */
+    int version;
+    void *reserved[4];
+    /* reference-counting interface */
+    void (*incRef)(struct android_native_base_t *base);
+    void (*decRef)(struct android_native_base_t *base);
+} android_native_base_t;
+
+typedef struct ANativeWindowBuffer
+{
+    struct android_native_base_t common;
+    int width;
+    int height;
+    int stride;
+    int format;
+    int usage_deprecated;
+    uintptr_t layerCount;
+    void *reserved[1];
+    const native_handle_t *handle;
+    uint64_t usage;
+    // we needed extra space for storing the 64-bits usage flags
+    // the number of slots to use from reserved_proc depends on the
+    // architecture.
+    void *reserved_proc[8 - (sizeof(uint64_t) / sizeof(void *))];
+} ANativeWindowBuffer_t;
+
+namespace rx
+{
+NativeBufferImageSiblingAndroid::NativeBufferImageSiblingAndroid(EGLClientBuffer buffer)
+    : mBuffer(static_cast<struct ANativeWindowBuffer *>(buffer))
+{
+}
+
+NativeBufferImageSiblingAndroid::~NativeBufferImageSiblingAndroid()
+{
+}
+
+gl::Format NativeBufferImageSiblingAndroid::getFormat() const
+{
+    return gl::Format(android::NativePixelFormatToGLInternalFormat(mBuffer->format));
+}
+
+bool NativeBufferImageSiblingAndroid::isRenderable(const gl::Context *context) const
+{
+    return true;
+}
+
+bool NativeBufferImageSiblingAndroid::isTexturable(const gl::Context *context) const
+{
+    return true;
+}
+
+gl::Extents NativeBufferImageSiblingAndroid::getSize() const
+{
+    return gl::Extents(mBuffer->width, mBuffer->height, 1);
+}
+
+size_t NativeBufferImageSiblingAndroid::getSamples() const
+{
+    return 0;
+}
+
+EGLClientBuffer NativeBufferImageSiblingAndroid::getBuffer() const
+{
+    return static_cast<EGLClientBuffer>(mBuffer);
+}
+
+}  // namespace rx
diff --git a/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h b/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h
new file mode 100644
index 0000000..20c8960
--- /dev/null
+++ b/src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h
@@ -0,0 +1,42 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// NativeBufferImageSiblingAndroid.h: Defines the NativeBufferImageSiblingAndroid to wrap EGL images
+// created from ANativeWindowBuffer objects
+
+#ifndef LIBANGLE_RENDERER_GL_EGL_ANDROID_NATIVEBUFFERIMAGESIBLINGANDROID_H_
+#define LIBANGLE_RENDERER_GL_EGL_ANDROID_NATIVEBUFFERIMAGESIBLINGANDROID_H_
+
+#include "libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h"
+
+struct ANativeWindowBuffer;
+
+namespace rx
+{
+
+class NativeBufferImageSiblingAndroid : public ExternalImageSiblingEGL
+{
+  public:
+    NativeBufferImageSiblingAndroid(EGLClientBuffer buffer);
+    virtual ~NativeBufferImageSiblingAndroid();
+
+    // ExternalImageSiblingImpl interface
+    gl::Format getFormat() const override;
+    bool isRenderable(const gl::Context *context) const override;
+    bool isTexturable(const gl::Context *context) const override;
+    gl::Extents getSize() const override;
+    size_t getSamples() const override;
+
+    // ExternalImageSiblingEGL interface
+    EGLClientBuffer getBuffer() const override;
+
+  private:
+    struct ANativeWindowBuffer *mBuffer;
+};
+
+}  // namespace rx
+
+#endif  // LIBANGLE_RENDERER_GL_EGL_ANDROID_NATIVEBUFFERIMAGESIBLINGANDROID_H_
diff --git a/src/libANGLE/renderer/gl/egl/android/android_util.cpp b/src/libANGLE/renderer/gl/egl/android/android_util.cpp
new file mode 100644
index 0000000..8ead15d
--- /dev/null
+++ b/src/libANGLE/renderer/gl/egl/android/android_util.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// android_util.cpp: Utilities for the using the Android platform
+
+#include "libANGLE/renderer/gl/egl/android/android_util.h"
+
+namespace rx
+{
+
+namespace
+{
+
+// Taken from android/hardware_buffer.h
+// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativewindow/include/android/hardware_buffer.h
+
+// AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM,
+// AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM formats were deprecated and re-added explicitly.
+
+// clang-format off
+/**
+ * Buffer pixel formats.
+ */
+enum {
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
+     *   OpenGL ES: GL_RGBA8
+     */
+    AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM           = 1,
+    /**
+     * 32 bits per pixel, 8 bits per channel format where alpha values are
+     * ignored (always opaque).
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R8G8B8A8_UNORM
+     *   OpenGL ES: GL_RGB8
+     */
+    AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM           = 2,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R8G8B8_UNORM
+     *   OpenGL ES: GL_RGB8
+     */
+    AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM             = 3,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16
+     *   OpenGL ES: GL_RGB565
+     */
+    AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM             = 4,
+    AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM           = 5,
+    AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM           = 6,
+    AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM           = 7,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT
+     *   OpenGL ES: GL_RGBA16F
+     */
+    AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT       = 0x16,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_A2B10G10R10_UNORM_PACK32
+     *   OpenGL ES: GL_RGB10_A2
+     */
+    AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM        = 0x2b,
+    /**
+     * An opaque binary blob format that must have height 1, with width equal to
+     * the buffer size in bytes.
+     */
+    AHARDWAREBUFFER_FORMAT_BLOB                     = 0x21,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D16_UNORM
+     *   OpenGL ES: GL_DEPTH_COMPONENT16
+     */
+    AHARDWAREBUFFER_FORMAT_D16_UNORM                = 0x30,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32
+     *   OpenGL ES: GL_DEPTH_COMPONENT24
+     */
+    AHARDWAREBUFFER_FORMAT_D24_UNORM                = 0x31,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D24_UNORM_S8_UINT
+     *   OpenGL ES: GL_DEPTH24_STENCIL8
+     */
+    AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT        = 0x32,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D32_SFLOAT
+     *   OpenGL ES: GL_DEPTH_COMPONENT32F
+     */
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT                = 0x33,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT
+     *   OpenGL ES: GL_DEPTH32F_STENCIL8
+     */
+    AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT        = 0x34,
+    /**
+     * Corresponding formats:
+     *   Vulkan: VK_FORMAT_S8_UINT
+     *   OpenGL ES: GL_STENCIL_INDEX8
+     */
+    AHARDWAREBUFFER_FORMAT_S8_UINT                  = 0x35,
+};
+// clang-format on
+
+}  // anonymous namespace
+
+namespace android
+{
+GLenum NativePixelFormatToGLInternalFormat(int pixelFormat)
+{
+    switch (pixelFormat)
+    {
+        case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+            return GL_RGBA8;
+        case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+            return GL_RGB8;
+        case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+            return GL_RGB8;
+        case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+            return GL_RGB565;
+        case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
+            return GL_BGRA8_EXT;
+        case AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM:
+            return GL_RGBA4;
+        case AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM:
+            return GL_RGB5_A1;
+        case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+            return GL_RGBA16F;
+        case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
+            return GL_RGB10_A2;
+        case AHARDWAREBUFFER_FORMAT_BLOB:
+            return GL_NONE;
+        case AHARDWAREBUFFER_FORMAT_D16_UNORM:
+            return GL_DEPTH_COMPONENT16;
+        case AHARDWAREBUFFER_FORMAT_D24_UNORM:
+            return GL_DEPTH_COMPONENT24;
+        case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
+            return GL_DEPTH24_STENCIL8;
+        case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
+            return GL_DEPTH_COMPONENT32F;
+        case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
+            return GL_DEPTH32F_STENCIL8;
+        case AHARDWAREBUFFER_FORMAT_S8_UINT:
+            return GL_STENCIL_INDEX8;
+        default:
+            return GL_NONE;
+    }
+}
+}
+}
diff --git a/src/libANGLE/renderer/gl/egl/android/android_util.h b/src/libANGLE/renderer/gl/egl/android/android_util.h
new file mode 100644
index 0000000..aaad466
--- /dev/null
+++ b/src/libANGLE/renderer/gl/egl/android/android_util.h
@@ -0,0 +1,23 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// android_util.h: Utilities for the using the Android platform
+
+#ifndef LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
+#define LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
+
+#include "angle_gl.h"
+
+namespace rx
+{
+
+namespace android
+{
+GLenum NativePixelFormatToGLInternalFormat(int pixelFormat);
+}
+}
+
+#endif  // LIBANGLE_RENDERER_GL_EGL_ANDROID_ANDROID_UTIL_H_
\ No newline at end of file
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index ba3c5d4..0a944ad 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -1649,7 +1649,8 @@
                              EGLClientBuffer buffer,
                              const AttributeMap &attributes)
 {
-    ANGLE_TRY(ValidateContext(display, context));
+
+    ANGLE_TRY(ValidateDisplay(display));
 
     const DisplayExtensions &displayExtensions = display->getExtensions();
 
@@ -1728,6 +1729,7 @@
                 return EglBadParameter() << "buffer cannot reference a 2D texture with the name 0.";
             }
 
+            ANGLE_TRY(ValidateContext(display, context));
             const gl::Texture *texture =
                 context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
             if (texture == nullptr || texture->getType() != gl::TextureType::_2D)
@@ -1770,6 +1772,7 @@
                        << "buffer cannot reference a cubemap texture with the name 0.";
             }
 
+            ANGLE_TRY(ValidateContext(display, context));
             const gl::Texture *texture =
                 context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
             if (texture == nullptr || texture->getType() != gl::TextureType::CubeMap)
@@ -1815,6 +1818,7 @@
                 return EglBadParameter() << "buffer cannot reference a 3D texture with the name 0.";
             }
 
+            ANGLE_TRY(ValidateContext(display, context));
             const gl::Texture *texture =
                 context->getTexture(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
             if (texture == nullptr || texture->getType() != gl::TextureType::_3D)
@@ -1868,6 +1872,7 @@
                        << "buffer cannot reference a renderbuffer with the name 0.";
             }
 
+            ANGLE_TRY(ValidateContext(display, context));
             const gl::Renderbuffer *renderbuffer =
                 context->getRenderbuffer(egl_gl::EGLClientBufferToGLObjectHandle(buffer));
             if (renderbuffer == nullptr)
@@ -1882,6 +1887,22 @@
         }
         break;
 
+        case EGL_NATIVE_BUFFER_ANDROID:
+        {
+            if (!displayExtensions.imageNativeBuffer)
+            {
+                return EglBadParameter() << "EGL_ANDROID_image_native_buffer not supported.";
+            }
+
+            if (context != nullptr)
+            {
+                return EglBadContext() << "ctx must be EGL_NO_CONTEXT.";
+            }
+
+            ANGLE_TRY(display->validateImageClientBuffer(context, target, buffer, attributes));
+        }
+        break;
+
         default:
             return EglBadParameter()
                    << "invalid target: 0x" << std::hex << std::uppercase << target;
diff --git a/src/libGLESv2.gni b/src/libGLESv2.gni
index 2a98dd6..fff5b6e 100644
--- a/src/libGLESv2.gni
+++ b/src/libGLESv2.gni
@@ -690,6 +690,7 @@
   "src/libANGLE/renderer/gl/egl/ContextEGL.h",
   "src/libANGLE/renderer/gl/egl/DisplayEGL.cpp",
   "src/libANGLE/renderer/gl/egl/DisplayEGL.h",
+  "src/libANGLE/renderer/gl/egl/ExternalImageSiblingEGL.h",
   "src/libANGLE/renderer/gl/egl/egl_utils.cpp",
   "src/libANGLE/renderer/gl/egl/egl_utils.h",
   "src/libANGLE/renderer/gl/egl/FunctionsEGL.cpp",
@@ -717,8 +718,12 @@
   "src/libANGLE/renderer/gl/egl/ozone/SurfaceOzone.h",
 ]
 libangle_gl_egl_android_sources = [
+  "src/libANGLE/renderer/gl/egl/android/android_util.cpp",
+  "src/libANGLE/renderer/gl/egl/android/android_util.h",
   "src/libANGLE/renderer/gl/egl/android/DisplayAndroid.cpp",
   "src/libANGLE/renderer/gl/egl/android/DisplayAndroid.h",
+  "src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.cpp",
+  "src/libANGLE/renderer/gl/egl/android/NativeBufferImageSiblingAndroid.h",
 ]
 libangle_gl_cgl_sources = [
   "src/libANGLE/renderer/gl/cgl/DisplayCGL.mm",