Add cross-platform Workarounds to Context.

These are distinct from the renderer-level workarounds.

Add the first workaround, loseContextOnOutOfMemory. This is enabled
when the application enables reset notifications via KHR_robustness,
and is intended for more robust handling of errors in key APIs for
Chromium's correctness (in particular, sync objects).

Change Context::getResetStatus to persistently return the "lost" status
if it was set by calling Context::markContextLost. Previously, if
markContextLost was called but the implementation hadn't actually
received an error like a lost device, the "lost" reset status would be
dropped. Returning it only once to the caller is also fragile. Tested
this by manually injecting a failure in FenceSync11::clientWait and
ensuring that Chromium detected it as expected.

BUG=chromium:650138

Change-Id: Ie53069eacd1754ad5d64936e3fef315af24605fa
Reviewed-on: https://chromium-review.googlesource.com/394233
Commit-Queue: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 235a3a5..3bdcc60 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -35,6 +35,7 @@
 #include "libANGLE/VertexArray.h"
 #include "libANGLE/formatutils.h"
 #include "libANGLE/validationES.h"
+#include "libANGLE/Workarounds.h"
 #include "libANGLE/renderer/ContextImpl.h"
 #include "libANGLE/renderer/EGLImplFactory.h"
 #include "libANGLE/queryconversions.h"
@@ -247,6 +248,7 @@
       mHasBeenCurrent(false),
       mContextLost(false),
       mResetStatus(GL_NO_ERROR),
+      mContextLostForced(false),
       mResetStrategy(GetResetStrategy(attribs)),
       mRobustAccess(GetRobustAccess(attribs)),
       mCurrentSurface(nullptr),
@@ -255,6 +257,7 @@
     ASSERT(!mRobustAccess);  // Unimplemented
 
     initCaps(GetWebGLContext(attribs));
+    initWorkarounds();
 
     mGLState.initialize(mCaps, mExtensions, mClientMajorVersion, GetDebug(attribs),
                         GetBindGeneratesResource(attribs));
@@ -1916,7 +1919,12 @@
 {
     if (error.isError())
     {
-        mErrors.insert(error.getCode());
+        GLenum code = error.getCode();
+        mErrors.insert(code);
+        if (code == GL_OUT_OF_MEMORY && getWorkarounds().loseContextOnOutOfMemory)
+        {
+            markContextLost();
+        }
 
         if (!error.getMessage().empty())
         {
@@ -1947,7 +1955,10 @@
 void Context::markContextLost()
 {
     if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT)
+    {
         mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT;
+        mContextLostForced = true;
+    }
     mContextLost     = true;
 }
 
@@ -1986,8 +1997,11 @@
             mContextLost = true;
         }
     }
-    else if (mResetStatus != GL_NO_ERROR)
+    else if (!mContextLostForced && mResetStatus != GL_NO_ERROR)
     {
+        // If markContextLost was used to mark the context lost then
+        // assume that is not recoverable, and continue to report the
+        // lost reset status for the lifetime of this context.
         mResetStatus = mImplementation->getResetStatus();
     }
 
@@ -2470,6 +2484,13 @@
     }
 }
 
+void Context::initWorkarounds()
+{
+    // Lose the context upon out of memory error if the application is
+    // expecting to watch for those events.
+    mWorkarounds.loseContextOnOutOfMemory = (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
+}
+
 void Context::syncRendererState()
 {
     const State::DirtyBits &dirtyBits = mGLState.getDirtyBits();
@@ -3557,4 +3578,9 @@
     programObject->attachShader(shaderObject);
 }
 
+const Workarounds &Context::getWorkarounds() const
+{
+    return mWorkarounds;
+}
+
 }  // namespace gl