Commit 96a49a48 by Jonah Ryan-Davis Committed by Commit Bot

GLX, EGL: Support NV_robustness_video_memory_purge

Chrome is showing rendering issues on Linux/Nvidia after returning from the lock screen. This could be related to the fact that Nvidia drivers are not able to guarantee conformance after certain events. By exposing this extension, we can instruct Chrome to reinitialize contexts after they are purged by the driver. If this is not explicitly requested, we can still generate an UnknownContextReset to tell apps to discard the invalid context anyway. Bug: chromium:1113040 Change-Id: Ie99b6356cc27fea33643d61b1d74f4f68a271d70 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2453689Reviewed-by: 's avatarKenneth Russell <kbr@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org> Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
parent c13ddc36
......@@ -554,6 +554,11 @@ GL_APICALL void GL_APIENTRY glImportSemaphoreZirconHandleANGLE(GLuint memory,
#define GL_TEXTURE_FILTERING_HINT_CHROMIUM 0x8AF0
#endif /* GL_CHROMIUM_texture_filtering_hint */
#ifndef GL_NV_robustness_video_memory
#define GL_NV_robustness_video_memory
#define GL_PURGED_CONTEXT_RESET_NV 0x92BB
#endif /* GL_NV_robustness_video_memory */
// clang-format on
#endif // INCLUDE_GLES2_GL2EXT_ANGLE_H_
......@@ -4,13 +4,13 @@
"src/common/PackedEGLEnums_autogen.h":
"085d82d2003f02345abc4986523127d4",
"src/common/PackedGLEnums_autogen.cpp":
"dfd979452806f59fff27dde8ffe8e300",
"2a02645fb791fc9379885d4ff3af0de4",
"src/common/PackedGLEnums_autogen.h":
"8466493b646665844ac579e997ebb6ca",
"d7b5d92d1b44d7b2e6684c81d316a165",
"src/common/gen_packed_gl_enums.py":
"b3e96ea44f52ec23ee893bd843dfd2cb",
"src/common/packed_egl_enums.json":
"76e1b814421e121164d60a0d89cb16c1",
"src/common/packed_gl_enums.json":
"5ed701940bc80450631f8886d585ef8a"
"2663ff32de3d8b3b848e6853f5e5eb24"
}
\ No newline at end of file
......@@ -560,6 +560,8 @@ GraphicsResetStatus FromGLenum<GraphicsResetStatus>(GLenum from)
return GraphicsResetStatus::InnocentContextReset;
case GL_UNKNOWN_CONTEXT_RESET:
return GraphicsResetStatus::UnknownContextReset;
case GL_PURGED_CONTEXT_RESET_NV:
return GraphicsResetStatus::PurgedContextResetNV;
default:
return GraphicsResetStatus::InvalidEnum;
}
......@@ -577,6 +579,8 @@ GLenum ToGLenum(GraphicsResetStatus from)
return GL_INNOCENT_CONTEXT_RESET;
case GraphicsResetStatus::UnknownContextReset:
return GL_UNKNOWN_CONTEXT_RESET;
case GraphicsResetStatus::PurgedContextResetNV:
return GL_PURGED_CONTEXT_RESET_NV;
default:
UNREACHABLE();
return 0;
......@@ -599,6 +603,9 @@ std::ostream &operator<<(std::ostream &os, GraphicsResetStatus value)
case GraphicsResetStatus::UnknownContextReset:
os << "GL_UNKNOWN_CONTEXT_RESET";
break;
case GraphicsResetStatus::PurgedContextResetNV:
os << "GL_PURGED_CONTEXT_RESET_NV";
break;
default:
os << "GL_INVALID_ENUM";
break;
......
......@@ -160,9 +160,10 @@ enum class GraphicsResetStatus : uint8_t
GuiltyContextReset = 1,
InnocentContextReset = 2,
UnknownContextReset = 3,
PurgedContextResetNV = 4,
InvalidEnum = 4,
EnumCount = 4,
InvalidEnum = 5,
EnumCount = 5,
};
template <>
......
......@@ -62,7 +62,8 @@
"NoError": "GL_NO_ERROR",
"GuiltyContextReset": "GL_GUILTY_CONTEXT_RESET",
"InnocentContextReset": "GL_INNOCENT_CONTEXT_RESET",
"UnknownContextReset": "GL_UNKNOWN_CONTEXT_RESET"
"UnknownContextReset": "GL_UNKNOWN_CONTEXT_RESET",
"PurgedContextResetNV": "GL_PURGED_CONTEXT_RESET_NV"
},
"HintSetting":
{
......
......@@ -1033,6 +1033,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_EXT_buffer_storage"] = enableableExtension(&Extensions::bufferStorageEXT);
map["GL_OES_texture_stencil8"] = enableableExtension(&Extensions::stencilIndex8);
map["GL_OES_sample_shading"] = enableableExtension(&Extensions::sampleShadingOES);
map["GL_NV_robustness_video_memory_purge"] = esOnlyExtension(&Extensions::robustnessVideoMemoryPurgeNV);
// GLES1 extensions
map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArrayOES);
map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMapOES);
......@@ -1416,6 +1417,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const
InsertExtensionString("EGL_EXT_image_dma_buf_import", imageDmaBufImportEXT, &extensionStrings);
InsertExtensionString("EGL_EXT_image_dma_buf_import_modifiers", imageDmaBufImportModifiersEXT, &extensionStrings);
InsertExtensionString("EGL_NOK_texture_from_pixmap", textureFromPixmapNOK, &extensionStrings);
InsertExtensionString("EGL_NV_robustness_video_memory_purge", robustnessVideoMemoryPurgeNV, &extensionStrings);
// clang-format on
return extensionStrings;
......
......@@ -653,6 +653,9 @@ struct Extensions
// GL_OES_sample_shading
bool sampleShadingOES = false;
// GL_NV_robustness_video_memory_purge
bool robustnessVideoMemoryPurgeNV = false;
};
// Pointer to a boolean memeber of the Extensions struct
......@@ -1116,6 +1119,9 @@ struct DisplayExtensions
// EGL_NOK_texture_from_pixmap
bool textureFromPixmapNOK = false;
// EGL_NV_robustness_video_memory_purge
bool robustnessVideoMemoryPurgeNV = false;
};
struct DeviceExtensions
......
......@@ -3269,6 +3269,11 @@ Extensions Context::generateSupportedExtensions() const
supportedExtensions.eglSyncOES = false;
}
if (mDisplay->getExtensions().robustnessVideoMemoryPurgeNV)
{
supportedExtensions.robustnessVideoMemoryPurgeNV = true;
}
supportedExtensions.memorySize = true;
// GL_CHROMIUM_lose_context is implemented in the frontend
......
......@@ -37,8 +37,11 @@ namespace rx
ContextGL::ContextGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer)
: ContextImpl(state, errorSet), mRenderer(renderer)
const std::shared_ptr<RendererGL> &renderer,
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus)
: ContextImpl(state, errorSet),
mRenderer(renderer),
mRobustnessVideoMemoryPurgeStatus(robustnessVideoMemoryPurgeStatus)
{}
ContextGL::~ContextGL() {}
......@@ -723,7 +726,15 @@ angle::Result ContextGL::multiDrawElementsInstancedBaseVertexBaseInstance(
gl::GraphicsResetStatus ContextGL::getResetStatus()
{
return mRenderer->getResetStatus();
gl::GraphicsResetStatus resetStatus = mRenderer->getResetStatus();
if (resetStatus == gl::GraphicsResetStatus::PurgedContextResetNV)
{
if (mRobustnessVideoMemoryPurgeStatus == RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED)
{
resetStatus = gl::GraphicsResetStatus::UnknownContextReset;
}
}
return resetStatus;
}
std::string ContextGL::getVendorString() const
......
......@@ -31,12 +31,19 @@ class FunctionsGL;
class RendererGL;
class StateManagerGL;
enum class RobustnessVideoMemoryPurgeStatus
{
NOT_REQUESTED = 0,
REQUESTED = 1,
};
class ContextGL : public ContextImpl
{
public:
ContextGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer);
const std::shared_ptr<RendererGL> &renderer,
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus);
~ContextGL() override;
angle::Result initialize() override;
......@@ -284,6 +291,8 @@ class ContextGL : public ContextImpl
protected:
std::shared_ptr<RendererGL> mRenderer;
RobustnessVideoMemoryPurgeStatus mRobustnessVideoMemoryPurgeStatus;
};
} // namespace rx
......
......@@ -21,7 +21,7 @@ ContextCGL::ContextCGL(DisplayCGL *display,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer,
bool usesDiscreteGPU)
: ContextGL(state, errorSet, renderer),
: ContextGL(state, errorSet, renderer, RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED),
mUsesDiscreteGpu(usesDiscreteGPU),
mReleasedDiscreteGpu(false)
{
......
......@@ -20,7 +20,7 @@ namespace rx
ContextEAGL::ContextEAGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer)
: ContextGL(state, errorSet, renderer)
: ContextGL(state, errorSet, renderer, RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED)
{}
} // namespace rx
......@@ -10,8 +10,9 @@ namespace rx
{
ContextEGL::ContextEGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererEGL> &renderer)
: ContextGL(state, errorSet, renderer), mRendererEGL(renderer)
const std::shared_ptr<RendererEGL> &renderer,
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus)
: ContextGL(state, errorSet, renderer, robustnessVideoMemoryPurgeStatus), mRendererEGL(renderer)
{}
ContextEGL::~ContextEGL() {}
......
......@@ -19,7 +19,8 @@ class ContextEGL : public ContextGL
public:
ContextEGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererEGL> &renderer);
const std::shared_ptr<RendererEGL> &renderer,
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus);
~ContextEGL() override;
EGLContext getContext() const;
......
......@@ -27,6 +27,12 @@
namespace
{
rx::RobustnessVideoMemoryPurgeStatus GetRobustnessVideoMemoryPurge(const egl::AttributeMap &attribs)
{
return static_cast<rx::RobustnessVideoMemoryPurgeStatus>(
attribs.get(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_FALSE));
}
EGLint ESBitFromPlatformAttrib(const rx::FunctionsEGL *egl, const EGLAttrib platformAttrib)
{
EGLint esBit = EGL_NONE;
......@@ -103,7 +109,12 @@ namespace rx
{
DisplayEGL::DisplayEGL(const egl::DisplayState &state)
: DisplayGL(state), mRenderer(nullptr), mEGL(nullptr), mConfig(EGL_NO_CONFIG_KHR)
: DisplayGL(state),
mRenderer(nullptr),
mEGL(nullptr),
mConfig(EGL_NO_CONFIG_KHR),
mHasEXTCreateContextRobustness(false),
mHasNVRobustnessVideoMemoryPurge(false)
{}
DisplayEGL::~DisplayEGL() {}
......@@ -152,7 +163,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
if (initializeRequested)
{
contextAttribLists.push_back({EGL_CONTEXT_MAJOR_VERSION, requestedMajor,
EGL_CONTEXT_MINOR_VERSION, requestedMinor, EGL_NONE});
EGL_CONTEXT_MINOR_VERSION, requestedMinor});
}
else
{
......@@ -169,7 +180,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
{
contextAttribLists.push_back(
{EGL_CONTEXT_MAJOR_VERSION, static_cast<EGLint>(version.major),
EGL_CONTEXT_MINOR_VERSION, static_cast<EGLint>(version.minor), EGL_NONE});
EGL_CONTEXT_MINOR_VERSION, static_cast<EGLint>(version.minor)});
}
}
}
......@@ -179,12 +190,23 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
{
return egl::EglBadAttribute() << "Unsupported requested context version";
}
contextAttribLists.push_back({EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE});
contextAttribLists.push_back({EGL_CONTEXT_CLIENT_VERSION, 2});
}
EGLContext context = EGL_NO_CONTEXT;
for (const auto &attribList : contextAttribLists)
for (auto &attribList : contextAttribLists)
{
if (mHasEXTCreateContextRobustness)
{
attribList.push_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY);
attribList.push_back(EGL_LOSE_CONTEXT_ON_RESET);
if (mHasNVRobustnessVideoMemoryPurge)
{
attribList.push_back(EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
attribList.push_back(GL_TRUE);
}
}
attribList.push_back(EGL_NONE);
context = mEGL->createContext(mConfig, shareContext, attribList.data());
if (context != EGL_NO_CONTEXT)
{
......@@ -227,6 +249,9 @@ egl::Error DisplayEGL::initialize(egl::Display *display)
}
}
mHasEXTCreateContextRobustness = mEGL->hasExtension("EGL_EXT_create_context_robustness");
mHasNVRobustnessVideoMemoryPurge = mEGL->hasExtension("EGL_NV_robustness_video_memory_purge");
const EGLAttrib platformAttrib = mDisplayAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, 0);
EGLint esBit = ESBitFromPlatformAttrib(mEGL, platformAttrib);
if (esBit == EGL_NONE)
......@@ -356,7 +381,9 @@ ContextImpl *DisplayEGL::createContext(const gl::State &state,
return nullptr;
}
return new ContextEGL(state, errorSet, renderer);
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus =
GetRobustnessVideoMemoryPurge(attribs);
return new ContextEGL(state, errorSet, renderer, robustnessVideoMemoryPurgeStatus);
}
template <typename T>
......@@ -683,6 +710,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->imageDmaBufImportModifiersEXT =
mEGL->hasExtension("EGL_EXT_image_dma_buf_import_modifiers");
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
DisplayGL::generateExtensions(outExtensions);
}
......
......@@ -141,6 +141,9 @@ class DisplayEGL : public DisplayGL
void generateCaps(egl::Caps *outCaps) const override;
std::map<EGLint, EGLint> mConfigIds;
bool mHasEXTCreateContextRobustness;
bool mHasNVRobustnessVideoMemoryPurge;
};
} // namespace rx
......
......@@ -229,7 +229,8 @@ ContextImpl *DisplayAndroid::createContext(const gl::State &state,
}
}
return new ContextEGL(state, errorSet, renderer);
return new ContextEGL(state, errorSet, renderer,
RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED);
}
bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
......
......@@ -912,7 +912,8 @@ ContextImpl *DisplayGbm::createContext(const gl::State &state,
const egl::AttributeMap &attribs)
{
// All contexts on Gbm are virtualized and share the same renderer.
return new ContextEGL(state, errorSet, mRenderer);
return new ContextEGL(state, errorSet, mRenderer,
RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED);
}
egl::Error DisplayGbm::makeCurrent(egl::Display *display,
......
......@@ -29,6 +29,12 @@
namespace
{
rx::RobustnessVideoMemoryPurgeStatus GetRobustnessVideoMemoryPurge(const egl::AttributeMap &attribs)
{
return static_cast<rx::RobustnessVideoMemoryPurgeStatus>(
attribs.get(GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_FALSE));
}
bool HasParallelShaderCompileExtension(const rx::FunctionsGL *functions)
{
return functions->maxShaderCompilerThreadsKHR != nullptr ||
......@@ -76,6 +82,7 @@ DisplayGLX::DisplayGLX(const egl::DisplayState &state)
mHasARBCreateContextProfile(false),
mHasARBCreateContextRobustness(false),
mHasEXTCreateContextES2Profile(false),
mHasNVRobustnessVideoMemoryPurge(false),
mSwapControl(SwapControl::Absent),
mMinSwapInterval(0),
mMaxSwapInterval(0),
......@@ -115,8 +122,9 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
mHasMultisample = mGLX.minorVersion > 3 || mGLX.hasExtension("GLX_ARB_multisample");
mHasARBCreateContext = mGLX.hasExtension("GLX_ARB_create_context");
mHasARBCreateContextProfile = mGLX.hasExtension("GLX_ARB_create_context_profile");
mHasARBCreateContextRobustness = mGLX.hasExtension("GLX_ARB_create_context_robustness");
mHasEXTCreateContextES2Profile = mGLX.hasExtension("GLX_EXT_create_context_es2_profile");
mHasARBCreateContextRobustness = mGLX.hasExtension("GLX_ARB_create_context_robustness");
mHasEXTCreateContextES2Profile = mGLX.hasExtension("GLX_EXT_create_context_es2_profile");
mHasNVRobustnessVideoMemoryPurge = mGLX.hasExtension("GLX_NV_robustness_video_memory_purge");
std::string clientVendor = mGLX.getClientString(GLX_VENDOR);
mIsMesa = clientVendor.find("Mesa") != std::string::npos;
......@@ -285,7 +293,14 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLGLX(mGLX.getProc));
functionsGL->initialize(eglAttributes);
if (mHasNVRobustnessVideoMemoryPurge)
{
GLenum status = functionsGL->getGraphicsResetStatus();
if (status != GL_NO_ERROR && status != GL_PURGED_CONTEXT_RESET_NV)
{
return egl::EglNotInitialized() << "Context lost for unknown reason.";
}
}
// TODO(cwallez, angleproject:1303) Disable the OpenGL ES backend on Linux NVIDIA and Intel as
// it has problems on our automated testing. An OpenGL ES backend might not trigger this test if
// there is no Desktop OpenGL support, but that's not the case in our automated testing.
......@@ -475,7 +490,9 @@ ContextImpl *DisplayGLX::createContext(const gl::State &state,
const gl::Context *shareContext,
const egl::AttributeMap &attribs)
{
return new ContextGL(state, errorSet, mRenderer);
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus =
GetRobustnessVideoMemoryPurge(attribs);
return new ContextGL(state, errorSet, mRenderer, robustnessVideoMemoryPurgeStatus);
}
DeviceImpl *DisplayGLX::createDevice()
......@@ -895,6 +912,8 @@ void DisplayGLX::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->textureFromPixmapNOK = mGLX.hasExtension("GLX_EXT_texture_from_pixmap");
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
DisplayGL::generateExtensions(outExtensions);
}
......@@ -930,6 +949,11 @@ egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
mAttribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
mAttribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
mAttribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
if (mHasNVRobustnessVideoMemoryPurge)
{
mAttribs.push_back(GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
mAttribs.push_back(GL_TRUE);
}
}
if (version.valid())
......
......@@ -140,6 +140,7 @@ class DisplayGLX : public DisplayGL
bool mHasARBCreateContextProfile;
bool mHasARBCreateContextRobustness;
bool mHasEXTCreateContextES2Profile;
bool mHasNVRobustnessVideoMemoryPurge;
enum class SwapControl
{
......
......@@ -163,6 +163,10 @@
// GLX_EXT_swap_control
# define GLX_SWAP_INTERVAL_EXT 0x20F1
# define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
// GLX_NV_robustness_video_memory_purge
# define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
#endif // !defined(ANGLE_SKIP_GLX_DEFINES)
// GLX typedefs depend on the X headers
......
......@@ -11,7 +11,8 @@ namespace rx
ContextWGL::ContextWGL(const gl::State &state,
gl::ErrorSet *errorSet,
const std::shared_ptr<RendererWGL> &renderer)
: ContextGL(state, errorSet, renderer), mRendererWGL(renderer)
: ContextGL(state, errorSet, renderer, RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED),
mRendererWGL(renderer)
{}
ContextWGL::~ContextWGL() {}
......
......@@ -1405,6 +1405,20 @@ Error ValidateCreateContext(Display *display,
}
break;
case EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV:
if (!display->getExtensions().robustnessVideoMemoryPurgeNV)
{
return EglBadAttribute()
<< "Attribute EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV requires "
"extension EGL_NV_robustness_video_memory_purge.";
}
if (value != EGL_TRUE && value != EGL_FALSE)
{
return EglBadAttribute() << "EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV must "
"be either EGL_TRUE or EGL_FALSE.";
}
break;
default:
return EglBadAttribute() << "Unknown attribute.";
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment