From e445fa45b14ac2b7ab112a4b39748f01e505ac23 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 13 Jan 2015 14:17:41 +0100 Subject: WGL: support reset notifications via GL_ARB_robustness Handling context losses is unavoidable with ANGLE. Introduce some level of support for desktop GL too by making it possible to opt in via a new flag. Support is added for Windows (WGL, opengl32) only for now. In case of Windows with ANGLE setting the flag is not necessary, context losses will be reported regardless. Change-Id: Ic354c1382e876566538c52a4381f7ff328b7477e Reviewed-by: Gunnar Sletta --- src/gui/kernel/qsurfaceformat.cpp | 4 ++ src/gui/kernel/qsurfaceformat.h | 3 +- .../platforms/windows/qwindowsglcontext.cpp | 49 +++++++++++++++++++++- src/plugins/platforms/windows/qwindowsglcontext.h | 4 +- 4 files changed, 57 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index b7f8e375a4..a0dc0acbc3 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -128,6 +128,10 @@ public: \value DeprecatedFunctions Used to request that deprecated functions be included in the OpenGL context profile. If not specified, you should get a forward compatible context without support functionality marked as deprecated. This requires OpenGL version 3.0 or higher. + \value ResetNotification Enables notifications about resets of the OpenGL context. The status is then + queryable via the context's \l{QOpenGLContext::isValid()}{isValid()} function. Note that not setting + this flag does not guarantee that context state loss never occurs. Additionally, some implementations + may choose to report context loss regardless of this flag. */ /*! diff --git a/src/gui/kernel/qsurfaceformat.h b/src/gui/kernel/qsurfaceformat.h index b33f4d1f6b..58013cade6 100644 --- a/src/gui/kernel/qsurfaceformat.h +++ b/src/gui/kernel/qsurfaceformat.h @@ -48,7 +48,8 @@ public: enum FormatOption { StereoBuffers = 0x0001, DebugContext = 0x0002, - DeprecatedFunctions = 0x0004 + DeprecatedFunctions = 0x0004, + ResetNotification = 0x0008 }; Q_DECLARE_FLAGS(FormatOptions, FormatOption) diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 0e3e6826ec..786a662287 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -135,6 +135,10 @@ #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #endif +// Common GL and WGL constants +#define RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#define LOSE_CONTEXT_ON_RESET_ARB 0x8252 + QT_BEGIN_NAMESPACE QWindowsOpengl32DLL QOpenGLStaticContext::opengl32; @@ -747,6 +751,12 @@ static HGLRC createContext(const QOpenGLStaticContext &staticContext, break; } } + + if (format.testOption(QSurfaceFormat::ResetNotification)) { + attributes[attribIndex++] = RESET_NOTIFICATION_STRATEGY_ARB; + attributes[attribIndex++] = LOSE_CONTEXT_ON_RESET_ARB; + } + qCDebug(lcQpaGl) << __FUNCTION__ << "Creating context version" << majorVersion << '.' << minorVersion << attribIndex / 2 << "attributes"; @@ -859,6 +869,10 @@ QWindowsOpenGLContextFormat QWindowsOpenGLContextFormat::current() result.options |= QSurfaceFormat::DeprecatedFunctions; if (value & GL_CONTEXT_FLAG_DEBUG_BIT) result.options |= QSurfaceFormat::DebugContext; + value = 0; + QOpenGLStaticContext::opengl32.glGetIntegerv(RESET_NOTIFICATION_STRATEGY_ARB, &value); + if (value == LOSE_CONTEXT_ON_RESET_ARB) + result.options |= QSurfaceFormat::ResetNotification; if (result.version < 0x0302) return result; // v3.2 onwards: Profiles @@ -1032,7 +1046,9 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, m_pixelFormat(0), m_extensionsUsed(false), m_swapInterval(-1), - m_ownsContext(true) + m_ownsContext(true), + m_getGraphicsResetStatus(0), + m_lost(false) { if (!m_staticContext) // Something went very wrong. Stop here, isValid() will return false. return; @@ -1212,6 +1228,28 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) if (m_staticContext->wglGetSwapInternalExt && obtainedSwapInterval) *obtainedSwapInterval = m_staticContext->wglGetSwapInternalExt(); + bool hasRobustness = false; + if (m_obtainedFormat.majorVersion() < 3) { + const char *exts = (const char *) QOpenGLStaticContext::opengl32.glGetString(GL_EXTENSIONS); + hasRobustness = exts && strstr(exts, "GL_ARB_robustness"); + } else { + typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); + glGetStringi_t glGetStringi = (glGetStringi_t) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"); + if (glGetStringi) { + GLint n = 0; + QOpenGLStaticContext::opengl32.glGetIntegerv(GL_NUM_EXTENSIONS, &n); + for (GLint i = 0; i < n; ++i) { + const char *p = (const char *) glGetStringi(GL_EXTENSIONS, i); + if (p && !strcmp(p, "GL_ARB_robustness")) { + hasRobustness = true; + break; + } + } + } + } + if (hasRobustness) + m_getGraphicsResetStatus = (GLenum (APIENTRY *)()) QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetGraphicsResetStatusARB"); + QOpenGLStaticContext::opengl32.wglMakeCurrent(prevSurface, prevContext); return true; } @@ -1296,7 +1334,16 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) } m_windowContexts.append(newContext); + m_lost = false; bool success = QOpenGLStaticContext::opengl32.wglMakeCurrent(newContext.hdc, newContext.renderingContext); + if (!success) { + if (m_getGraphicsResetStatus && m_getGraphicsResetStatus()) { + m_lost = true; + qCDebug(lcQpaGl) << "makeCurrent(): context loss detected" << this; + // Drop the surface. Will recreate on the next makeCurrent. + window->invalidateSurface(); + } + } // Set the swap interval if (m_staticContext->wglSwapInternalExt) { diff --git a/src/plugins/platforms/windows/qwindowsglcontext.h b/src/plugins/platforms/windows/qwindowsglcontext.h index 5f845f245e..27b0b2e191 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.h +++ b/src/plugins/platforms/windows/qwindowsglcontext.h @@ -232,7 +232,7 @@ public: explicit QWindowsGLContext(QOpenGLStaticContext *staticContext, QOpenGLContext *context); ~QWindowsGLContext(); bool isSharing() const Q_DECL_OVERRIDE { return m_context->shareHandle(); } - bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext; } + bool isValid() const Q_DECL_OVERRIDE { return m_renderingContext && !m_lost; } QSurfaceFormat format() const Q_DECL_OVERRIDE { return m_obtainedFormat; } void swapBuffers(QPlatformSurface *surface) Q_DECL_OVERRIDE; @@ -262,6 +262,8 @@ private: bool m_extensionsUsed; int m_swapInterval; bool m_ownsContext; + GLenum (APIENTRY * m_getGraphicsResetStatus)(); + bool m_lost; }; QT_END_NAMESPACE -- cgit v1.2.3