Implement EGL_KHR_debug.

BUG=angleproject:1618

Change-Id: I790944b49badc910b6c72266469fcb8e86ac4252
Reviewed-on: https://chromium-review.googlesource.com/1019387
Commit-Queue: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/common/PackedEGLEnums_autogen.cpp b/src/common/PackedEGLEnums_autogen.cpp
index 77fb3d4..e09a9a6 100644
--- a/src/common/PackedEGLEnums_autogen.cpp
+++ b/src/common/PackedEGLEnums_autogen.cpp
@@ -16,6 +16,90 @@
 {
 
 template <>
+MessageType FromEGLenum<MessageType>(EGLenum from)
+{
+    switch (from)
+    {
+        case EGL_DEBUG_MSG_CRITICAL_KHR:
+            return MessageType::Critical;
+        case EGL_DEBUG_MSG_ERROR_KHR:
+            return MessageType::Error;
+        case EGL_DEBUG_MSG_WARN_KHR:
+            return MessageType::Warn;
+        case EGL_DEBUG_MSG_INFO_KHR:
+            return MessageType::Info;
+        default:
+            return MessageType::InvalidEnum;
+    }
+}
+
+EGLenum ToEGLenum(MessageType from)
+{
+    switch (from)
+    {
+        case MessageType::Critical:
+            return EGL_DEBUG_MSG_CRITICAL_KHR;
+        case MessageType::Error:
+            return EGL_DEBUG_MSG_ERROR_KHR;
+        case MessageType::Warn:
+            return EGL_DEBUG_MSG_WARN_KHR;
+        case MessageType::Info:
+            return EGL_DEBUG_MSG_INFO_KHR;
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+}
+
+template <>
+ObjectType FromEGLenum<ObjectType>(EGLenum from)
+{
+    switch (from)
+    {
+        case EGL_OBJECT_THREAD_KHR:
+            return ObjectType::Thread;
+        case EGL_OBJECT_DISPLAY_KHR:
+            return ObjectType::Display;
+        case EGL_OBJECT_CONTEXT_KHR:
+            return ObjectType::Context;
+        case EGL_OBJECT_SURFACE_KHR:
+            return ObjectType::Surface;
+        case EGL_OBJECT_IMAGE_KHR:
+            return ObjectType::Image;
+        case EGL_OBJECT_SYNC_KHR:
+            return ObjectType::Sync;
+        case EGL_OBJECT_STREAM_KHR:
+            return ObjectType::Stream;
+        default:
+            return ObjectType::InvalidEnum;
+    }
+}
+
+EGLenum ToEGLenum(ObjectType from)
+{
+    switch (from)
+    {
+        case ObjectType::Thread:
+            return EGL_OBJECT_THREAD_KHR;
+        case ObjectType::Display:
+            return EGL_OBJECT_DISPLAY_KHR;
+        case ObjectType::Context:
+            return EGL_OBJECT_CONTEXT_KHR;
+        case ObjectType::Surface:
+            return EGL_OBJECT_SURFACE_KHR;
+        case ObjectType::Image:
+            return EGL_OBJECT_IMAGE_KHR;
+        case ObjectType::Sync:
+            return EGL_OBJECT_SYNC_KHR;
+        case ObjectType::Stream:
+            return EGL_OBJECT_STREAM_KHR;
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+}
+
+template <>
 TextureFormat FromEGLenum<TextureFormat>(EGLenum from)
 {
     switch (from)
diff --git a/src/common/PackedEGLEnums_autogen.h b/src/common/PackedEGLEnums_autogen.h
index 16856aa..fd3d719 100644
--- a/src/common/PackedEGLEnums_autogen.h
+++ b/src/common/PackedEGLEnums_autogen.h
@@ -24,6 +24,39 @@
 template <typename Enum>
 Enum FromEGLenum(EGLenum from);
 
+enum class MessageType : uint8_t
+{
+    Critical = 0,
+    Error    = 1,
+    Warn     = 2,
+    Info     = 3,
+
+    InvalidEnum = 4,
+    EnumCount   = 4,
+};
+
+template <>
+MessageType FromEGLenum<MessageType>(EGLenum from);
+EGLenum ToEGLenum(MessageType from);
+
+enum class ObjectType : uint8_t
+{
+    Thread  = 0,
+    Display = 1,
+    Context = 2,
+    Surface = 3,
+    Image   = 4,
+    Sync    = 5,
+    Stream  = 6,
+
+    InvalidEnum = 7,
+    EnumCount   = 7,
+};
+
+template <>
+ObjectType FromEGLenum<ObjectType>(EGLenum from);
+EGLenum ToEGLenum(ObjectType from);
+
 enum class TextureFormat : uint8_t
 {
     NoTexture = 0,
diff --git a/src/common/PackedEnums.cpp b/src/common/PackedEnums.cpp
index 4843c4e..517c443 100644
--- a/src/common/PackedEnums.cpp
+++ b/src/common/PackedEnums.cpp
@@ -149,6 +149,41 @@
 
 }  // namespace gl
 
+namespace egl
+{
+MessageType ErrorCodeToMessageType(EGLint errorCode)
+{
+    switch (errorCode)
+    {
+        case EGL_BAD_ALLOC:
+        case EGL_CONTEXT_LOST:
+        case EGL_NOT_INITIALIZED:
+            return MessageType::Critical;
+
+        case EGL_BAD_ACCESS:
+        case EGL_BAD_ATTRIBUTE:
+        case EGL_BAD_CONFIG:
+        case EGL_BAD_CONTEXT:
+        case EGL_BAD_CURRENT_SURFACE:
+        case EGL_BAD_DISPLAY:
+        case EGL_BAD_MATCH:
+        case EGL_BAD_NATIVE_PIXMAP:
+        case EGL_BAD_NATIVE_WINDOW:
+        case EGL_BAD_PARAMETER:
+        case EGL_BAD_SURFACE:
+        case EGL_BAD_STREAM_KHR:
+        case EGL_BAD_STATE_KHR:
+        case EGL_BAD_DEVICE_EXT:
+            return MessageType::Error;
+
+        case EGL_SUCCESS:
+        default:
+            UNREACHABLE();
+            return MessageType::InvalidEnum;
+    }
+}
+}  // namespace egl
+
 namespace egl_gl
 {
 
diff --git a/src/common/PackedEnums.h b/src/common/PackedEnums.h
index d649cf4..c53d3e5 100644
--- a/src/common/PackedEnums.h
+++ b/src/common/PackedEnums.h
@@ -189,6 +189,11 @@
 
 }  // namespace gl
 
+namespace egl
+{
+MessageType ErrorCodeToMessageType(EGLint errorCode);
+}  // namespace egl
+
 namespace egl_gl
 {
 gl::TextureTarget EGLCubeMapTargetToCubeMapTarget(EGLenum eglTarget);
diff --git a/src/common/packed_egl_enums.json b/src/common/packed_egl_enums.json
index dc946b6..04d67d4 100644
--- a/src/common/packed_egl_enums.json
+++ b/src/common/packed_egl_enums.json
@@ -4,5 +4,22 @@
         "NoTexture": "EGL_NO_TEXTURE",
         "RGB": "EGL_TEXTURE_RGB",
         "RGBA": "EGL_TEXTURE_RGBA"
+    },
+    "ObjectType":
+    {
+        "Thread": "EGL_OBJECT_THREAD_KHR",
+        "Display": "EGL_OBJECT_DISPLAY_KHR",
+        "Context": "EGL_OBJECT_CONTEXT_KHR",
+        "Surface": "EGL_OBJECT_SURFACE_KHR",
+        "Image": "EGL_OBJECT_IMAGE_KHR",
+        "Sync": "EGL_OBJECT_SYNC_KHR",
+        "Stream": "EGL_OBJECT_STREAM_KHR"
+    },
+    "MessageType":
+    {
+        "Critical": "EGL_DEBUG_MSG_CRITICAL_KHR",
+        "Error": "EGL_DEBUG_MSG_ERROR_KHR",
+        "Warn": "EGL_DEBUG_MSG_WARN_KHR",
+        "Info": "EGL_DEBUG_MSG_INFO_KHR"
     }
 }
diff --git a/src/libANGLE/Caps.cpp b/src/libANGLE/Caps.cpp
index 293693e..016d712 100644
--- a/src/libANGLE/Caps.cpp
+++ b/src/libANGLE/Caps.cpp
@@ -1387,7 +1387,8 @@
       x11Visual(false),
       experimentalPresentPath(false),
       clientGetAllProcAddresses(false),
-      explicitContext(false)
+      explicitContext(false),
+      debug(false)
 {
 }
 
@@ -1413,6 +1414,7 @@
     InsertExtensionString("EGL_ANGLE_experimental_present_path",   experimentalPresentPath,   &extensionStrings);
     InsertExtensionString("EGL_KHR_client_get_all_proc_addresses", clientGetAllProcAddresses, &extensionStrings);
     InsertExtensionString("EGL_ANGLE_explicit_context",            explicitContext,           &extensionStrings);
+    InsertExtensionString("EGL_KHR_debug",                         debug,                     &extensionStrings);
     // clang-format on
 
     return extensionStrings;
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index f783364..0589d00 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -826,6 +826,9 @@
 
     // EGL_ANGLE_explicit_context
     bool explicitContext;
+
+    // EGL_KHR_debug
+    bool debug;
 };
 
 }  // namespace egl
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 0ec0bfc..e62be2a 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -280,6 +280,7 @@
       mDisplayTextureShareGroup(shareTextures != nullptr),
       mSavedArgsType(nullptr),
       mImplementation(implFactory->createContext(mState)),
+      mLabel(nullptr),
       mCompiler(),
       mGLState(GetDebug(attribs),
                GetBindGeneratesResource(attribs),
@@ -518,6 +519,16 @@
 {
 }
 
+void Context::setLabel(EGLLabelKHR label)
+{
+    mLabel = label;
+}
+
+EGLLabelKHR Context::getLabel() const
+{
+    return mLabel;
+}
+
 egl::Error Context::makeCurrent(egl::Display *display, egl::Surface *surface)
 {
     mCurrentDisplay = display;
@@ -904,7 +915,7 @@
     return mState.mPipelines->getProgramPipeline(handle);
 }
 
-LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const
+gl::LabeledObject *Context::getLabeledObject(GLenum identifier, GLuint name) const
 {
     switch (identifier)
     {
@@ -934,14 +945,14 @@
     }
 }
 
-LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const
+gl::LabeledObject *Context::getLabeledObjectFromPtr(const void *ptr) const
 {
     return getSync(reinterpret_cast<GLsync>(const_cast<void *>(ptr)));
 }
 
 void Context::objectLabel(GLenum identifier, GLuint name, GLsizei length, const GLchar *label)
 {
-    LabeledObject *object = getLabeledObject(identifier, name);
+    gl::LabeledObject *object = getLabeledObject(identifier, name);
     ASSERT(object != nullptr);
 
     std::string labelName = GetObjectLabelFromPointer(length, label);
@@ -954,7 +965,7 @@
 
 void Context::objectPtrLabel(const void *ptr, GLsizei length, const GLchar *label)
 {
-    LabeledObject *object = getLabeledObjectFromPtr(ptr);
+    gl::LabeledObject *object = getLabeledObjectFromPtr(ptr);
     ASSERT(object != nullptr);
 
     std::string labelName = GetObjectLabelFromPointer(length, label);
@@ -967,7 +978,7 @@
                              GLsizei *length,
                              GLchar *label) const
 {
-    LabeledObject *object = getLabeledObject(identifier, name);
+    gl::LabeledObject *object = getLabeledObject(identifier, name);
     ASSERT(object != nullptr);
 
     const std::string &objectLabel = object->getLabel();
@@ -979,7 +990,7 @@
                                 GLsizei *length,
                                 GLchar *label) const
 {
-    LabeledObject *object = getLabeledObjectFromPtr(ptr);
+    gl::LabeledObject *object = getLabeledObjectFromPtr(ptr);
     ASSERT(object != nullptr);
 
     const std::string &objectLabel = object->getLabel();
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index bcd4361..2d14caf 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -63,7 +63,7 @@
 class VertexArray;
 struct VertexAttribute;
 
-class Context final : angle::NonCopyable
+class Context final : public egl::LabeledObject, angle::NonCopyable
 {
   public:
     Context(rx::EGLImplFactory *implFactory,
@@ -78,6 +78,9 @@
     egl::Error onDestroy(const egl::Display *display);
     ~Context();
 
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
     egl::Error makeCurrent(egl::Display *display, egl::Surface *surface);
     egl::Error releaseSurface(const egl::Display *display);
 
@@ -1502,8 +1505,8 @@
     void updateCaps();
     void initWorkarounds();
 
-    LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
-    LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
+    gl::LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
+    gl::LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
 
     ContextState mState;
     bool mSkipValidation;
@@ -1519,6 +1522,8 @@
 
     std::unique_ptr<rx::ContextImpl> mImplementation;
 
+    EGLLabelKHR mLabel;
+
     // Caps to use for validation
     Caps mCaps;
     TextureCapsMap mTextureCaps;
diff --git a/src/libANGLE/Debug.cpp b/src/libANGLE/Debug.cpp
index c742fe1..4619235 100644
--- a/src/libANGLE/Debug.cpp
+++ b/src/libANGLE/Debug.cpp
@@ -325,3 +325,64 @@
     mGroups.push_back(std::move(g));
 }
 }  // namespace gl
+
+namespace egl
+{
+
+namespace
+{
+angle::PackedEnumBitSet<MessageType> GetDefaultMessageTypeBits()
+{
+    angle::PackedEnumBitSet<MessageType> result;
+    result.set(MessageType::Critical);
+    result.set(MessageType::Error);
+    return result;
+}
+}  // anonymous namespace
+
+Debug::Debug() : mCallback(nullptr), mEnabledMessageTypes(GetDefaultMessageTypeBits())
+{
+}
+
+void Debug::setCallback(EGLDEBUGPROCKHR callback, const AttributeMap &attribs)
+{
+    mCallback = callback;
+
+    const angle::PackedEnumBitSet<MessageType> defaultMessageTypes = GetDefaultMessageTypeBits();
+    if (mCallback != nullptr)
+    {
+        for (MessageType messageType : angle::AllEnums<MessageType>())
+        {
+            mEnabledMessageTypes[messageType] =
+                (attribs.getAsInt(egl::ToEGLenum(messageType), defaultMessageTypes[messageType]) ==
+                 EGL_TRUE);
+        }
+    }
+}
+
+EGLDEBUGPROCKHR Debug::getCallback() const
+{
+    return mCallback;
+}
+
+bool Debug::isMessageTypeEnabled(MessageType type) const
+{
+    return mEnabledMessageTypes[type];
+}
+
+void Debug::insertMessage(EGLenum error,
+                          const char *command,
+                          MessageType messageType,
+                          EGLLabelKHR threadLabel,
+                          EGLLabelKHR objectLabel,
+                          const std::string &message) const
+{
+    // TODO(geofflang): Lock before checking the callback. http://anglebug.com/2464
+    if (mCallback && isMessageTypeEnabled(messageType))
+    {
+        mCallback(error, command, egl::ToEGLenum(messageType), threadLabel, objectLabel,
+                  message.c_str());
+    }
+}
+
+}  // namespace egl
diff --git a/src/libANGLE/Debug.h b/src/libANGLE/Debug.h
index 261ca54..544512a 100644
--- a/src/libANGLE/Debug.h
+++ b/src/libANGLE/Debug.h
@@ -10,7 +10,9 @@
 #define LIBANGLE_DEBUG_H_
 
 #include "angle_gl.h"
+#include "common/PackedEnums.h"
 #include "common/angleutils.h"
+#include "libANGLE/AttributeMap.h"
 
 #include <deque>
 #include <string>
@@ -126,4 +128,35 @@
 };
 }  // namespace gl
 
+namespace egl
+{
+class LabeledObject
+{
+  public:
+    virtual ~LabeledObject() {}
+    virtual void setLabel(EGLLabelKHR label) = 0;
+    virtual EGLLabelKHR getLabel() const     = 0;
+};
+
+class Debug : angle::NonCopyable
+{
+  public:
+    Debug();
+
+    void setCallback(EGLDEBUGPROCKHR callback, const AttributeMap &attribs);
+    EGLDEBUGPROCKHR getCallback() const;
+    bool isMessageTypeEnabled(MessageType type) const;
+
+    void insertMessage(EGLenum error,
+                       const char *command,
+                       MessageType messageType,
+                       EGLLabelKHR threadLabel,
+                       EGLLabelKHR objectLabel,
+                       const std::string &message) const;
+
+  private:
+    EGLDEBUGPROCKHR mCallback;
+    angle::PackedEnumBitSet<MessageType> mEnabledMessageTypes;
+};
+}  // namespace egl
 #endif  // LIBANGLE_DEBUG_H_
diff --git a/src/libANGLE/Device.cpp b/src/libANGLE/Device.cpp
index fe37558..51d4524 100644
--- a/src/libANGLE/Device.cpp
+++ b/src/libANGLE/Device.cpp
@@ -70,14 +70,14 @@
     return NoError();
 }
 
-bool Device::IsValidDevice(Device *device)
+bool Device::IsValidDevice(const Device *device)
 {
     const DeviceSet *deviceSet = GetDeviceSet();
-    return deviceSet->find(device) != deviceSet->end();
+    return deviceSet->find(const_cast<Device *>(device)) != deviceSet->end();
 }
 
 Device::Device(Display *owningDisplay, rx::DeviceImpl *impl)
-    : mOwningDisplay(owningDisplay), mImplementation(impl)
+    : mLabel(nullptr), mOwningDisplay(owningDisplay), mImplementation(impl)
 {
     ASSERT(GetDeviceSet()->find(this) == GetDeviceSet()->end());
     GetDeviceSet()->insert(this);
@@ -90,6 +90,16 @@
     GetDeviceSet()->erase(this);
 }
 
+void Device::setLabel(EGLLabelKHR label)
+{
+    mLabel = label;
+}
+
+EGLLabelKHR Device::getLabel() const
+{
+    return mLabel;
+}
+
 Error Device::getDevice(EGLAttrib *value)
 {
     void *nativeDevice = nullptr;
diff --git a/src/libANGLE/Device.h b/src/libANGLE/Device.h
index ce6d4ee..9625fe6 100644
--- a/src/libANGLE/Device.h
+++ b/src/libANGLE/Device.h
@@ -23,12 +23,15 @@
 
 namespace egl
 {
-class Device final : angle::NonCopyable
+class Device final : public LabeledObject, angle::NonCopyable
 {
   public:
     Device(Display *owningDisplay, rx::DeviceImpl *impl);
     virtual ~Device();
 
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
     Error getDevice(EGLAttrib *value);
     Display *getOwningDisplay() { return mOwningDisplay; };
     EGLint getType();
@@ -39,11 +42,13 @@
     rx::DeviceImpl *getImplementation() { return mImplementation.get(); }
 
     static egl::Error CreateDevice(EGLint deviceType, void *nativeDevice, Device **outDevice);
-    static bool IsValidDevice(Device *device);
+    static bool IsValidDevice(const Device *device);
 
   private:
     void initDeviceExtensions();
 
+    EGLLabelKHR mLabel;
+
     Display *mOwningDisplay;
     std::unique_ptr<rx::DeviceImpl> mImplementation;
 
diff --git a/src/libANGLE/Display.cpp b/src/libANGLE/Display.cpp
index f936dd2..1c83a45 100644
--- a/src/libANGLE/Display.cpp
+++ b/src/libANGLE/Display.cpp
@@ -273,7 +273,7 @@
 
 }  // anonymous namespace
 
-DisplayState::DisplayState()
+DisplayState::DisplayState() : label(nullptr)
 {
 }
 
@@ -425,6 +425,16 @@
     SafeDelete(mImplementation);
 }
 
+void Display::setLabel(EGLLabelKHR label)
+{
+    mState.label = label;
+}
+
+EGLLabelKHR Display::getLabel() const
+{
+    return mState.label;
+}
+
 void Display::setAttributes(rx::DisplayImpl *impl, const AttributeMap &attribMap)
 {
     ASSERT(!mInitialized);
@@ -1020,6 +1030,7 @@
 
     extensions.clientGetAllProcAddresses = true;
     extensions.explicitContext           = true;
+    extensions.debug                     = true;
 
     return extensions;
 }
diff --git a/src/libANGLE/Display.h b/src/libANGLE/Display.h
index ed8770a..9d56478 100644
--- a/src/libANGLE/Display.h
+++ b/src/libANGLE/Display.h
@@ -17,6 +17,7 @@
 #include "libANGLE/AttributeMap.h"
 #include "libANGLE/Caps.h"
 #include "libANGLE/Config.h"
+#include "libANGLE/Debug.h"
 #include "libANGLE/Error.h"
 #include "libANGLE/LoggingAnnotator.h"
 #include "libANGLE/MemoryProgramCache.h"
@@ -48,17 +49,21 @@
     DisplayState();
     ~DisplayState();
 
+    EGLLabelKHR label;
     SurfaceSet surfaceSet;
 };
 
 // Constant coded here as a sanity limit.
 constexpr EGLAttrib kProgramCacheSizeAbsoluteMax = 0x4000000;
 
-class Display final : angle::NonCopyable
+class Display final : public LabeledObject, angle::NonCopyable
 {
   public:
     ~Display();
 
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
     Error initialize();
     Error terminate();
 
diff --git a/src/libANGLE/Image.cpp b/src/libANGLE/Image.cpp
index 4adbeff..34e8d7a 100644
--- a/src/libANGLE/Image.cpp
+++ b/src/libANGLE/Image.cpp
@@ -118,7 +118,7 @@
 }
 
 ImageState::ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs)
-    : imageIndex(GetImageIndex(target, attribs)), source(buffer), targets()
+    : label(nullptr), imageIndex(GetImageIndex(target, attribs)), source(buffer), targets()
 {
 }
 
@@ -161,6 +161,16 @@
     SafeDelete(mImplementation);
 }
 
+void Image::setLabel(EGLLabelKHR label)
+{
+    mState.label = label;
+}
+
+EGLLabelKHR Image::getLabel() const
+{
+    return mState.label;
+}
+
 void Image::addTargetSibling(ImageSibling *sibling)
 {
     mState.targets.insert(sibling);
diff --git a/src/libANGLE/Image.h b/src/libANGLE/Image.h
index 844aee8..86012fd 100644
--- a/src/libANGLE/Image.h
+++ b/src/libANGLE/Image.h
@@ -11,6 +11,7 @@
 
 #include "common/angleutils.h"
 #include "libANGLE/AttributeMap.h"
+#include "libANGLE/Debug.h"
 #include "libANGLE/Error.h"
 #include "libANGLE/FramebufferAttachment.h"
 #include "libANGLE/RefCountObject.h"
@@ -66,12 +67,13 @@
     ImageState(EGLenum target, ImageSibling *buffer, const AttributeMap &attribs);
     ~ImageState();
 
+    EGLLabelKHR label;
     gl::ImageIndex imageIndex;
     gl::BindingPointer<ImageSibling> source;
     std::set<ImageSibling *> targets;
 };
 
-class Image final : public gl::RefCountObject
+class Image final : public gl::RefCountObject, public LabeledObject
 {
   public:
     Image(rx::EGLImplFactory *factory,
@@ -82,6 +84,9 @@
     gl::Error onDestroy(const gl::Context *context) override;
     ~Image() override;
 
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
     gl::Format getFormat() const;
     size_t getWidth() const;
     size_t getHeight() const;
diff --git a/src/libANGLE/Stream.cpp b/src/libANGLE/Stream.cpp
index a2db4d5..320e06f 100644
--- a/src/libANGLE/Stream.cpp
+++ b/src/libANGLE/Stream.cpp
@@ -25,7 +25,8 @@
 {
 
 Stream::Stream(Display *display, const AttributeMap &attribs)
-    : mDisplay(display),
+    : mLabel(nullptr),
+      mDisplay(display),
       mProducerImplementation(nullptr),
       mState(EGL_STREAM_STATE_CREATED_KHR),
       mProducerFrame(0),
@@ -55,6 +56,16 @@
     }
 }
 
+void Stream::setLabel(EGLLabelKHR label)
+{
+    mLabel = label;
+}
+
+EGLLabelKHR Stream::getLabel() const
+{
+    return mLabel;
+}
+
 void Stream::setConsumerLatency(EGLint latency)
 {
     mConsumerLatency = latency;
diff --git a/src/libANGLE/Stream.h b/src/libANGLE/Stream.h
index 2319355..7fac4f8 100644
--- a/src/libANGLE/Stream.h
+++ b/src/libANGLE/Stream.h
@@ -17,6 +17,7 @@
 
 #include "common/angleutils.h"
 #include "libANGLE/AttributeMap.h"
+#include "libANGLE/Debug.h"
 
 namespace rx
 {
@@ -35,12 +36,15 @@
 class Error;
 class Thread;
 
-class Stream final : angle::NonCopyable
+class Stream final : public LabeledObject, angle::NonCopyable
 {
   public:
     Stream(Display *display, const AttributeMap &attribs);
     ~Stream();
 
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
     enum class ConsumerType
     {
         NoConsumer,
@@ -100,6 +104,8 @@
     Error postD3D11Texture(void *texture, const AttributeMap &attributes);
 
   private:
+    EGLLabelKHR mLabel;
+
     // Associated display
     Display *mDisplay;
 
diff --git a/src/libANGLE/Surface.cpp b/src/libANGLE/Surface.cpp
index bf4861f..3822d45 100644
--- a/src/libANGLE/Surface.cpp
+++ b/src/libANGLE/Surface.cpp
@@ -25,7 +25,7 @@
 {
 
 SurfaceState::SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn)
-    : config(configIn), attributes(attributesIn)
+    : label(nullptr), config(configIn), attributes(attributesIn)
 {
 }
 
@@ -212,6 +212,16 @@
     return NoError();
 }
 
+void Surface::setLabel(EGLLabelKHR label)
+{
+    mState.label = label;
+}
+
+EGLLabelKHR Surface::getLabel() const
+{
+    return mState.label;
+}
+
 EGLint Surface::getType() const
 {
     return mType;
diff --git a/src/libANGLE/Surface.h b/src/libANGLE/Surface.h
index 3107aa2..ea09341 100644
--- a/src/libANGLE/Surface.h
+++ b/src/libANGLE/Surface.h
@@ -16,6 +16,7 @@
 #include "common/PackedEnums.h"
 #include "common/angleutils.h"
 #include "libANGLE/AttributeMap.h"
+#include "libANGLE/Debug.h"
 #include "libANGLE/Error.h"
 #include "libANGLE/FramebufferAttachment.h"
 #include "libANGLE/RefCountObject.h"
@@ -43,15 +44,19 @@
 {
     SurfaceState(const egl::Config *configIn, const AttributeMap &attributesIn);
 
+    EGLLabelKHR label;
     const egl::Config *config;
     AttributeMap attributes;
 };
 
-class Surface : public gl::FramebufferAttachmentObject
+class Surface : public LabeledObject, public gl::FramebufferAttachmentObject
 {
   public:
     rx::SurfaceImpl *getImplementation() const { return mImplementation; }
 
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
     EGLint getType() const;
 
     Error initialize(const Display *display);
diff --git a/src/libANGLE/Thread.cpp b/src/libANGLE/Thread.cpp
index d346db1..a7c5045 100644
--- a/src/libANGLE/Thread.cpp
+++ b/src/libANGLE/Thread.cpp
@@ -9,20 +9,48 @@
 #include "libANGLE/Thread.h"
 
 #include "libANGLE/Context.h"
+#include "libANGLE/Debug.h"
 #include "libANGLE/Error.h"
 
 namespace egl
 {
+
 Thread::Thread()
-    : mError(EGL_SUCCESS),
+    : mLabel(nullptr),
+      mError(EGL_SUCCESS),
       mAPI(EGL_OPENGL_ES_API),
       mContext(static_cast<gl::Context *>(EGL_NO_CONTEXT))
 {
 }
 
-void Thread::setError(const Error &error)
+void Thread::setLabel(EGLLabelKHR label)
 {
+    mLabel = label;
+}
+
+EGLLabelKHR Thread::getLabel() const
+{
+    return mLabel;
+}
+
+void Thread::setSuccess()
+{
+    mError = EGL_SUCCESS;
+}
+
+void Thread::setError(const Error &error,
+                      const Debug *debug,
+                      const char *command,
+                      const LabeledObject *object)
+{
+    ASSERT(debug != nullptr);
+
     mError = error.getCode();
+    if (error.isError() && !error.getMessage().empty())
+    {
+        debug->insertMessage(error.getCode(), command, ErrorCodeToMessageType(error.getCode()),
+                             getLabel(), object ? object->getLabel() : nullptr, error.getMessage());
+    }
 }
 
 EGLint Thread::getError() const
diff --git a/src/libANGLE/Thread.h b/src/libANGLE/Thread.h
index 6406dad..8f37895 100644
--- a/src/libANGLE/Thread.h
+++ b/src/libANGLE/Thread.h
@@ -11,6 +11,8 @@
 
 #include <EGL/egl.h>
 
+#include "libANGLE/Debug.h"
+
 namespace gl
 {
 class Context;
@@ -19,15 +21,23 @@
 namespace egl
 {
 class Error;
+class Debug;
 class Display;
 class Surface;
 
-class Thread
+class Thread : public LabeledObject
 {
   public:
     Thread();
 
-    void setError(const Error &error);
+    void setLabel(EGLLabelKHR label) override;
+    EGLLabelKHR getLabel() const override;
+
+    void setSuccess();
+    void setError(const Error &error,
+                  const Debug *debug,
+                  const char *command,
+                  const LabeledObject *object);
     EGLint getError() const;
 
     void setAPI(EGLenum api);
@@ -41,6 +51,7 @@
     Display *getCurrentDisplay() const;
 
   private:
+    EGLLabelKHR mLabel;
     EGLint mError;
     EGLenum mAPI;
     gl::Context *mContext;
diff --git a/src/libANGLE/validationEGL.cpp b/src/libANGLE/validationEGL.cpp
index 2e6e502..dcd4edb 100644
--- a/src/libANGLE/validationEGL.cpp
+++ b/src/libANGLE/validationEGL.cpp
@@ -17,6 +17,7 @@
 #include "libANGLE/Stream.h"
 #include "libANGLE/Surface.h"
 #include "libANGLE/Texture.h"
+#include "libANGLE/Thread.h"
 #include "libANGLE/formatutils.h"
 
 #include <EGL/eglext.h>
@@ -493,6 +494,100 @@
     return NoError();
 }
 
+Error ValidateStream(const Display *display, const Stream *stream)
+{
+    ANGLE_TRY(ValidateDisplay(display));
+
+    const DisplayExtensions &displayExtensions = display->getExtensions();
+    if (!displayExtensions.stream)
+    {
+        return EglBadAccess() << "Stream extension not active";
+    }
+
+    if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
+    {
+        return EglBadStream() << "Invalid stream";
+    }
+
+    return NoError();
+}
+
+Error ValidateLabeledObject(Thread *thread,
+                            const Display *display,
+                            ObjectType objectType,
+                            EGLObjectKHR object,
+                            LabeledObject **outLabeledObject)
+{
+    switch (objectType)
+    {
+        case ObjectType::Context:
+        {
+            gl::Context *context = static_cast<gl::Context *>(object);
+            ANGLE_TRY(ValidateContext(display, context));
+            *outLabeledObject = context;
+            break;
+        }
+
+        case ObjectType::Display:
+        {
+            ANGLE_TRY(ValidateDisplay(display));
+            if (display != object)
+            {
+                return EglBadParameter() << "when object type is EGL_OBJECT_DISPLAY_KHR, the "
+                                            "object must be the same as the display.";
+            }
+
+            *outLabeledObject = static_cast<Display *>(object);
+            break;
+        }
+
+        case ObjectType::Image:
+        {
+            Image *image = static_cast<Image *>(object);
+            ANGLE_TRY(ValidateImage(display, image));
+            *outLabeledObject = image;
+            break;
+        }
+
+        case ObjectType::Stream:
+        {
+            Stream *stream = static_cast<Stream *>(object);
+            ANGLE_TRY(ValidateStream(display, stream));
+            *outLabeledObject = stream;
+            break;
+        }
+
+        case ObjectType::Surface:
+        {
+            Surface *surface = static_cast<Surface *>(object);
+            ANGLE_TRY(ValidateSurface(display, surface));
+            *outLabeledObject = surface;
+            break;
+        }
+
+        case ObjectType::Sync:
+        {
+            ANGLE_TRY(ValidateDisplay(display));
+            // TODO(geofflang): Implement sync objects. http://anglebug.com/2466
+            UNIMPLEMENTED();
+            return EglBadDisplay() << "Sync objects are unimplemented.";
+
+            break;
+        }
+
+        case ObjectType::Thread:
+        {
+            *outLabeledObject = thread;
+            break;
+        }
+
+        default:
+            return EglBadParameter() << "unknown object type.";
+    }
+
+    return NoError();
+}
+
 }  // namespace
 
 Error ValidateDisplay(const Display *display)
@@ -568,24 +663,101 @@
     return NoError();
 }
 
-Error ValidateStream(const Display *display, const Stream *stream)
+Error ValidateDevice(const Device *device)
 {
-    ANGLE_TRY(ValidateDisplay(display));
-
-    const DisplayExtensions &displayExtensions = display->getExtensions();
-    if (!displayExtensions.stream)
+    if (device == EGL_NO_DEVICE_EXT)
     {
-        return EglBadAccess() << "Stream extension not active";
+        return EglBadAccess() << "device is EGL_NO_DEVICE.";
     }
 
-    if (stream == EGL_NO_STREAM_KHR || !display->isValidStream(stream))
+    if (!Device::IsValidDevice(device))
     {
-        return EglBadStream() << "Invalid stream";
+        return EglBadAccess() << "device is not valid.";
     }
 
     return NoError();
 }
 
+const Thread *GetThreadIfValid(const Thread *thread)
+{
+    // Threads should always be valid
+    return thread;
+}
+
+const Display *GetDisplayIfValid(const Display *display)
+{
+    if (ValidateDisplay(display).isError())
+    {
+        return nullptr;
+    }
+
+    return display;
+}
+
+const Surface *GetSurfaceIfValid(const Display *display, const Surface *surface)
+{
+    if (ValidateSurface(display, surface).isError())
+    {
+        return nullptr;
+    }
+
+    return surface;
+}
+
+const Image *GetImageIfValid(const Display *display, const Image *image)
+{
+    if (ValidateImage(display, image).isError())
+    {
+        return nullptr;
+    }
+
+    return image;
+}
+
+const Stream *GetStreamIfValid(const Display *display, const Stream *stream)
+{
+    if (ValidateStream(display, stream).isError())
+    {
+        return nullptr;
+    }
+
+    return stream;
+}
+
+const gl::Context *GetContextIfValid(const Display *display, const gl::Context *context)
+{
+    if (ValidateContext(display, context).isError())
+    {
+        return nullptr;
+    }
+
+    return context;
+}
+
+const Device *GetDeviceIfValid(const Device *device)
+{
+    if (ValidateDevice(device).isError())
+    {
+        return nullptr;
+    }
+
+    return device;
+}
+
+LabeledObject *GetLabeledObjectIfValid(Thread *thread,
+                                       const Display *display,
+                                       ObjectType objectType,
+                                       EGLObjectKHR object)
+{
+    LabeledObject *labeledObject = nullptr;
+    if (ValidateLabeledObject(thread, display, objectType, object, &labeledObject).isError())
+    {
+        return nullptr;
+    }
+
+    return labeledObject;
+}
+
 Error ValidateCreateContext(Display *display,
                             Config *configuration,
                             gl::Context *shareContext,
@@ -2715,4 +2887,73 @@
     return NoError();
 }
 
+Error ValidateDebugMessageControlKHR(EGLDEBUGPROCKHR callback, const AttributeMap &attribs)
+{
+    const ClientExtensions &clientExtensions = Display::GetClientExtensions();
+    if (!clientExtensions.debug)
+    {
+        return EglBadAccess() << "EGL_KHR_debug extension is not available.";
+    }
+
+    for (const auto &attrib : attribs)
+    {
+        switch (attrib.first)
+        {
+            case EGL_DEBUG_MSG_CRITICAL_KHR:
+            case EGL_DEBUG_MSG_ERROR_KHR:
+            case EGL_DEBUG_MSG_WARN_KHR:
+            case EGL_DEBUG_MSG_INFO_KHR:
+                if (attrib.second != EGL_TRUE && attrib.second != EGL_FALSE)
+                {
+                    return EglBadAttribute() << "message controls must be EGL_TRUE or EGL_FALSE.";
+                }
+                break;
+        }
+    }
+
+    return NoError();
+}
+
+Error ValidateQueryDebugKHR(EGLint attribute, EGLAttrib *value)
+{
+    const ClientExtensions &clientExtensions = Display::GetClientExtensions();
+    if (!clientExtensions.debug)
+    {
+        return EglBadAccess() << "EGL_KHR_debug extension is not available.";
+    }
+
+    switch (attribute)
+    {
+        case EGL_DEBUG_MSG_CRITICAL_KHR:
+        case EGL_DEBUG_MSG_ERROR_KHR:
+        case EGL_DEBUG_MSG_WARN_KHR:
+        case EGL_DEBUG_MSG_INFO_KHR:
+        case EGL_DEBUG_CALLBACK_KHR:
+            break;
+
+        default:
+            return EglBadAttribute() << "unknown attribute.";
+    }
+
+    return NoError();
+}
+
+Error ValidateLabelObjectKHR(Thread *thread,
+                             const Display *display,
+                             ObjectType objectType,
+                             EGLObjectKHR object,
+                             EGLLabelKHR label)
+{
+    const ClientExtensions &clientExtensions = Display::GetClientExtensions();
+    if (!clientExtensions.debug)
+    {
+        return EglBadAccess() << "EGL_KHR_debug extension is not available.";
+    }
+
+    LabeledObject *labeledObject = nullptr;
+    ANGLE_TRY(ValidateLabeledObject(thread, display, objectType, object, &labeledObject));
+
+    return NoError();
+}
+
 }  // namespace egl
diff --git a/src/libANGLE/validationEGL.h b/src/libANGLE/validationEGL.h
index a0a8169..cb07084 100644
--- a/src/libANGLE/validationEGL.h
+++ b/src/libANGLE/validationEGL.h
@@ -9,6 +9,7 @@
 #ifndef LIBANGLE_VALIDATIONEGL_H_
 #define LIBANGLE_VALIDATIONEGL_H_
 
+#include "common/PackedEnums.h"
 #include "libANGLE/Error.h"
 
 #include <EGL/egl.h>
@@ -30,6 +31,8 @@
 class Image;
 class Stream;
 class Surface;
+class Thread;
+class LabeledObject;
 
 // Object validation
 Error ValidateDisplay(const Display *display);
@@ -37,6 +40,20 @@
 Error ValidateConfig(const Display *display, const Config *config);
 Error ValidateContext(const Display *display, const gl::Context *context);
 Error ValidateImage(const Display *display, const Image *image);
+Error ValidateDevice(const Device *device);
+
+// Return the requested object only if it is valid (otherwise nullptr)
+const Thread *GetThreadIfValid(const Thread *thread);
+const Display *GetDisplayIfValid(const Display *display);
+const Surface *GetSurfaceIfValid(const Display *display, const Surface *surface);
+const Image *GetImageIfValid(const Display *display, const Image *image);
+const Stream *GetStreamIfValid(const Display *display, const Stream *stream);
+const gl::Context *GetContextIfValid(const Display *display, const gl::Context *context);
+const Device *GetDeviceIfValid(const Device *device);
+LabeledObject *GetLabeledObjectIfValid(Thread *thread,
+                                       const Display *display,
+                                       ObjectType objectType,
+                                       EGLObjectKHR object);
 
 // Entry point validation
 Error ValidateCreateContext(Display *display,
@@ -181,23 +198,34 @@
                            EGLint attribute,
                            EGLint *value);
 
+// EGL_KHR_debug
+Error ValidateDebugMessageControlKHR(EGLDEBUGPROCKHR callback, const AttributeMap &attribs);
+
+Error ValidateQueryDebugKHR(EGLint attribute, EGLAttrib *value);
+
+Error ValidateLabelObjectKHR(Thread *thread,
+                             const Display *display,
+                             ObjectType objectType,
+                             EGLObjectKHR object,
+                             EGLLabelKHR label);
+
 }  // namespace egl
 
-#define ANGLE_EGL_TRY(THREAD, EXPR)                   \
-    {                                                 \
-        auto ANGLE_LOCAL_VAR = (EXPR);                \
-        if (ANGLE_LOCAL_VAR.isError())                \
-            return THREAD->setError(ANGLE_LOCAL_VAR); \
+#define ANGLE_EGL_TRY(THREAD, EXPR, FUNCNAME, LABELOBJECT)                               \
+    {                                                                                    \
+        auto ANGLE_LOCAL_VAR = (EXPR);                                                   \
+        if (ANGLE_LOCAL_VAR.isError())                                                   \
+            return THREAD->setError(ANGLE_LOCAL_VAR, GetDebug(), FUNCNAME, LABELOBJECT); \
     }
 
-#define ANGLE_EGL_TRY_RETURN(THREAD, EXPR, RETVAL) \
-    {                                              \
-        auto ANGLE_LOCAL_VAR = (EXPR);             \
-        if (ANGLE_LOCAL_VAR.isError())             \
-        {                                          \
-            THREAD->setError(ANGLE_LOCAL_VAR);     \
-            return RETVAL;                         \
-        }                                          \
+#define ANGLE_EGL_TRY_RETURN(THREAD, EXPR, FUNCNAME, LABELOBJECT, RETVAL)         \
+    {                                                                             \
+        auto ANGLE_LOCAL_VAR = (EXPR);                                            \
+        if (ANGLE_LOCAL_VAR.isError())                                            \
+        {                                                                         \
+            THREAD->setError(ANGLE_LOCAL_VAR, GetDebug(), FUNCNAME, LABELOBJECT); \
+            return RETVAL;                                                        \
+        }                                                                         \
     }
 
 #endif  // LIBANGLE_VALIDATIONEGL_H_
diff --git a/src/libEGL/libEGL.cpp b/src/libEGL/libEGL.cpp
index 0498336..98822d0 100644
--- a/src/libEGL/libEGL.cpp
+++ b/src/libEGL/libEGL.cpp
@@ -493,4 +493,22 @@
     return egl::ProgramCacheResizeANGLE(dpy, limit, mode);
 }
 
+EGLint EGLAPIENTRY eglDebugMessageControlKHR(EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list)
+{
+    return egl::DebugMessageControlKHR(callback, attrib_list);
+}
+
+EGLBoolean EGLAPIENTRY eglQueryDebugKHR(EGLint attribute, EGLAttrib *value)
+{
+    return egl::QueryDebugKHR(attribute, value);
+}
+
+EGLint EGLAPIENTRY eglLabelObjectKHR(EGLDisplay dpy,
+                                     EGLenum objectType,
+                                     EGLObjectKHR object,
+                                     EGLLabelKHR label)
+{
+    return egl::LabelObjectKHR(dpy, objectType, object, label);
+}
+
 }  // extern "C"
diff --git a/src/libEGL/libEGL.def b/src/libEGL/libEGL.def
index d85cbab..1e5ee63 100644
--- a/src/libEGL/libEGL.def
+++ b/src/libEGL/libEGL.def
@@ -66,6 +66,9 @@
     eglCreatePlatformWindowSurfaceEXT           @72
     eglCreatePlatformPixmapSurfaceEXT           @73
     eglPresentationTimeANDROID                  @74
+    eglDebugMessageControlKHR                   @75
+    eglQueryDebugKHR                            @76
+    eglLabelObjectKHR                           @77
 
     ; 1.5 entry points
     eglCreateSync                               @38
diff --git a/src/libGLESv2/entry_points_egl.cpp b/src/libGLESv2/entry_points_egl.cpp
index aa445ed..938ec7f 100644
--- a/src/libGLESv2/entry_points_egl.cpp
+++ b/src/libGLESv2/entry_points_egl.cpp
@@ -50,7 +50,6 @@
     }
     *num_config = result_size;
 }
-
 }  // anonymous namespace
 
 // EGL 1.0
@@ -60,7 +59,7 @@
     Thread *thread = GetCurrentThread();
 
     EGLint error = thread->getError();
-    thread->setError(NoError());
+    thread->setSuccess();
     return error;
 }
 
@@ -80,14 +79,14 @@
     Display *display = static_cast<Display *>(dpy);
     if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
     {
-        thread->setError(EglBadDisplay());
+        thread->setError(EglBadDisplay(), GetDebug(), "eglInitialize", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
     Error error = display->initialize();
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglInitialize", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
@@ -96,7 +95,7 @@
     if (minor)
         *minor = 4;
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -108,7 +107,7 @@
     Display *display = static_cast<Display *>(dpy);
     if (dpy == EGL_NO_DISPLAY || !Display::isValidDisplay(display))
     {
-        thread->setError(EglBadDisplay());
+        thread->setError(EglBadDisplay(), GetDebug(), "eglTerminate", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
@@ -120,11 +119,11 @@
     Error error = display->terminate();
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglTerminate", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -139,7 +138,7 @@
         Error error = ValidateDisplay(display);
         if (error.isError())
         {
-            thread->setError(error);
+            thread->setError(error, GetDebug(), "eglQueryString", GetDisplayIfValid(display));
             return nullptr;
         }
     }
@@ -167,11 +166,12 @@
             result = "1.4 (ANGLE " ANGLE_VERSION_STRING ")";
             break;
         default:
-            thread->setError(EglBadParameter());
+            thread->setError(EglBadParameter(), GetDebug(), "eglQueryString",
+                             GetDisplayIfValid(display));
             return nullptr;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return result;
 }
 
@@ -191,13 +191,13 @@
     Error error = ValidateGetConfigs(display, config_size, num_config);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglGetConfigs", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
     ClipConfigs(display->getConfigs(AttributeMap()), configs, config_size, num_config);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -219,13 +219,13 @@
     Error error = ValidateChooseConfig(display, attribMap, config_size, num_config);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglChooseConfig", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
     ClipConfigs(display->getConfigs(attribMap), configs, config_size, num_config);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -246,13 +246,13 @@
     Error error = ValidateGetConfigAttrib(display, configuration, attribute);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglGetConfigAttrib", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
     QueryConfigAttrib(configuration, attribute, value);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -274,7 +274,7 @@
     Error error = ValidateCreateWindowSurface(display, configuration, win, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateWindowSurface", GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
@@ -282,7 +282,7 @@
     error                 = display->createWindowSurface(configuration, win, attributes, &surface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateWindowSurface", GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
@@ -306,7 +306,7 @@
     Error error = ValidateCreatePbufferSurface(display, configuration, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreatePbufferSurface", GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
@@ -314,7 +314,7 @@
     error                 = display->createPbufferSurface(configuration, attributes, &surface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreatePbufferSurface", GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
@@ -339,13 +339,13 @@
     Error error = ValidateConfig(display, configuration);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreatePixmapSurface", GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
     UNIMPLEMENTED();  // FIXME
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_NO_SURFACE;
 }
 
@@ -360,24 +360,27 @@
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglDestroySurface",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (surface == EGL_NO_SURFACE)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglDestroySurface",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
-    error = display->destroySurface(reinterpret_cast<Surface *>(surface));
+    error = display->destroySurface(eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglDestroySurface",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -398,13 +401,14 @@
     Error error = ValidateQuerySurface(display, eglSurface, attribute, value);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglQuerySurface",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     QuerySurfaceAttrib(eglSurface, attribute, value);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -428,7 +432,7 @@
     Error error = ValidateCreateContext(display, configuration, sharedGLContext, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateContext", GetDisplayIfValid(display));
         return EGL_NO_CONTEXT;
     }
 
@@ -436,11 +440,11 @@
     error = display->createContext(configuration, sharedGLContext, attributes, &context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateContext", GetDisplayIfValid(display));
         return EGL_NO_CONTEXT;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return static_cast<EGLContext>(context);
 }
 
@@ -455,13 +459,15 @@
     Error error = ValidateContext(display, context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglDestroyContext",
+                         GetContextIfValid(display, context));
         return EGL_FALSE;
     }
 
     if (ctx == EGL_NO_CONTEXT)
     {
-        thread->setError(EglBadContext());
+        thread->setError(EglBadContext(), GetDebug(), "eglDestroyContext",
+                         GetContextIfValid(display, context));
         return EGL_FALSE;
     }
 
@@ -473,11 +479,12 @@
     error = display->destroyContext(context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglDestroyContext",
+                         GetContextIfValid(display, context));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -495,7 +502,7 @@
     gl::Context *context = static_cast<gl::Context *>(ctx);
 
     ANGLE_EGL_TRY_RETURN(thread, ValidateMakeCurrent(display, drawSurface, readSurface, context),
-                         EGL_FALSE);
+                         "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
 
     Surface *previousDraw        = thread->getCurrentDrawSurface();
     Surface *previousRead        = thread->getCurrentReadSurface();
@@ -505,7 +512,7 @@
     if (previousDraw != drawSurface || previousRead != readSurface || previousContext != context)
     {
         ANGLE_EGL_TRY_RETURN(thread, display->makeCurrent(drawSurface, readSurface, context),
-                             EGL_FALSE);
+                             "eglMakeCurrent", GetContextIfValid(display, context), EGL_FALSE);
 
         thread->setCurrent(context);
 
@@ -513,11 +520,12 @@
         // destroyed surfaces to delete themselves.
         if (previousContext != nullptr && context != previousContext)
         {
-            ANGLE_EGL_TRY_RETURN(thread, previousContext->releaseSurface(display), EGL_FALSE);
+            ANGLE_EGL_TRY_RETURN(thread, previousContext->releaseSurface(display), "eglMakeCurrent",
+                                 GetContextIfValid(display, context), EGL_FALSE);
         }
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -528,17 +536,17 @@
 
     if (readdraw == EGL_READ)
     {
-        thread->setError(NoError());
+        thread->setSuccess();
         return thread->getCurrentReadSurface();
     }
     else if (readdraw == EGL_DRAW)
     {
-        thread->setError(NoError());
+        thread->setSuccess();
         return thread->getCurrentDrawSurface();
     }
     else
     {
-        thread->setError(EglBadParameter());
+        thread->setError(EglBadParameter(), GetDebug(), "eglGetCurrentSurface", nullptr);
         return EGL_NO_SURFACE;
     }
 }
@@ -548,7 +556,7 @@
     EVENT("()");
     Thread *thread = GetCurrentThread();
 
-    thread->setError(NoError());
+    thread->setSuccess();
     if (thread->getContext() != nullptr)
     {
         return thread->getContext()->getCurrentDisplay();
@@ -570,13 +578,13 @@
     Error error = ValidateQueryContext(display, context, attribute, value);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglQueryContext", GetContextIfValid(display, context));
         return EGL_FALSE;
     }
 
     QueryContextAttrib(context, attribute, value);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -590,7 +598,7 @@
     Error error = ValidateDisplay(display);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglWaitGL", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
@@ -599,11 +607,11 @@
     error = display->waitClient(thread->getContext());
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglWaitGL", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -617,23 +625,24 @@
     Error error = ValidateDisplay(display);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglWaitNative", GetThreadIfValid(thread));
         return EGL_FALSE;
     }
 
     if (engine != EGL_CORE_NATIVE_ENGINE)
     {
-        thread->setError(EglBadParameter() << "the 'engine' parameter has an unrecognized value");
+        thread->setError(EglBadParameter() << "the 'engine' parameter has an unrecognized value",
+                         GetDebug(), "eglWaitNative", GetDisplayIfValid(display));
     }
 
     error = display->waitNative(thread->getContext(), engine);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglWaitNative", GetThreadIfValid(thread));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -648,36 +657,41 @@
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSwapBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (display->isDeviceLost())
     {
-        thread->setError(EglContextLost());
+        thread->setError(EglContextLost(), GetDebug(), "eglSwapBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (surface == EGL_NO_SURFACE)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglSwapBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (!thread->getContext() || thread->getCurrentDrawSurface() != eglSurface)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglSwapBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     error = eglSurface->swap(thread->getContext());
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSwapBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -695,19 +709,21 @@
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCopyBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (display->testDeviceLost())
     {
-        thread->setError(EglContextLost());
+        thread->setError(EglContextLost(), GetDebug(), "eglCopyBuffers",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     UNIMPLEMENTED();  // FIXME
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return 0;
 }
 
@@ -724,31 +740,36 @@
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglBindTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (buffer != EGL_BACK_BUFFER)
     {
-        thread->setError(EglBadParameter());
+        thread->setError(EglBadParameter(), GetDebug(), "eglBindTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglBindTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (eglSurface->getBoundTexture())
     {
-        thread->setError(EglBadAccess());
+        thread->setError(EglBadAccess(), GetDebug(), "eglBindTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (eglSurface->getTextureFormat() == TextureFormat::NoTexture)
     {
-        thread->setError(EglBadMatch());
+        thread->setError(EglBadMatch(), GetDebug(), "eglBindTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
@@ -762,19 +783,21 @@
 
         if (textureObject->getImmutableFormat())
         {
-            thread->setError(EglBadMatch());
+            thread->setError(EglBadMatch(), GetDebug(), "eglBindTexImage",
+                             GetSurfaceIfValid(display, eglSurface));
             return EGL_FALSE;
         }
 
         error = eglSurface->bindTexImage(context, textureObject, buffer);
         if (error.isError())
         {
-            thread->setError(error);
+            thread->setError(error, GetDebug(), "eglBindTexImage",
+                             GetSurfaceIfValid(display, eglSurface));
             return EGL_FALSE;
         }
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -795,13 +818,14 @@
     Error error = ValidateSurfaceAttrib(display, eglSurface, attribute, value);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSurfaceAttrib",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     SetSurfaceAttrib(eglSurface, attribute, value);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -817,25 +841,29 @@
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglReleaseTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (buffer != EGL_BACK_BUFFER)
     {
-        thread->setError(EglBadParameter());
+        thread->setError(EglBadParameter(), GetDebug(), "eglReleaseTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (surface == EGL_NO_SURFACE || eglSurface->getType() == EGL_WINDOW_BIT)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglReleaseTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (eglSurface->getTextureFormat() == TextureFormat::NoTexture)
     {
-        thread->setError(EglBadMatch());
+        thread->setError(EglBadMatch(), GetDebug(), "eglReleaseTexImage",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
@@ -846,12 +874,13 @@
         error = eglSurface->releaseTexImage(thread->getContext(), buffer);
         if (error.isError())
         {
-            thread->setError(error);
+            thread->setError(error, GetDebug(), "eglReleaseTexImage",
+                             GetSurfaceIfValid(display, eglSurface));
             return EGL_FALSE;
         }
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -865,7 +894,7 @@
     Error error = ValidateDisplay(display);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSwapInterval", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
@@ -873,7 +902,8 @@
 
     if (draw_surface == nullptr)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglSwapInterval",
+                         GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
@@ -883,7 +913,7 @@
 
     draw_surface->setSwapInterval(clampedInterval);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -897,18 +927,18 @@
     {
         case EGL_OPENGL_API:
         case EGL_OPENVG_API:
-            thread->setError(EglBadParameter());
+            thread->setError(EglBadParameter(), GetDebug(), "eglBindAPI", GetThreadIfValid(thread));
             return EGL_FALSE;  // Not supported by this implementation
         case EGL_OPENGL_ES_API:
             break;
         default:
-            thread->setError(EglBadParameter());
+            thread->setError(EglBadParameter(), GetDebug(), "eglBindAPI", GetThreadIfValid(thread));
             return EGL_FALSE;
     }
 
     thread->setAPI(api);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -919,7 +949,7 @@
 
     EGLenum API = thread->getAPI();
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return API;
 }
 
@@ -943,7 +973,8 @@
         ValidateCreatePbufferFromClientBuffer(display, buftype, buffer, configuration, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreatePbufferFromClientBuffer",
+                         GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
@@ -952,7 +983,8 @@
                                                    &surface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreatePbufferFromClientBuffer",
+                         GetDisplayIfValid(display));
         return EGL_NO_SURFACE;
     }
 
@@ -966,7 +998,7 @@
 
     MakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -975,23 +1007,24 @@
     EVENT("()");
     Thread *thread = GetCurrentThread();
 
-    Display *display = thread->getCurrentDisplay();
+    Display *display     = thread->getCurrentDisplay();
+    gl::Context *context = thread->getContext();
 
     Error error = ValidateDisplay(display);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglWaitClient", GetContextIfValid(display, context));
         return EGL_FALSE;
     }
 
-    error = display->waitClient(thread->getContext());
+    error = display->waitClient(context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglWaitClient", GetContextIfValid(display, context));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -1003,7 +1036,7 @@
 
     gl::Context *context = thread->getContext();
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return static_cast<EGLContext>(context);
 }
 
@@ -1012,10 +1045,13 @@
 {
     EVENT("(EGLDisplay dpy = 0x%0.8p, EGLenum type = 0x%X, const EGLint* attrib_list = 0x%0.8p)",
           dpy, type, attrib_list);
-    Thread *thread = GetCurrentThread();
+    Thread *thread   = GetCurrentThread();
+    Display *display = static_cast<Display *>(dpy);
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglCreateSync unimplemented.");
+    // TODO(geofflang): Implement sync objects. http://anglebug.com/2466
+    thread->setError(EglBadDisplay() << "eglCreateSync unimplemented.", GetDebug(), "eglCreateSync",
+                     GetDisplayIfValid(display));
     return EGL_NO_SYNC;
 }
 
@@ -1025,7 +1061,9 @@
     Thread *thread = GetCurrentThread();
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglDestroySync unimplemented.");
+    // TODO(geofflang): Pass the EGL sync object to the setError function. http://anglebug.com/2466
+    thread->setError(EglBadDisplay() << "eglDestroySync unimplemented.", GetDebug(),
+                     "eglDestroySync", nullptr);
     return EGL_FALSE;
 }
 
@@ -1038,7 +1076,9 @@
     Thread *thread = GetCurrentThread();
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglClientWaitSync unimplemented.");
+    // TODO(geofflang): Pass the EGL sync object to the setError function. http://anglebug.com/2466
+    thread->setError(EglBadDisplay() << "eglClientWaitSync unimplemented.", GetDebug(),
+                     "eglClientWaitSync", nullptr);
     return 0;
 }
 
@@ -1054,7 +1094,9 @@
     Thread *thread = GetCurrentThread();
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglSyncAttrib unimplemented.");
+    // TODO(geofflang): Pass the EGL sync object to the setError function. http://anglebug.com/2466
+    thread->setError(EglBadDisplay() << "eglSyncAttrib unimplemented.", GetDebug(),
+                     "eglGetSyncAttrib", nullptr);
     return EGL_FALSE;
 }
 
@@ -1068,20 +1110,25 @@
         "(EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLenum target = 0x%X, "
         "EGLClientBuffer buffer = 0x%0.8p, const EGLAttrib *attrib_list = 0x%0.8p)",
         dpy, ctx, target, buffer, attrib_list);
-    Thread *thread = GetCurrentThread();
+    Thread *thread   = GetCurrentThread();
+    Display *display = static_cast<Display *>(dpy);
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglCreateImage unimplemented.");
+    thread->setError(EglBadDisplay() << "eglCreateImage unimplemented.", GetDebug(),
+                     "eglCreateImage", GetDisplayIfValid(display));
     return EGL_NO_IMAGE;
 }
 
 EGLBoolean EGLAPIENTRY DestroyImage(EGLDisplay dpy, EGLImage image)
 {
     EVENT("(EGLDisplay dpy = 0x%0.8p, EGLImage image = 0x%0.8p)", dpy, image);
-    Thread *thread = GetCurrentThread();
+    Thread *thread   = GetCurrentThread();
+    Display *display = static_cast<Display *>(dpy);
+    Image *eglImage  = static_cast<Image *>(image);
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglDestroyImage unimplemented.");
+    thread->setError(EglBadDisplay() << "eglDestroyImage unimplemented.", GetDebug(),
+                     "eglDestroyImage", GetImageIfValid(display, eglImage));
     return EGL_FALSE;
 }
 
@@ -1096,7 +1143,7 @@
     Thread *thread = GetCurrentThread();
 
     Error err = ValidateGetPlatformDisplay(platform, native_display, attrib_list);
-    thread->setError(err);
+    thread->setError(err, GetDebug(), "eglGetPlatformDisplay", GetThreadIfValid(thread));
     if (err.isError())
     {
         return EGL_NO_DISPLAY;
@@ -1129,10 +1176,12 @@
         "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_window = 0x%0.8p, "
         "const EGLint* attrib_list = 0x%0.8p)",
         dpy, config, native_window, attrib_list);
-    Thread *thread = GetCurrentThread();
+    Thread *thread   = GetCurrentThread();
+    Display *display = static_cast<Display *>(dpy);
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglCreatePlatformWindowSurface unimplemented.");
+    thread->setError(EglBadDisplay() << "eglCreatePlatformWindowSurface unimplemented.", GetDebug(),
+                     "eglCreatePlatformWindowSurface", GetDisplayIfValid(display));
     return EGL_NO_SURFACE;
 }
 
@@ -1145,10 +1194,12 @@
         "(EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, void* native_pixmap = 0x%0.8p, "
         "const EGLint* attrib_list = 0x%0.8p)",
         dpy, config, native_pixmap, attrib_list);
-    Thread *thread = GetCurrentThread();
+    Thread *thread   = GetCurrentThread();
+    Display *display = static_cast<Display *>(dpy);
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglCreatePlatformPixmapSurface unimplemented.");
+    thread->setError(EglBadDisplay() << "eglCreatePlatformPixmapSurface unimplemented.", GetDebug(),
+                     "eglCreatePlatformPixmapSurface", GetDisplayIfValid(display));
     return EGL_NO_SURFACE;
 }
 
@@ -1156,10 +1207,12 @@
 {
     EVENT("(EGLDisplay dpy = 0x%0.8p, EGLSync sync = 0x%0.8p, EGLint flags = 0x%X)", dpy, sync,
           flags);
-    Thread *thread = GetCurrentThread();
+    Thread *thread   = GetCurrentThread();
+    Display *display = static_cast<Display *>(dpy);
 
     UNIMPLEMENTED();
-    thread->setError(EglBadDisplay() << "eglWaitSync unimplemented.");
+    thread->setError(EglBadDisplay() << "eglWaitSync unimplemented.", GetDebug(), "eglWaitSync",
+                     GetDisplayIfValid(display));
     return EGL_FALSE;
 }
 
@@ -1171,7 +1224,7 @@
     ProcEntry *entry =
         std::lower_bound(&g_procTable[0], &g_procTable[g_numProcs], procname, CompareProc);
 
-    thread->setError(NoError());
+    thread->setSuccess();
 
     if (entry == &g_procTable[g_numProcs] || strcmp(entry->first, procname) != 0)
     {
diff --git a/src/libGLESv2/entry_points_egl_ext.cpp b/src/libGLESv2/entry_points_egl_ext.cpp
index b0fc1d7..2a1f1b1 100644
--- a/src/libGLESv2/entry_points_egl_ext.cpp
+++ b/src/libGLESv2/entry_points_egl_ext.cpp
@@ -40,19 +40,21 @@
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglQuerySurfacePointerANGLE",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (!display->getExtensions().querySurfacePointer)
     {
-        thread->setError(NoError());
+        thread->setSuccess();
         return EGL_FALSE;
     }
 
     if (surface == EGL_NO_SURFACE)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglQuerySurfacePointerANGLE",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
@@ -62,25 +64,35 @@
         case EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE:
             if (!display->getExtensions().surfaceD3DTexture2DShareHandle)
             {
-                thread->setError(EglBadAttribute());
+                thread->setError(EglBadAttribute(), GetDebug(), "eglQuerySurfacePointerANGLE",
+                                 GetSurfaceIfValid(display, eglSurface));
                 return EGL_FALSE;
             }
             break;
         case EGL_DXGI_KEYED_MUTEX_ANGLE:
             if (!display->getExtensions().keyedMutex)
             {
-                thread->setError(EglBadAttribute());
+                thread->setError(EglBadAttribute(), GetDebug(), "eglQuerySurfacePointerANGLE",
+                                 GetSurfaceIfValid(display, eglSurface));
                 return EGL_FALSE;
             }
             break;
         default:
-            thread->setError(EglBadAttribute());
+            thread->setError(EglBadAttribute(), GetDebug(), "eglQuerySurfacePointerANGLE",
+                             GetSurfaceIfValid(display, eglSurface));
             return EGL_FALSE;
     }
 
     error = eglSurface->querySurfacePointerANGLE(attribute, value);
-    thread->setError(error);
-    return (error.isError() ? EGL_FALSE : EGL_TRUE);
+    if (error.isError())
+    {
+        thread->setError(error, GetDebug(), "eglQuerySurfacePointerANGLE",
+                         GetSurfaceIfValid(display, eglSurface));
+        return EGL_FALSE;
+    }
+
+    thread->setSuccess();
+    return EGL_TRUE;
 }
 
 // EGL_NV_post_sub_buffer
@@ -91,40 +103,43 @@
         "(EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint x = %d, EGLint y = %d, "
         "EGLint width = %d, EGLint height = %d)",
         dpy, surface, x, y, width, height);
-    Thread *thread = GetCurrentThread();
+    Thread *thread      = GetCurrentThread();
+    Display *display    = static_cast<Display *>(dpy);
+    Surface *eglSurface = static_cast<Surface *>(surface);
 
     if (x < 0 || y < 0 || width < 0 || height < 0)
     {
-        thread->setError(EglBadParameter());
+        thread->setError(EglBadParameter(), GetDebug(), "eglPostSubBufferNV",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
-    Display *display    = static_cast<Display *>(dpy);
-    Surface *eglSurface = static_cast<Surface *>(surface);
-
     Error error = ValidateSurface(display, eglSurface);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglPostSubBufferNV",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (display->testDeviceLost())
     {
-        thread->setError(EglContextLost());
+        thread->setError(EglContextLost(), GetDebug(), "eglPostSubBufferNV",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (surface == EGL_NO_SURFACE)
     {
-        thread->setError(EglBadSurface());
+        thread->setError(EglBadSurface(), GetDebug(), "eglPostSubBufferNV",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     if (!display->getExtensions().postSubBuffer)
     {
         // Spec is not clear about how this should be handled.
-        thread->setError(NoError());
+        thread->setSuccess();
         return EGL_TRUE;
     }
 
@@ -132,11 +147,12 @@
     error = eglSurface->postSubBuffer(thread->getContext(), x, y, width, height);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglPostSubBufferNV",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -152,7 +168,7 @@
     Thread *thread = GetCurrentThread();
 
     Error err = ValidateGetPlatformDisplayEXT(platform, native_display, attrib_list);
-    thread->setError(err);
+    thread->setError(err, GetDebug(), "eglGetPlatformDisplayEXT", GetThreadIfValid(thread));
     if (err.isError())
     {
         return EGL_NO_DISPLAY;
@@ -194,9 +210,10 @@
     ANGLE_EGL_TRY_RETURN(
         thread,
         ValidateCreatePlatformWindowSurfaceEXT(display, configuration, native_window, attributes),
-        EGL_NO_SURFACE);
+        "eglCreatePlatformWindowSurfaceEXT", GetDisplayIfValid(display), EGL_NO_SURFACE);
 
-    thread->setError(EglBadDisplay() << "CreatePlatformWindowSurfaceEXT unimplemented.");
+    thread->setError(EglBadDisplay() << "CreatePlatformWindowSurfaceEXT unimplemented.", GetDebug(),
+                     "eglCreatePlatformWindowSurfaceEXT", GetDisplayIfValid(display));
     return EGL_NO_SURFACE;
 }
 
@@ -218,9 +235,10 @@
     ANGLE_EGL_TRY_RETURN(
         thread,
         ValidateCreatePlatformPixmapSurfaceEXT(display, configuration, native_pixmap, attributes),
-        EGL_NO_SURFACE);
+        "eglCreatePlatformPixmapSurfaceEXT", GetDisplayIfValid(display), EGL_NO_SURFACE);
 
-    thread->setError(EglBadDisplay() << "CreatePlatformPixmapSurfaceEXT unimplemented.");
+    thread->setError(EglBadDisplay() << "CreatePlatformPixmapSurfaceEXT unimplemented.", GetDebug(),
+                     "eglCreatePlatformPixmapSurfaceEXT", GetDisplayIfValid(display));
     return EGL_NO_SURFACE;
 }
 
@@ -232,9 +250,11 @@
     Thread *thread = GetCurrentThread();
 
     Device *dev = static_cast<Device *>(device);
-    if (dev == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(dev))
+
+    Error error = ValidateDevice(dev);
+    if (error.isError())
     {
-        thread->setError(EglBadAccess());
+        thread->setError(error, GetDebug(), "eglQueryDeviceAttribEXT", GetDeviceIfValid(dev));
         return EGL_FALSE;
     }
 
@@ -245,12 +265,11 @@
     {
         thread->setError(EglBadAccess() << "Device wasn't created using eglCreateDeviceANGLE, "
                                            "and the Display that created it doesn't support "
-                                           "device querying");
+                                           "device querying",
+                         GetDebug(), "eglQueryDeviceAttribEXT", GetDeviceIfValid(dev));
         return EGL_FALSE;
     }
 
-    Error error(NoError());
-
     // validate the attribute parameter
     switch (attribute)
     {
@@ -258,18 +277,26 @@
         case EGL_D3D9_DEVICE_ANGLE:
             if (!dev->getExtensions().deviceD3D || dev->getType() != attribute)
             {
-                thread->setError(EglBadAttribute());
+                thread->setError(EglBadAttribute(), GetDebug(), "eglQueryDeviceAttribEXT",
+                                 GetDeviceIfValid(dev));
                 return EGL_FALSE;
             }
             error = dev->getDevice(value);
+            if (error.isError())
+            {
+                thread->setError(error, GetDebug(), "eglQueryDeviceAttribEXT",
+                                 GetDeviceIfValid(dev));
+                return EGL_FALSE;
+            }
             break;
         default:
-            thread->setError(EglBadAttribute());
+            thread->setError(EglBadAttribute(), GetDebug(), "eglQueryDeviceAttribEXT",
+                             GetDeviceIfValid(dev));
             return EGL_FALSE;
     }
 
-    thread->setError(error);
-    return (error.isError() ? EGL_FALSE : EGL_TRUE);
+    thread->setSuccess();
+    return EGL_TRUE;
 }
 
 // EGL_EXT_device_query
@@ -279,10 +306,12 @@
     Thread *thread = GetCurrentThread();
 
     Device *dev = static_cast<Device *>(device);
-    if (dev == EGL_NO_DEVICE_EXT || !Device::IsValidDevice(dev))
+
+    Error error = ValidateDevice(dev);
+    if (error.isError())
     {
-        thread->setError(EglBadDevice());
-        return nullptr;
+        thread->setError(error, GetDebug(), "eglQueryDeviceStringEXT", GetDeviceIfValid(dev));
+        return EGL_FALSE;
     }
 
     const char *result;
@@ -292,11 +321,12 @@
             result = dev->getExtensionString().c_str();
             break;
         default:
-            thread->setError(EglBadDevice());
+            thread->setError(EglBadDevice(), GetDebug(), "eglQueryDeviceStringEXT",
+                             GetDeviceIfValid(dev));
             return nullptr;
     }
 
-    thread->setError(NoError());
+    thread->setSuccess();
     return result;
 }
 
@@ -312,13 +342,14 @@
     Error error = ValidateDisplay(display);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglQueryDisplayAttribEXT", GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
     if (!display->getExtensions().deviceQuery)
     {
-        thread->setError(EglBadAccess());
+        thread->setError(EglBadAccess(), GetDebug(), "eglQueryDisplayAttribEXT",
+                         GetDisplayIfValid(display));
         return EGL_FALSE;
     }
 
@@ -330,12 +361,13 @@
             break;
 
         default:
-            thread->setError(EglBadAttribute());
+            thread->setError(EglBadAttribute(), GetDebug(), "eglQueryDisplayAttribEXT",
+                             GetDisplayIfValid(display));
             return EGL_FALSE;
     }
 
-    thread->setError(error);
-    return (error.isError() ? EGL_FALSE : EGL_TRUE);
+    thread->setSuccess();
+    return EGL_TRUE;
 }
 
 ANGLE_EXPORT EGLImageKHR EGLAPIENTRY CreateImageKHR(EGLDisplay dpy,
@@ -357,7 +389,7 @@
     Error error = ValidateCreateImageKHR(display, context, target, buffer, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateImageKHR", GetDisplayIfValid(display));
         return EGL_NO_IMAGE;
     }
 
@@ -365,10 +397,11 @@
     error        = display->createImage(context, target, buffer, attributes, &image);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateImageKHR", GetDisplayIfValid(display));
         return EGL_NO_IMAGE;
     }
 
+    thread->setSuccess();
     return static_cast<EGLImage>(image);
 }
 
@@ -383,12 +416,13 @@
     Error error = ValidateDestroyImageKHR(display, img);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglDestroyImageKHR", GetImageIfValid(display, img));
         return EGL_FALSE;
     }
 
     display->destroyImage(img);
 
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -405,7 +439,7 @@
     Error error = ValidateCreateDeviceANGLE(device_type, native_device, attrib_list);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateDeviceANGLE", GetThreadIfValid(thread));
         return EGL_NO_DEVICE_EXT;
     }
 
@@ -414,10 +448,11 @@
     if (error.isError())
     {
         ASSERT(device == nullptr);
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateDeviceANGLE", GetThreadIfValid(thread));
         return EGL_NO_DEVICE_EXT;
     }
 
+    thread->setSuccess();
     return device;
 }
 
@@ -431,12 +466,13 @@
     Error error = ValidateReleaseDeviceANGLE(dev);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglReleaseDeviceANGLE", GetDeviceIfValid(dev));
         return EGL_FALSE;
     }
 
     SafeDelete(dev);
 
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -452,7 +488,7 @@
     Error error = ValidateCreateStreamKHR(display, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateStreamKHR", GetDisplayIfValid(display));
         return EGL_NO_STREAM_KHR;
     }
 
@@ -460,11 +496,11 @@
     error = display->createStream(attributes, &stream);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateStreamKHR", GetDisplayIfValid(display));
         return EGL_NO_STREAM_KHR;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return static_cast<EGLStreamKHR>(stream);
 }
 
@@ -479,12 +515,14 @@
     Error error = ValidateDestroyStreamKHR(display, streamObject);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglDestroyStreamKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     display->destroyStream(streamObject);
-    thread->setError(error);
+
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -505,7 +543,8 @@
     Error error = ValidateStreamAttribKHR(display, streamObject, attribute, value);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamAttribKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
@@ -521,7 +560,7 @@
             UNREACHABLE();
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -542,7 +581,8 @@
     Error error = ValidateQueryStreamKHR(display, streamObject, attribute, value);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglQueryStreamKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
@@ -561,7 +601,7 @@
             UNREACHABLE();
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -582,7 +622,8 @@
     Error error = ValidateQueryStreamu64KHR(display, streamObject, attribute, value);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglQueryStreamu64KHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
@@ -598,7 +639,7 @@
             UNREACHABLE();
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -614,18 +655,20 @@
     Error error = ValidateStreamConsumerGLTextureExternalKHR(display, context, streamObject);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerGLTextureExternalKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     error = streamObject->createConsumerGLTextureExternal(AttributeMap(), context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerGLTextureExternalKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -641,18 +684,20 @@
     Error error = ValidateStreamConsumerAcquireKHR(display, context, streamObject);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerAcquireKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     error = streamObject->consumerAcquire(context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerAcquireKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -668,18 +713,20 @@
     Error error = ValidateStreamConsumerReleaseKHR(display, context, streamObject);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSStreamConsumerReleaseKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     error = streamObject->consumerRelease(context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerReleaseKHR",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -701,18 +748,20 @@
                                                                    attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerGLTextureExternalAttribsNV",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     error = streamObject->createConsumerGLTextureExternal(attributes, context);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamConsumerGLTextureExternalAttribsNV",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -732,18 +781,20 @@
     Error error = ValidateCreateStreamProducerD3DTextureANGLE(display, streamObject, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateStreamProducerD3DTextureANGLE",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     error = streamObject->createProducerD3D11Texture(attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglCreateStreamProducerD3DTextureANGLE",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -765,18 +816,20 @@
     Error error = ValidateStreamPostD3DTextureANGLE(display, streamObject, texture, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamPostD3DTextureANGLE",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
     error = streamObject->postD3D11Texture(texture, attributes);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglStreamPostD3DTextureANGLE",
+                         GetStreamIfValid(display, streamObject));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -798,18 +851,20 @@
     Error error = ValidateGetSyncValuesCHROMIUM(display, eglSurface, ust, msc, sbc);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglGetSyncValuesCHROMIUM",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     error = eglSurface->getSyncValues(ust, msc, sbc);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglGetSyncValuesCHROMIUM",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
-    thread->setError(error);
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -830,17 +885,20 @@
     Error error = ValidateSwapBuffersWithDamageKHR(display, eglSurface, rects, n_rects);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSwapBuffersWithDamageEXT",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
     error = eglSurface->swapWithDamage(thread->getContext(), rects, n_rects);
     if (error.isError())
     {
-        thread->setError(error);
+        thread->setError(error, GetDebug(), "eglSwapBuffersWithDamageEXT",
+                         GetSurfaceIfValid(display, eglSurface));
         return EGL_FALSE;
     }
 
+    thread->setSuccess();
     return EGL_TRUE;
 }
 
@@ -856,8 +914,11 @@
     Surface *eglSurface = static_cast<Surface *>(surface);
 
     ANGLE_EGL_TRY_RETURN(thread, ValidatePresentationTimeANDROID(display, eglSurface, time),
+                         "eglPresentationTimeANDROID", GetSurfaceIfValid(display, eglSurface),
                          EGL_FALSE);
-    ANGLE_EGL_TRY_RETURN(thread, eglSurface->setPresentationTime(time), EGL_FALSE);
+    ANGLE_EGL_TRY_RETURN(thread, eglSurface->setPresentationTime(time),
+                         "eglPresentationTimeANDROID", GetSurfaceIfValid(display, eglSurface),
+                         EGL_FALSE);
 
     return EGL_TRUE;
 }
@@ -869,8 +930,10 @@
     Display *display = static_cast<Display *>(dpy);
     Thread *thread   = GetCurrentThread();
 
-    ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheGetAttribANGLE(display, attrib), 0);
+    ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheGetAttribANGLE(display, attrib),
+                         "eglProgramCacheGetAttribANGLE", GetDisplayIfValid(display), 0);
 
+    thread->setSuccess();
     return display->programCacheGetAttrib(attrib);
 }
 
@@ -890,9 +953,13 @@
     Thread *thread   = GetCurrentThread();
 
     ANGLE_EGL_TRY(thread,
-                  ValidateProgramCacheQueryANGLE(display, index, key, keysize, binary, binarysize));
+                  ValidateProgramCacheQueryANGLE(display, index, key, keysize, binary, binarysize),
+                  "eglProgramCacheQueryANGLE", GetDisplayIfValid(display));
 
-    ANGLE_EGL_TRY(thread, display->programCacheQuery(index, key, keysize, binary, binarysize));
+    ANGLE_EGL_TRY(thread, display->programCacheQuery(index, key, keysize, binary, binarysize),
+                  "eglProgramCacheQueryANGLE", GetDisplayIfValid(display));
+
+    thread->setSuccess();
 }
 
 void EGLAPIENTRY ProgramCachePopulateANGLE(EGLDisplay dpy,
@@ -910,9 +977,13 @@
     Thread *thread   = GetCurrentThread();
 
     ANGLE_EGL_TRY(thread,
-                  ValidateProgramCachePopulateANGLE(display, key, keysize, binary, binarysize));
+                  ValidateProgramCachePopulateANGLE(display, key, keysize, binary, binarysize),
+                  "eglProgramCachePopulateANGLE", GetDisplayIfValid(display));
 
-    ANGLE_EGL_TRY(thread, display->programCachePopulate(key, keysize, binary, binarysize));
+    ANGLE_EGL_TRY(thread, display->programCachePopulate(key, keysize, binary, binarysize),
+                  "eglProgramCachePopulateANGLE", GetDisplayIfValid(display));
+
+    thread->setSuccess();
 }
 
 EGLint EGLAPIENTRY ProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode)
@@ -922,9 +993,100 @@
     Display *display = static_cast<Display *>(dpy);
     Thread *thread   = GetCurrentThread();
 
-    ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheResizeANGLE(display, limit, mode), 0);
+    ANGLE_EGL_TRY_RETURN(thread, ValidateProgramCacheResizeANGLE(display, limit, mode),
+                         "eglProgramCacheResizeANGLE", GetDisplayIfValid(display), 0);
 
+    thread->setSuccess();
     return display->programCacheResize(limit, mode);
 }
 
+EGLint EGLAPIENTRY DebugMessageControlKHR(EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list)
+{
+    EVENT("(EGLDEBUGPROCKHR callback = 0x%0.8p, EGLAttrib attrib_list = 0x%0.8p)", callback,
+          attrib_list);
+
+    Thread *thread = GetCurrentThread();
+
+    AttributeMap attributes = AttributeMap::CreateFromAttribArray(attrib_list);
+
+    Error error = ValidateDebugMessageControlKHR(callback, attributes);
+    if (error.isError())
+    {
+        thread->setError(error, GetDebug(), "eglDebugMessageControlKHR", nullptr);
+        return error.getCode();
+    }
+
+    Debug *debug = GetDebug();
+    debug->setCallback(callback, attributes);
+
+    thread->setSuccess();
+    return EGL_SUCCESS;
+}
+
+EGLBoolean EGLAPIENTRY QueryDebugKHR(EGLint attribute, EGLAttrib *value)
+{
+    EVENT("(EGLint attribute = 0x%X, EGLAttrib* value = 0x%0.8p)", attribute, value);
+
+    Thread *thread = GetCurrentThread();
+
+    Error error = ValidateQueryDebugKHR(attribute, value);
+    if (error.isError())
+    {
+        thread->setError(error, GetDebug(), "eglQueryDebugKHR", nullptr);
+        return EGL_FALSE;
+    }
+
+    Debug *debug = GetDebug();
+    switch (attribute)
+    {
+        case EGL_DEBUG_MSG_CRITICAL_KHR:
+        case EGL_DEBUG_MSG_ERROR_KHR:
+        case EGL_DEBUG_MSG_WARN_KHR:
+        case EGL_DEBUG_MSG_INFO_KHR:
+            *value = debug->isMessageTypeEnabled(FromEGLenum<MessageType>(attribute)) ? EGL_TRUE
+                                                                                      : EGL_FALSE;
+            break;
+        case EGL_DEBUG_CALLBACK_KHR:
+            *value = reinterpret_cast<EGLAttrib>(debug->getCallback());
+            break;
+
+        default:
+            UNREACHABLE();
+    }
+
+    thread->setSuccess();
+    return EGL_TRUE;
+}
+
+EGLint EGLAPIENTRY LabelObjectKHR(EGLDisplay dpy,
+                                  EGLenum objectType,
+                                  EGLObjectKHR object,
+                                  EGLLabelKHR label)
+{
+    EVENT(
+        "(EGLDisplay dpy = 0x%0.8pf, EGLenum objectType = 0x%X, EGLObjectKHR object = 0x%0.8p, "
+        "EGLLabelKHR label = 0x%0.8p)",
+        dpy, objectType, object, label);
+
+    Display *display = static_cast<Display *>(dpy);
+    Thread *thread   = GetCurrentThread();
+
+    ObjectType objectTypePacked = FromEGLenum<ObjectType>(objectType);
+    Error error = ValidateLabelObjectKHR(thread, display, objectTypePacked, object, label);
+    if (error.isError())
+    {
+        thread->setError(error, GetDebug(), "eglLabelObjectKHR",
+                         GetLabeledObjectIfValid(thread, display, objectTypePacked, object));
+        return error.getCode();
+    }
+
+    LabeledObject *labeledObject =
+        GetLabeledObjectIfValid(thread, display, objectTypePacked, object);
+    ASSERT(labeledObject != nullptr);
+    labeledObject->setLabel(label);
+
+    thread->setSuccess();
+    return EGL_SUCCESS;
+}
+
 }  // namespace egl
diff --git a/src/libGLESv2/entry_points_egl_ext.h b/src/libGLESv2/entry_points_egl_ext.h
index 98cd457..6a44978 100644
--- a/src/libGLESv2/entry_points_egl_ext.h
+++ b/src/libGLESv2/entry_points_egl_ext.h
@@ -120,7 +120,7 @@
                                                             EGLSurface surface,
                                                             EGLnsecsANDROID time);
 
-//
+// EGL_ANGLE_program_cache_control
 ANGLE_EXPORT EGLint EGLAPIENTRY ProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib);
 ANGLE_EXPORT void EGLAPIENTRY ProgramCacheQueryANGLE(EGLDisplay dpy,
                                                      EGLint index,
@@ -135,6 +135,17 @@
                                                         EGLint binarysize);
 ANGLE_EXPORT EGLint EGLAPIENTRY ProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLenum mode);
 
+// EGL_KHR_debug
+ANGLE_EXPORT EGLint EGLAPIENTRY DebugMessageControlKHR(EGLDEBUGPROCKHR callback,
+                                                       const EGLAttrib *attrib_list);
+
+ANGLE_EXPORT EGLBoolean EGLAPIENTRY QueryDebugKHR(EGLint attribute, EGLAttrib *value);
+
+ANGLE_EXPORT EGLint EGLAPIENTRY LabelObjectKHR(EGLDisplay display,
+                                               EGLenum objectType,
+                                               EGLObjectKHR object,
+                                               EGLLabelKHR label);
+
 }  // namespace egl
 
 #endif  // LIBGLESV2_ENTRYPOINTSEGLEXT_H_
diff --git a/src/libGLESv2/global_state.cpp b/src/libGLESv2/global_state.cpp
index c5f3dfe..181a029 100644
--- a/src/libGLESv2/global_state.cpp
+++ b/src/libGLESv2/global_state.cpp
@@ -12,6 +12,7 @@
 #include "common/platform.h"
 #include "common/tls.h"
 
+#include "libANGLE/Debug.h"
 #include "libANGLE/Thread.h"
 
 namespace gl
@@ -38,6 +39,7 @@
 {
 
 static TLSIndex threadTLS = TLS_INVALID_INDEX;
+Debug *g_Debug            = nullptr;
 
 Thread *AllocateCurrentThread()
 {
@@ -57,6 +59,15 @@
     return thread;
 }
 
+void AllocateDebug()
+{
+    // TODO(geofflang): Lock around global allocation. http://anglebug.com/2464
+    if (g_Debug == nullptr)
+    {
+        g_Debug = new Debug();
+    }
+}
+
 }  // anonymous namespace
 
 Thread *GetCurrentThread()
@@ -74,6 +85,12 @@
     return (current ? current : AllocateCurrentThread());
 }
 
+Debug *GetDebug()
+{
+    AllocateDebug();
+    return g_Debug;
+}
+
 }  // namespace egl
 
 #ifdef ANGLE_PLATFORM_WINDOWS
@@ -90,8 +107,16 @@
     return SetTLSValue(threadTLS, nullptr);
 }
 
+void DealocateDebug()
+{
+    SafeDelete(g_Debug);
+}
+
 bool InitializeProcess()
 {
+    ASSERT(g_Debug == nullptr);
+    AllocateDebug();
+
     threadTLS = CreateTLSIndex();
     if (threadTLS == TLS_INVALID_INDEX)
     {
@@ -103,6 +128,8 @@
 
 bool TerminateProcess()
 {
+    DealocateDebug();
+
     if (!DeallocateCurrentThread())
     {
         return false;
diff --git a/src/libGLESv2/global_state.h b/src/libGLESv2/global_state.h
index 6442cce..d7dcf56 100644
--- a/src/libGLESv2/global_state.h
+++ b/src/libGLESv2/global_state.h
@@ -20,9 +20,11 @@
 
 namespace egl
 {
+class Debug;
 class Thread;
 
 Thread *GetCurrentThread();
+Debug *GetDebug();
 
 }  // namespace egl
 
diff --git a/src/libGLESv2/proc_table_autogen.cpp b/src/libGLESv2/proc_table_autogen.cpp
index 7512247..c822309 100644
--- a/src/libGLESv2/proc_table_autogen.cpp
+++ b/src/libGLESv2/proc_table_autogen.cpp
@@ -47,6 +47,7 @@
     {"eglCreateStreamProducerD3DTextureANGLE", P(egl::CreateStreamProducerD3DTextureANGLE)},
     {"eglCreateSync", P(egl::CreateSync)},
     {"eglCreateWindowSurface", P(egl::CreateWindowSurface)},
+    {"eglDebugMessageControlKHR", P(egl::DebugMessageControlKHR)},
     {"eglDestroyContext", P(egl::DestroyContext)},
     {"eglDestroyImage", P(egl::DestroyImage)},
     {"eglDestroyImageKHR", P(egl::DestroyImageKHR)},
@@ -66,6 +67,7 @@
     {"eglGetSyncAttrib", P(egl::GetSyncAttrib)},
     {"eglGetSyncValuesCHROMIUM", P(egl::GetSyncValuesCHROMIUM)},
     {"eglInitialize", P(egl::Initialize)},
+    {"eglLabelObjectKHR", P(egl::LabelObjectKHR)},
     {"eglMakeCurrent", P(egl::MakeCurrent)},
     {"eglPostSubBufferNV", P(egl::PostSubBufferNV)},
     {"eglPresentationTimeANDROID", P(egl::PresentationTimeANDROID)},
@@ -75,6 +77,7 @@
     {"eglProgramCacheResizeANGLE", P(egl::ProgramCacheResizeANGLE)},
     {"eglQueryAPI", P(egl::QueryAPI)},
     {"eglQueryContext", P(egl::QueryContext)},
+    {"eglQueryDebugKHR", P(egl::QueryDebugKHR)},
     {"eglQueryDeviceAttribEXT", P(egl::QueryDeviceAttribEXT)},
     {"eglQueryDeviceStringEXT", P(egl::QueryDeviceStringEXT)},
     {"eglQueryDisplayAttribEXT", P(egl::QueryDisplayAttribEXT)},
@@ -1234,5 +1237,5 @@
     {"glWeightPointerOES", P(gl::WeightPointerOES)},
     {"glWeightPointerOESContextANGLE", P(gl::WeightPointerOESContextANGLE)}};
 
-size_t g_numProcs = 1166;
+size_t g_numProcs = 1169;
 }  // namespace egl
diff --git a/src/libGLESv2/proc_table_data.json b/src/libGLESv2/proc_table_data.json
index 50af45b..80d7d02 100644
--- a/src/libGLESv2/proc_table_data.json
+++ b/src/libGLESv2/proc_table_data.json
@@ -839,6 +839,12 @@
         "eglProgramCacheResizeANGLE"
     ],
 
+    "EGL_KHR_debug": [
+        "eglDebugMessageControlKHR",
+        "eglQueryDebugKHR",
+        "eglLabelObjectKHR"
+    ],
+
     "angle::Platform related entry points": [
         "ANGLEGetDisplayPlatform",
         "ANGLEResetDisplayPlatform"
diff --git a/src/tests/angle_end2end_tests.gypi b/src/tests/angle_end2end_tests.gypi
index 0265b05..8b60b77 100644
--- a/src/tests/angle_end2end_tests.gypi
+++ b/src/tests/angle_end2end_tests.gypi
@@ -127,6 +127,7 @@
             '<(angle_path)/src/tests/gl_tests/WebGLReadOutsideFramebufferTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLContextCompatibilityTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLContextSharingTest.cpp',
+            '<(angle_path)/src/tests/egl_tests/EGLDebugTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLProgramCacheControlTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLQueryContextTest.cpp',
             '<(angle_path)/src/tests/egl_tests/EGLRobustnessTest.cpp',
diff --git a/src/tests/egl_tests/EGLDebugTest.cpp b/src/tests/egl_tests/EGLDebugTest.cpp
new file mode 100644
index 0000000..558f952
--- /dev/null
+++ b/src/tests/egl_tests/EGLDebugTest.cpp
@@ -0,0 +1,181 @@
+//
+// Copyright (c) 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.
+//
+// EGLDebugTest.cpp:
+//   Tests of EGL_KHR_debug extension
+
+#include <gtest/gtest.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "test_utils/ANGLETest.h"
+#include "test_utils/angle_test_configs.h"
+
+namespace angle
+{
+class EGLDebugTest : public ANGLETest
+{
+  protected:
+    bool hasExtension() const { return eglClientExtensionEnabled("EGL_KHR_debug"); }
+
+    static void EGLAPIENTRY StubCallback(EGLenum error,
+                                         const char *command,
+                                         EGLint messageType,
+                                         EGLLabelKHR threadLabel,
+                                         EGLLabelKHR objectLabel,
+                                         const char *message)
+    {
+    }
+
+    static void EGLAPIENTRY CheckBadBindAPIError(EGLenum error,
+                                                 const char *command,
+                                                 EGLint messageType,
+                                                 EGLLabelKHR threadLabel,
+                                                 EGLLabelKHR objectLabel,
+                                                 const char *message)
+    {
+        EXPECT_STREQ("eglBindAPI", command);
+        ASSERT_EGLENUM_EQ(EGL_BAD_PARAMETER, error);
+        EXPECT_STREQ("Thread", static_cast<const char *>(threadLabel));
+    }
+
+    static EGLDEBUGPROCKHR EGLAttribToDebugCallback(EGLAttrib attrib)
+    {
+        return reinterpret_cast<EGLDEBUGPROCKHR>(static_cast<uintptr_t>(attrib));
+    }
+
+    static EGLAttrib DebugCallbackToEGLAttrib(EGLDEBUGPROCKHR callback)
+    {
+        return static_cast<EGLAttrib>(reinterpret_cast<intptr_t>(callback));
+    }
+};
+
+// Test that the extension is always available (it is implemented in ANGLE's frontend).
+TEST_P(EGLDebugTest, ExtensionAlwaysAvailable)
+{
+    ASSERT_TRUE(hasExtension());
+}
+
+// Check that the default message filters and callbacks are correct
+TEST_P(EGLDebugTest, DefaultParameters)
+{
+    ANGLE_SKIP_TEST_IF(!hasExtension());
+
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(nullptr, nullptr));
+
+    EGLAttrib result = 0;
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_ERROR_KHR, &result));
+    EXPECT_EGL_TRUE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_WARN_KHR, &result));
+    EXPECT_EGL_FALSE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_INFO_KHR, &result));
+    EXPECT_EGL_FALSE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_CALLBACK_KHR, &result));
+    EXPECT_EQ(nullptr, EGLAttribToDebugCallback(result));
+}
+
+// Check that the message control and callback parameters can be set and then queried back
+TEST_P(EGLDebugTest, SetMessageControl)
+{
+    ANGLE_SKIP_TEST_IF(!hasExtension());
+
+    EGLAttrib controls[] = {
+        EGL_DEBUG_MSG_CRITICAL_KHR, EGL_FALSE,
+        // EGL_DEBUG_MSG_ERROR_KHR left unset
+        EGL_DEBUG_MSG_WARN_KHR, EGL_TRUE, EGL_DEBUG_MSG_INFO_KHR, EGL_FALSE, EGL_NONE, EGL_NONE,
+    };
+
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(&StubCallback, controls));
+
+    EGLAttrib result = 0;
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_CRITICAL_KHR, &result));
+    EXPECT_EGL_FALSE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_ERROR_KHR, &result));
+    EXPECT_EGL_TRUE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_WARN_KHR, &result));
+    EXPECT_EGL_TRUE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_MSG_INFO_KHR, &result));
+    EXPECT_EGL_FALSE(result);
+
+    EXPECT_EGL_TRUE(eglQueryDebugKHR(EGL_DEBUG_CALLBACK_KHR, &result));
+    EXPECT_EQ(DebugCallbackToEGLAttrib(&StubCallback), result);
+}
+
+// Set a thread label and then trigger a callback to verify the callback parameters are correct
+TEST_P(EGLDebugTest, CorrectCallbackParameters)
+{
+    ANGLE_SKIP_TEST_IF(!hasExtension());
+
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(nullptr, nullptr));
+
+    EXPECT_EQ(EGL_SUCCESS, eglLabelObjectKHR(EGL_NO_DISPLAY, EGL_OBJECT_THREAD_KHR, nullptr,
+                                             const_cast<char *>("Thread")));
+
+    // Enable all messages
+    EGLAttrib controls[] = {
+        EGL_DEBUG_MSG_CRITICAL_KHR,
+        EGL_TRUE,
+        EGL_DEBUG_MSG_ERROR_KHR,
+        EGL_TRUE,
+        EGL_DEBUG_MSG_WARN_KHR,
+        EGL_TRUE,
+        EGL_DEBUG_MSG_INFO_KHR,
+        EGL_TRUE,
+        EGL_NONE,
+        EGL_NONE,
+    };
+
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS),
+              eglDebugMessageControlKHR(&CheckBadBindAPIError, controls));
+
+    // Generate an error and trigger the callback
+    EXPECT_EGL_FALSE(eglBindAPI(0xBADDBADD));
+}
+
+// Test that labels can be set and that errors are generated if the wrong object type is used
+TEST_P(EGLDebugTest, SetLabel)
+{
+    ANGLE_SKIP_TEST_IF(!hasExtension());
+
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS), eglDebugMessageControlKHR(nullptr, nullptr));
+
+    // Display display and object must be equal when setting a display label
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS),
+              eglLabelObjectKHR(getEGLWindow()->getDisplay(), EGL_OBJECT_DISPLAY_KHR,
+                                getEGLWindow()->getDisplay(), const_cast<char *>("Display")));
+    EXPECT_NE(static_cast<EGLint>(EGL_SUCCESS),
+              eglLabelObjectKHR(nullptr, EGL_OBJECT_DISPLAY_KHR, getEGLWindow()->getDisplay(),
+                                const_cast<char *>("Display")));
+
+    //  Set a surface label
+    EXPECT_EQ(static_cast<EGLint>(EGL_SUCCESS),
+              eglLabelObjectKHR(getEGLWindow()->getDisplay(), EGL_OBJECT_SURFACE_KHR,
+                                getEGLWindow()->getSurface(), const_cast<char *>("Surface")));
+    EXPECT_EGL_ERROR(EGL_SUCCESS);
+
+    // Provide a surface but use an image label type
+    EXPECT_EQ(static_cast<EGLint>(EGL_BAD_PARAMETER),
+              eglLabelObjectKHR(getEGLWindow()->getDisplay(), EGL_OBJECT_IMAGE_KHR,
+                                getEGLWindow()->getSurface(), const_cast<char *>("Image")));
+    EXPECT_EGL_ERROR(EGL_BAD_PARAMETER);
+}
+
+ANGLE_INSTANTIATE_TEST(EGLDebugTest,
+                       ES2_D3D9(),
+                       ES2_D3D11(),
+                       ES3_D3D11(),
+                       ES2_OPENGL(),
+                       ES3_OPENGL());
+
+}  // namespace angle
diff --git a/src/tests/test_utils/ANGLETest.h b/src/tests/test_utils/ANGLETest.h
index c73db9c..f618eeb 100644
--- a/src/tests/test_utils/ANGLETest.h
+++ b/src/tests/test_utils/ANGLETest.h
@@ -37,10 +37,12 @@
 #define EXPECT_EGL_SUCCESS() EXPECT_EGL_ERROR(EGL_SUCCESS)
 
 // EGLBoolean is |unsigned int| but EGL_TRUE is 0, not 0u.
-#define ASSERT_EGL_TRUE(a) ASSERT_EQ(static_cast<EGLBoolean>(EGL_TRUE), (a))
-#define ASSERT_EGL_FALSE(a) ASSERT_EQ(static_cast<EGLBoolean>(EGL_FALSE), (a))
-#define EXPECT_EGL_TRUE(a) EXPECT_EQ(static_cast<EGLBoolean>(EGL_TRUE), (a))
-#define EXPECT_EGL_FALSE(a) EXPECT_EQ(static_cast<EGLBoolean>(EGL_FALSE), (a))
+#define ASSERT_EGL_TRUE(a) ASSERT_EQ(static_cast<EGLBoolean>(EGL_TRUE), static_cast<EGLBoolean>(a))
+#define ASSERT_EGL_FALSE(a) \
+    ASSERT_EQ(static_cast<EGLBoolean>(EGL_FALSE), static_cast<EGLBoolean>(a))
+#define EXPECT_EGL_TRUE(a) EXPECT_EQ(static_cast<EGLBoolean>(EGL_TRUE), static_cast<EGLBoolean>(a))
+#define EXPECT_EGL_FALSE(a) \
+    EXPECT_EQ(static_cast<EGLBoolean>(EGL_FALSE), static_cast<EGLBoolean>(a))
 
 #define ASSERT_EGL_ERROR(err) ASSERT_EQ((err), eglGetError())
 #define ASSERT_EGL_SUCCESS() ASSERT_EGL_ERROR(EGL_SUCCESS)
@@ -54,6 +56,11 @@
 #define EXPECT_GLENUM_NE(expected, actual) \
     EXPECT_NE(static_cast<GLenum>(expected), static_cast<GLenum>(actual))
 
+#define ASSERT_EGLENUM_EQ(expected, actual) \
+    ASSERT_EQ(static_cast<EGLenum>(expected), static_cast<EGLenum>(actual))
+#define EXPECT_EGLENUM_EQ(expected, actual) \
+    EXPECT_EQ(static_cast<EGLenum>(expected), static_cast<EGLenum>(actual))
+
 namespace angle
 {
 struct GLColorRGB