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, ...@@ -554,6 +554,11 @@ GL_APICALL void GL_APIENTRY glImportSemaphoreZirconHandleANGLE(GLuint memory,
#define GL_TEXTURE_FILTERING_HINT_CHROMIUM 0x8AF0 #define GL_TEXTURE_FILTERING_HINT_CHROMIUM 0x8AF0
#endif /* GL_CHROMIUM_texture_filtering_hint */ #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 // clang-format on
#endif // INCLUDE_GLES2_GL2EXT_ANGLE_H_ #endif // INCLUDE_GLES2_GL2EXT_ANGLE_H_
...@@ -4,13 +4,13 @@ ...@@ -4,13 +4,13 @@
"src/common/PackedEGLEnums_autogen.h": "src/common/PackedEGLEnums_autogen.h":
"085d82d2003f02345abc4986523127d4", "085d82d2003f02345abc4986523127d4",
"src/common/PackedGLEnums_autogen.cpp": "src/common/PackedGLEnums_autogen.cpp":
"dfd979452806f59fff27dde8ffe8e300", "2a02645fb791fc9379885d4ff3af0de4",
"src/common/PackedGLEnums_autogen.h": "src/common/PackedGLEnums_autogen.h":
"8466493b646665844ac579e997ebb6ca", "d7b5d92d1b44d7b2e6684c81d316a165",
"src/common/gen_packed_gl_enums.py": "src/common/gen_packed_gl_enums.py":
"b3e96ea44f52ec23ee893bd843dfd2cb", "b3e96ea44f52ec23ee893bd843dfd2cb",
"src/common/packed_egl_enums.json": "src/common/packed_egl_enums.json":
"76e1b814421e121164d60a0d89cb16c1", "76e1b814421e121164d60a0d89cb16c1",
"src/common/packed_gl_enums.json": "src/common/packed_gl_enums.json":
"5ed701940bc80450631f8886d585ef8a" "2663ff32de3d8b3b848e6853f5e5eb24"
} }
\ No newline at end of file
...@@ -560,6 +560,8 @@ GraphicsResetStatus FromGLenum<GraphicsResetStatus>(GLenum from) ...@@ -560,6 +560,8 @@ GraphicsResetStatus FromGLenum<GraphicsResetStatus>(GLenum from)
return GraphicsResetStatus::InnocentContextReset; return GraphicsResetStatus::InnocentContextReset;
case GL_UNKNOWN_CONTEXT_RESET: case GL_UNKNOWN_CONTEXT_RESET:
return GraphicsResetStatus::UnknownContextReset; return GraphicsResetStatus::UnknownContextReset;
case GL_PURGED_CONTEXT_RESET_NV:
return GraphicsResetStatus::PurgedContextResetNV;
default: default:
return GraphicsResetStatus::InvalidEnum; return GraphicsResetStatus::InvalidEnum;
} }
...@@ -577,6 +579,8 @@ GLenum ToGLenum(GraphicsResetStatus from) ...@@ -577,6 +579,8 @@ GLenum ToGLenum(GraphicsResetStatus from)
return GL_INNOCENT_CONTEXT_RESET; return GL_INNOCENT_CONTEXT_RESET;
case GraphicsResetStatus::UnknownContextReset: case GraphicsResetStatus::UnknownContextReset:
return GL_UNKNOWN_CONTEXT_RESET; return GL_UNKNOWN_CONTEXT_RESET;
case GraphicsResetStatus::PurgedContextResetNV:
return GL_PURGED_CONTEXT_RESET_NV;
default: default:
UNREACHABLE(); UNREACHABLE();
return 0; return 0;
...@@ -599,6 +603,9 @@ std::ostream &operator<<(std::ostream &os, GraphicsResetStatus value) ...@@ -599,6 +603,9 @@ std::ostream &operator<<(std::ostream &os, GraphicsResetStatus value)
case GraphicsResetStatus::UnknownContextReset: case GraphicsResetStatus::UnknownContextReset:
os << "GL_UNKNOWN_CONTEXT_RESET"; os << "GL_UNKNOWN_CONTEXT_RESET";
break; break;
case GraphicsResetStatus::PurgedContextResetNV:
os << "GL_PURGED_CONTEXT_RESET_NV";
break;
default: default:
os << "GL_INVALID_ENUM"; os << "GL_INVALID_ENUM";
break; break;
......
...@@ -160,9 +160,10 @@ enum class GraphicsResetStatus : uint8_t ...@@ -160,9 +160,10 @@ enum class GraphicsResetStatus : uint8_t
GuiltyContextReset = 1, GuiltyContextReset = 1,
InnocentContextReset = 2, InnocentContextReset = 2,
UnknownContextReset = 3, UnknownContextReset = 3,
PurgedContextResetNV = 4,
InvalidEnum = 4, InvalidEnum = 5,
EnumCount = 4, EnumCount = 5,
}; };
template <> template <>
......
...@@ -62,7 +62,8 @@ ...@@ -62,7 +62,8 @@
"NoError": "GL_NO_ERROR", "NoError": "GL_NO_ERROR",
"GuiltyContextReset": "GL_GUILTY_CONTEXT_RESET", "GuiltyContextReset": "GL_GUILTY_CONTEXT_RESET",
"InnocentContextReset": "GL_INNOCENT_CONTEXT_RESET", "InnocentContextReset": "GL_INNOCENT_CONTEXT_RESET",
"UnknownContextReset": "GL_UNKNOWN_CONTEXT_RESET" "UnknownContextReset": "GL_UNKNOWN_CONTEXT_RESET",
"PurgedContextResetNV": "GL_PURGED_CONTEXT_RESET_NV"
}, },
"HintSetting": "HintSetting":
{ {
......
...@@ -1033,6 +1033,7 @@ const ExtensionInfoMap &GetExtensionInfoMap() ...@@ -1033,6 +1033,7 @@ const ExtensionInfoMap &GetExtensionInfoMap()
map["GL_EXT_buffer_storage"] = enableableExtension(&Extensions::bufferStorageEXT); map["GL_EXT_buffer_storage"] = enableableExtension(&Extensions::bufferStorageEXT);
map["GL_OES_texture_stencil8"] = enableableExtension(&Extensions::stencilIndex8); map["GL_OES_texture_stencil8"] = enableableExtension(&Extensions::stencilIndex8);
map["GL_OES_sample_shading"] = enableableExtension(&Extensions::sampleShadingOES); map["GL_OES_sample_shading"] = enableableExtension(&Extensions::sampleShadingOES);
map["GL_NV_robustness_video_memory_purge"] = esOnlyExtension(&Extensions::robustnessVideoMemoryPurgeNV);
// GLES1 extensions // GLES1 extensions
map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArrayOES); map["GL_OES_point_size_array"] = enableableExtension(&Extensions::pointSizeArrayOES);
map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMapOES); map["GL_OES_texture_cube_map"] = enableableExtension(&Extensions::textureCubeMapOES);
...@@ -1416,6 +1417,7 @@ std::vector<std::string> DisplayExtensions::getStrings() const ...@@ -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", imageDmaBufImportEXT, &extensionStrings);
InsertExtensionString("EGL_EXT_image_dma_buf_import_modifiers", imageDmaBufImportModifiersEXT, &extensionStrings); InsertExtensionString("EGL_EXT_image_dma_buf_import_modifiers", imageDmaBufImportModifiersEXT, &extensionStrings);
InsertExtensionString("EGL_NOK_texture_from_pixmap", textureFromPixmapNOK, &extensionStrings); InsertExtensionString("EGL_NOK_texture_from_pixmap", textureFromPixmapNOK, &extensionStrings);
InsertExtensionString("EGL_NV_robustness_video_memory_purge", robustnessVideoMemoryPurgeNV, &extensionStrings);
// clang-format on // clang-format on
return extensionStrings; return extensionStrings;
......
...@@ -653,6 +653,9 @@ struct Extensions ...@@ -653,6 +653,9 @@ struct Extensions
// GL_OES_sample_shading // GL_OES_sample_shading
bool sampleShadingOES = false; bool sampleShadingOES = false;
// GL_NV_robustness_video_memory_purge
bool robustnessVideoMemoryPurgeNV = false;
}; };
// Pointer to a boolean memeber of the Extensions struct // Pointer to a boolean memeber of the Extensions struct
...@@ -1116,6 +1119,9 @@ struct DisplayExtensions ...@@ -1116,6 +1119,9 @@ struct DisplayExtensions
// EGL_NOK_texture_from_pixmap // EGL_NOK_texture_from_pixmap
bool textureFromPixmapNOK = false; bool textureFromPixmapNOK = false;
// EGL_NV_robustness_video_memory_purge
bool robustnessVideoMemoryPurgeNV = false;
}; };
struct DeviceExtensions struct DeviceExtensions
......
...@@ -3269,6 +3269,11 @@ Extensions Context::generateSupportedExtensions() const ...@@ -3269,6 +3269,11 @@ Extensions Context::generateSupportedExtensions() const
supportedExtensions.eglSyncOES = false; supportedExtensions.eglSyncOES = false;
} }
if (mDisplay->getExtensions().robustnessVideoMemoryPurgeNV)
{
supportedExtensions.robustnessVideoMemoryPurgeNV = true;
}
supportedExtensions.memorySize = true; supportedExtensions.memorySize = true;
// GL_CHROMIUM_lose_context is implemented in the frontend // GL_CHROMIUM_lose_context is implemented in the frontend
......
...@@ -37,8 +37,11 @@ namespace rx ...@@ -37,8 +37,11 @@ namespace rx
ContextGL::ContextGL(const gl::State &state, ContextGL::ContextGL(const gl::State &state,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer) const std::shared_ptr<RendererGL> &renderer,
: ContextImpl(state, errorSet), mRenderer(renderer) RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus)
: ContextImpl(state, errorSet),
mRenderer(renderer),
mRobustnessVideoMemoryPurgeStatus(robustnessVideoMemoryPurgeStatus)
{} {}
ContextGL::~ContextGL() {} ContextGL::~ContextGL() {}
...@@ -723,7 +726,15 @@ angle::Result ContextGL::multiDrawElementsInstancedBaseVertexBaseInstance( ...@@ -723,7 +726,15 @@ angle::Result ContextGL::multiDrawElementsInstancedBaseVertexBaseInstance(
gl::GraphicsResetStatus ContextGL::getResetStatus() 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 std::string ContextGL::getVendorString() const
......
...@@ -31,12 +31,19 @@ class FunctionsGL; ...@@ -31,12 +31,19 @@ class FunctionsGL;
class RendererGL; class RendererGL;
class StateManagerGL; class StateManagerGL;
enum class RobustnessVideoMemoryPurgeStatus
{
NOT_REQUESTED = 0,
REQUESTED = 1,
};
class ContextGL : public ContextImpl class ContextGL : public ContextImpl
{ {
public: public:
ContextGL(const gl::State &state, ContextGL(const gl::State &state,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer); const std::shared_ptr<RendererGL> &renderer,
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus);
~ContextGL() override; ~ContextGL() override;
angle::Result initialize() override; angle::Result initialize() override;
...@@ -284,6 +291,8 @@ class ContextGL : public ContextImpl ...@@ -284,6 +291,8 @@ class ContextGL : public ContextImpl
protected: protected:
std::shared_ptr<RendererGL> mRenderer; std::shared_ptr<RendererGL> mRenderer;
RobustnessVideoMemoryPurgeStatus mRobustnessVideoMemoryPurgeStatus;
}; };
} // namespace rx } // namespace rx
......
...@@ -21,7 +21,7 @@ ContextCGL::ContextCGL(DisplayCGL *display, ...@@ -21,7 +21,7 @@ ContextCGL::ContextCGL(DisplayCGL *display,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer, const std::shared_ptr<RendererGL> &renderer,
bool usesDiscreteGPU) bool usesDiscreteGPU)
: ContextGL(state, errorSet, renderer), : ContextGL(state, errorSet, renderer, RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED),
mUsesDiscreteGpu(usesDiscreteGPU), mUsesDiscreteGpu(usesDiscreteGPU),
mReleasedDiscreteGpu(false) mReleasedDiscreteGpu(false)
{ {
......
...@@ -20,7 +20,7 @@ namespace rx ...@@ -20,7 +20,7 @@ namespace rx
ContextEAGL::ContextEAGL(const gl::State &state, ContextEAGL::ContextEAGL(const gl::State &state,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererGL> &renderer) const std::shared_ptr<RendererGL> &renderer)
: ContextGL(state, errorSet, renderer) : ContextGL(state, errorSet, renderer, RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED)
{} {}
} // namespace rx } // namespace rx
...@@ -10,8 +10,9 @@ namespace rx ...@@ -10,8 +10,9 @@ namespace rx
{ {
ContextEGL::ContextEGL(const gl::State &state, ContextEGL::ContextEGL(const gl::State &state,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererEGL> &renderer) const std::shared_ptr<RendererEGL> &renderer,
: ContextGL(state, errorSet, renderer), mRendererEGL(renderer) RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus)
: ContextGL(state, errorSet, renderer, robustnessVideoMemoryPurgeStatus), mRendererEGL(renderer)
{} {}
ContextEGL::~ContextEGL() {} ContextEGL::~ContextEGL() {}
......
...@@ -19,7 +19,8 @@ class ContextEGL : public ContextGL ...@@ -19,7 +19,8 @@ class ContextEGL : public ContextGL
public: public:
ContextEGL(const gl::State &state, ContextEGL(const gl::State &state,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererEGL> &renderer); const std::shared_ptr<RendererEGL> &renderer,
RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus);
~ContextEGL() override; ~ContextEGL() override;
EGLContext getContext() const; EGLContext getContext() const;
......
...@@ -27,6 +27,12 @@ ...@@ -27,6 +27,12 @@
namespace 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 ESBitFromPlatformAttrib(const rx::FunctionsEGL *egl, const EGLAttrib platformAttrib)
{ {
EGLint esBit = EGL_NONE; EGLint esBit = EGL_NONE;
...@@ -103,7 +109,12 @@ namespace rx ...@@ -103,7 +109,12 @@ namespace rx
{ {
DisplayEGL::DisplayEGL(const egl::DisplayState &state) 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() {} DisplayEGL::~DisplayEGL() {}
...@@ -152,7 +163,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -152,7 +163,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
if (initializeRequested) if (initializeRequested)
{ {
contextAttribLists.push_back({EGL_CONTEXT_MAJOR_VERSION, requestedMajor, contextAttribLists.push_back({EGL_CONTEXT_MAJOR_VERSION, requestedMajor,
EGL_CONTEXT_MINOR_VERSION, requestedMinor, EGL_NONE}); EGL_CONTEXT_MINOR_VERSION, requestedMinor});
} }
else else
{ {
...@@ -169,7 +180,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext, ...@@ -169,7 +180,7 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
{ {
contextAttribLists.push_back( contextAttribLists.push_back(
{EGL_CONTEXT_MAJOR_VERSION, static_cast<EGLint>(version.major), {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, ...@@ -179,12 +190,23 @@ egl::Error DisplayEGL::initializeContext(EGLContext shareContext,
{ {
return egl::EglBadAttribute() << "Unsupported requested context version"; 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; 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()); context = mEGL->createContext(mConfig, shareContext, attribList.data());
if (context != EGL_NO_CONTEXT) if (context != EGL_NO_CONTEXT)
{ {
...@@ -227,6 +249,9 @@ egl::Error DisplayEGL::initialize(egl::Display *display) ...@@ -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); const EGLAttrib platformAttrib = mDisplayAttributes.get(EGL_PLATFORM_ANGLE_TYPE_ANGLE, 0);
EGLint esBit = ESBitFromPlatformAttrib(mEGL, platformAttrib); EGLint esBit = ESBitFromPlatformAttrib(mEGL, platformAttrib);
if (esBit == EGL_NONE) if (esBit == EGL_NONE)
...@@ -356,7 +381,9 @@ ContextImpl *DisplayEGL::createContext(const gl::State &state, ...@@ -356,7 +381,9 @@ ContextImpl *DisplayEGL::createContext(const gl::State &state,
return nullptr; return nullptr;
} }
return new ContextEGL(state, errorSet, renderer); RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus =
GetRobustnessVideoMemoryPurge(attribs);
return new ContextEGL(state, errorSet, renderer, robustnessVideoMemoryPurgeStatus);
} }
template <typename T> template <typename T>
...@@ -683,6 +710,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -683,6 +710,8 @@ void DisplayEGL::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->imageDmaBufImportModifiersEXT = outExtensions->imageDmaBufImportModifiersEXT =
mEGL->hasExtension("EGL_EXT_image_dma_buf_import_modifiers"); mEGL->hasExtension("EGL_EXT_image_dma_buf_import_modifiers");
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
DisplayGL::generateExtensions(outExtensions); DisplayGL::generateExtensions(outExtensions);
} }
......
...@@ -141,6 +141,9 @@ class DisplayEGL : public DisplayGL ...@@ -141,6 +141,9 @@ class DisplayEGL : public DisplayGL
void generateCaps(egl::Caps *outCaps) const override; void generateCaps(egl::Caps *outCaps) const override;
std::map<EGLint, EGLint> mConfigIds; std::map<EGLint, EGLint> mConfigIds;
bool mHasEXTCreateContextRobustness;
bool mHasNVRobustnessVideoMemoryPurge;
}; };
} // namespace rx } // namespace rx
......
...@@ -229,7 +229,8 @@ ContextImpl *DisplayAndroid::createContext(const gl::State &state, ...@@ -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 bool DisplayAndroid::isValidNativeWindow(EGLNativeWindowType window) const
......
...@@ -912,7 +912,8 @@ ContextImpl *DisplayGbm::createContext(const gl::State &state, ...@@ -912,7 +912,8 @@ ContextImpl *DisplayGbm::createContext(const gl::State &state,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
// All contexts on Gbm are virtualized and share the same renderer. // 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, egl::Error DisplayGbm::makeCurrent(egl::Display *display,
......
...@@ -29,6 +29,12 @@ ...@@ -29,6 +29,12 @@
namespace 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) bool HasParallelShaderCompileExtension(const rx::FunctionsGL *functions)
{ {
return functions->maxShaderCompilerThreadsKHR != nullptr || return functions->maxShaderCompilerThreadsKHR != nullptr ||
...@@ -76,6 +82,7 @@ DisplayGLX::DisplayGLX(const egl::DisplayState &state) ...@@ -76,6 +82,7 @@ DisplayGLX::DisplayGLX(const egl::DisplayState &state)
mHasARBCreateContextProfile(false), mHasARBCreateContextProfile(false),
mHasARBCreateContextRobustness(false), mHasARBCreateContextRobustness(false),
mHasEXTCreateContextES2Profile(false), mHasEXTCreateContextES2Profile(false),
mHasNVRobustnessVideoMemoryPurge(false),
mSwapControl(SwapControl::Absent), mSwapControl(SwapControl::Absent),
mMinSwapInterval(0), mMinSwapInterval(0),
mMaxSwapInterval(0), mMaxSwapInterval(0),
...@@ -115,8 +122,9 @@ egl::Error DisplayGLX::initialize(egl::Display *display) ...@@ -115,8 +122,9 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
mHasMultisample = mGLX.minorVersion > 3 || mGLX.hasExtension("GLX_ARB_multisample"); mHasMultisample = mGLX.minorVersion > 3 || mGLX.hasExtension("GLX_ARB_multisample");
mHasARBCreateContext = mGLX.hasExtension("GLX_ARB_create_context"); mHasARBCreateContext = mGLX.hasExtension("GLX_ARB_create_context");
mHasARBCreateContextProfile = mGLX.hasExtension("GLX_ARB_create_context_profile"); mHasARBCreateContextProfile = mGLX.hasExtension("GLX_ARB_create_context_profile");
mHasARBCreateContextRobustness = mGLX.hasExtension("GLX_ARB_create_context_robustness"); mHasARBCreateContextRobustness = mGLX.hasExtension("GLX_ARB_create_context_robustness");
mHasEXTCreateContextES2Profile = mGLX.hasExtension("GLX_EXT_create_context_es2_profile"); 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); std::string clientVendor = mGLX.getClientString(GLX_VENDOR);
mIsMesa = clientVendor.find("Mesa") != std::string::npos; mIsMesa = clientVendor.find("Mesa") != std::string::npos;
...@@ -285,7 +293,14 @@ egl::Error DisplayGLX::initialize(egl::Display *display) ...@@ -285,7 +293,14 @@ egl::Error DisplayGLX::initialize(egl::Display *display)
std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLGLX(mGLX.getProc)); std::unique_ptr<FunctionsGL> functionsGL(new FunctionsGLGLX(mGLX.getProc));
functionsGL->initialize(eglAttributes); 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 // 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 // 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. // 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, ...@@ -475,7 +490,9 @@ ContextImpl *DisplayGLX::createContext(const gl::State &state,
const gl::Context *shareContext, const gl::Context *shareContext,
const egl::AttributeMap &attribs) const egl::AttributeMap &attribs)
{ {
return new ContextGL(state, errorSet, mRenderer); RobustnessVideoMemoryPurgeStatus robustnessVideoMemoryPurgeStatus =
GetRobustnessVideoMemoryPurge(attribs);
return new ContextGL(state, errorSet, mRenderer, robustnessVideoMemoryPurgeStatus);
} }
DeviceImpl *DisplayGLX::createDevice() DeviceImpl *DisplayGLX::createDevice()
...@@ -895,6 +912,8 @@ void DisplayGLX::generateExtensions(egl::DisplayExtensions *outExtensions) const ...@@ -895,6 +912,8 @@ void DisplayGLX::generateExtensions(egl::DisplayExtensions *outExtensions) const
outExtensions->textureFromPixmapNOK = mGLX.hasExtension("GLX_EXT_texture_from_pixmap"); outExtensions->textureFromPixmapNOK = mGLX.hasExtension("GLX_EXT_texture_from_pixmap");
outExtensions->robustnessVideoMemoryPurgeNV = mHasNVRobustnessVideoMemoryPurge;
DisplayGL::generateExtensions(outExtensions); DisplayGL::generateExtensions(outExtensions);
} }
...@@ -930,6 +949,11 @@ egl::Error DisplayGLX::createContextAttribs(glx::FBConfig, ...@@ -930,6 +949,11 @@ egl::Error DisplayGLX::createContextAttribs(glx::FBConfig,
mAttribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB); mAttribs.push_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
mAttribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB); mAttribs.push_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
mAttribs.push_back(GLX_LOSE_CONTEXT_ON_RESET_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()) if (version.valid())
......
...@@ -140,6 +140,7 @@ class DisplayGLX : public DisplayGL ...@@ -140,6 +140,7 @@ class DisplayGLX : public DisplayGL
bool mHasARBCreateContextProfile; bool mHasARBCreateContextProfile;
bool mHasARBCreateContextRobustness; bool mHasARBCreateContextRobustness;
bool mHasEXTCreateContextES2Profile; bool mHasEXTCreateContextES2Profile;
bool mHasNVRobustnessVideoMemoryPurge;
enum class SwapControl enum class SwapControl
{ {
......
...@@ -163,6 +163,10 @@ ...@@ -163,6 +163,10 @@
// GLX_EXT_swap_control // GLX_EXT_swap_control
# define GLX_SWAP_INTERVAL_EXT 0x20F1 # define GLX_SWAP_INTERVAL_EXT 0x20F1
# define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2 # 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) #endif // !defined(ANGLE_SKIP_GLX_DEFINES)
// GLX typedefs depend on the X headers // GLX typedefs depend on the X headers
......
...@@ -11,7 +11,8 @@ namespace rx ...@@ -11,7 +11,8 @@ namespace rx
ContextWGL::ContextWGL(const gl::State &state, ContextWGL::ContextWGL(const gl::State &state,
gl::ErrorSet *errorSet, gl::ErrorSet *errorSet,
const std::shared_ptr<RendererWGL> &renderer) const std::shared_ptr<RendererWGL> &renderer)
: ContextGL(state, errorSet, renderer), mRendererWGL(renderer) : ContextGL(state, errorSet, renderer, RobustnessVideoMemoryPurgeStatus::NOT_REQUESTED),
mRendererWGL(renderer)
{} {}
ContextWGL::~ContextWGL() {} ContextWGL::~ContextWGL() {}
......
...@@ -1405,6 +1405,20 @@ Error ValidateCreateContext(Display *display, ...@@ -1405,6 +1405,20 @@ Error ValidateCreateContext(Display *display,
} }
break; 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: default:
return EglBadAttribute() << "Unknown attribute."; 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