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