From ee54df0311516b07d04ada71c6c5e81827cb0b38 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 15 Feb 2018 02:01:39 +0000 Subject: Support GLX_NV_robustness_video_memory_purge in XCB-GLX Nvidia doesn't handle suspend very well in Linux and textures get corrupted. To handle this Nvidia has a bespoke extension to query when this has happened. This patch checks if graphics have been reset and invalidates the surface. Task-number: QTBUG-56610 Change-Id: I0b97d539ce6cc2b9cfe41c71bf6efd4f68496cd6 Reviewed-by: Laszlo Agocs --- .../gl_integrations/xcb_glx/qglxintegration.cpp | 64 +++++++++++++++++++--- .../xcb/gl_integrations/xcb_glx/qglxintegration.h | 2 + 2 files changed, 58 insertions(+), 8 deletions(-) (limited to 'src/plugins/platforms/xcb') diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 21024385b0..86ca7afa12 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -86,6 +86,22 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC #define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 #endif +#ifndef GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB +#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004 +#endif + +#ifndef GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB +#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256 +#endif + +#ifndef GLX_LOSE_CONTEXT_ON_RESET_ARB +#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252 +#endif + +#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV +#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7 +#endif + static Window createDummyWindow(Display *dpy, XVisualInfo *visualInfo, int screenNumber, Window rootWin) { Colormap cmap = XCreateColormap(dpy, rootWin, visualInfo->visual, AllocNone); @@ -179,6 +195,8 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat , m_isPBufferCurrent(false) , m_swapInterval(-1) , m_ownsContext(nativeHandle.isNull()) + , m_getGraphicsResetStatus(0) + , m_lost(false) { if (nativeHandle.isNull()) init(screen, share); @@ -214,6 +232,8 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB"); const bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile"); + const bool supportsRobustness = glxExt.contains("GLX_ARB_create_context_robustness"); + const bool supportsVideoMemoryPurge = glxExt.contains("GLX_NV_robustness_video_memory_purge"); // Use glXCreateContextAttribsARB if available // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile @@ -266,6 +286,9 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) int flags = 0; + if (supportsRobustness) + flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB; + if (m_format.testOption(QSurfaceFormat::DebugContext)) flags |= GLX_CONTEXT_DEBUG_BIT_ARB; @@ -279,14 +302,33 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share) contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_ES2_PROFILE_BIT_EXT; } - contextAttributes << None; + if (supportsRobustness && supportsVideoMemoryPurge) { + QVector contextAttributesWithNvidiaReset = contextAttributes; + + contextAttributesWithNvidiaReset << GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB << GLX_LOSE_CONTEXT_ON_RESET_ARB; + contextAttributesWithNvidiaReset << GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV << GL_TRUE; - m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true, contextAttributes.data()); - if (!m_context && m_shareContext) { - // re-try without a shared glx context - m_context = glXCreateContextAttribsARB(m_display, config, 0, true, contextAttributes.data()); - if (m_context) - m_shareContext = 0; + contextAttributesWithNvidiaReset << None; + m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true, contextAttributesWithNvidiaReset.data()); + if (!m_context && m_shareContext) { + // re-try without a shared glx context + m_context = glXCreateContextAttribsARB(m_display, config, 0, true, contextAttributesWithNvidiaReset.data()); + if (m_context) + m_shareContext = 0; + } + } + + if (m_context) { + m_getGraphicsResetStatus = reinterpret_cast(getProcAddress("glGetGraphicsResetStatusARB")); + } else { + contextAttributes << None; + m_context = glXCreateContextAttribsARB(m_display, config, m_shareContext, true, contextAttributes.data()); + if (!m_context && m_shareContext) { + // re-try without a shared glx context + m_context = glXCreateContextAttribsARB(m_display, config, 0, true, contextAttributes.data()); + if (m_context) + m_shareContext = 0; + } } } } @@ -494,6 +536,12 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface) QXcbWindow *window = static_cast(surface); glxDrawable = window->xcb_window(); success = glXMakeCurrent(m_display, glxDrawable, m_context); + m_lost = false; + if (m_getGraphicsResetStatus && m_getGraphicsResetStatus() != GL_NO_ERROR) { + m_lost = true; + // Drop the surface. Will recreate on the next makeCurrent. + window->invalidateSurface(); + } } else if (surfaceClass == QSurface::Offscreen) { m_isPBufferCurrent = true; QGLXPbuffer *pbuffer = static_cast(surface); @@ -609,7 +657,7 @@ bool QGLXContext::isSharing() const bool QGLXContext::isValid() const { - return m_context != 0; + return m_context != 0 && !m_lost; } bool QGLXContext::m_queriedDummyContext = false; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h index f6372582db..be9d3f5dcb 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h @@ -89,6 +89,8 @@ private: bool m_isPBufferCurrent; int m_swapInterval; bool m_ownsContext; + GLenum (APIENTRY * m_getGraphicsResetStatus)(); + bool m_lost; static bool m_queriedDummyContext; static bool m_supportsThreading; }; -- cgit v1.2.3