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
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index ae84144..935eca6 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -22,6 +22,7 @@
#include "libANGLE/Error.h"
#include "libANGLE/HandleAllocator.h"
#include "libANGLE/VertexAttribute.h"
+#include "libANGLE/Workarounds.h"
#include "libANGLE/angletypes.h"
namespace rx
@@ -595,6 +596,7 @@
size_t getExtensionStringCount() const;
rx::ContextImpl *getImplementation() const { return mImplementation.get(); }
+ const Workarounds &getWorkarounds() const;
private:
void syncRendererState();
@@ -620,6 +622,7 @@
void initCaps(bool webGLContext);
void updateCaps();
+ void initWorkarounds();
LabeledObject *getLabeledObject(GLenum identifier, GLuint name) const;
LabeledObject *getLabeledObjectFromPtr(const void *ptr) const;
@@ -672,6 +675,7 @@
bool mHasBeenCurrent;
bool mContextLost;
GLenum mResetStatus;
+ bool mContextLostForced;
GLenum mResetStrategy;
bool mRobustAccess;
egl::Surface *mCurrentSurface;
@@ -686,6 +690,8 @@
State::DirtyObjects mClearDirtyObjects;
State::DirtyBits mBlitDirtyBits;
State::DirtyObjects mBlitDirtyObjects;
+
+ Workarounds mWorkarounds;
};
} // namespace gl
diff --git a/src/libANGLE/Workarounds.h b/src/libANGLE/Workarounds.h
new file mode 100644
index 0000000..c5533c1
--- /dev/null
+++ b/src/libANGLE/Workarounds.h
@@ -0,0 +1,25 @@
+//
+// Copyright (c) 2016 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.
+//
+
+// Workarounds.h: Workarounds for driver bugs and other behaviors seen
+// on all platforms.
+
+#ifndef LIBANGLE_WORKAROUNDS_H_
+#define LIBANGLE_WORKAROUNDS_H_
+
+namespace gl
+{
+
+struct Workarounds
+{
+ // Force the context to be lost (via KHR_robustness) if a GL_OUT_OF_MEMORY error occurs. The
+ // driver may be in an inconsistent state if this happens, and some users of ANGLE rely on this
+ // notification to prevent further execution.
+ bool loseContextOnOutOfMemory = false;
+};
+} // namespace gl
+
+#endif // LIBANGLE_WORKAROUNDS_H_