From 041be646b55840fad424f8da78415e2736b4f761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fredrik=20H=C3=B6glund?= Date: Sun, 19 May 2013 16:45:06 +0200 Subject: [PATCH] kwin: Detect and handle graphics resets Reset compositing when the GL context state has been lost as a result of a graphics reset. --- composite.cpp | 1 + kwin.notifyrc | 5 +++++ scene_opengl.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ scene_opengl.h | 6 ++++++ 4 files changed, 63 insertions(+) diff --git a/composite.cpp b/composite.cpp index d82be84d5b..eddd663c96 100644 --- a/composite.cpp +++ b/composite.cpp @@ -198,6 +198,7 @@ void Compositor::slotCompositingOptionsInitialized() #endif m_scene = SceneOpenGL::createScene(); + connect(m_scene, SIGNAL(resetCompositing()), SLOT(restart())); // TODO: Add 30 second delay to protect against screen freezes as well unsafeConfig.writeEntry(openGLIsUnsafe, false); diff --git a/kwin.notifyrc b/kwin.notifyrc index eda3fc2cf5..fa0b779f5d 100644 --- a/kwin.notifyrc +++ b/kwin.notifyrc @@ -194,3 +194,8 @@ Comment[x-test]=xxAnother application has requested to suspend compositing.xx Comment[zh_CN]=另一个应用程序已经请求中断混成操作。 Comment[zh_TW]=另一個應用程式要求暫停組合效能。 Action=Popup + +[Event/graphicsreset] +Name=Graphics Reset +Comment=A graphics reset event occurred +Action=Popup diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 8ea91aadf4..b79bad60b9 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -46,6 +46,7 @@ along with this program. If not, see . #include "workspace.h" #include +#include // turns on checks for opengl errors in various places (for easier finding of them) // normally only few of them are enabled @@ -64,6 +65,7 @@ along with this program. If not, see . #include #include +#include #include namespace KWin @@ -275,6 +277,48 @@ void SceneOpenGL::copyPixels(const QRegion ®ion) } #endif +#ifndef KWIN_HAVE_OPENGLES +# define GL_GUILTY_CONTEXT_RESET_KWIN GL_GUILTY_CONTEXT_RESET_ARB +# define GL_INNOCENT_CONTEXT_RESET_KWIN GL_INNOCENT_CONTEXT_RESET_ARB +# define GL_UNKNOWN_CONTEXT_RESET_KWIN GL_UNKNOWN_CONTEXT_RESET_ARB +#else +# define GL_GUILTY_CONTEXT_RESET_KWIN GL_GUILTY_CONTEXT_RESET_EXT +# define GL_INNOCENT_CONTEXT_RESET_KWIN GL_INNOCENT_CONTEXT_RESET_EXT +# define GL_UNKNOWN_CONTEXT_RESET_KWIN GL_UNKNOWN_CONTEXT_RESET_EXT +#endif + +void SceneOpenGL::handleGraphicsReset(GLenum status) +{ + switch (status) { + case GL_GUILTY_CONTEXT_RESET_KWIN: + kDebug(1212) << "A graphics reset attributable to the current GL context occurred."; + break; + + case GL_INNOCENT_CONTEXT_RESET_KWIN: + kDebug(1212) << "A graphics reset not attributable to the current GL context occurred."; + break; + + case GL_UNKNOWN_CONTEXT_RESET_KWIN: + kDebug(1212) << "A graphics reset of an unknown cause occurred."; + break; + + default: + break; + } + + QElapsedTimer timer; + timer.start(); + + // Wait until the reset is completed or max 10 seconds + while (timer.elapsed() < 10000 && glGetGraphicsResetStatus() != GL_NO_ERROR) + usleep(50); + + kDebug(1212) << "Attempting to reset compositing."; + QMetaObject::invokeMethod(this, "resetCompositing", Qt::QueuedConnection); + + KNotification::event("graphicsreset", i18n("Desktop effects were restarted due to a graphics reset")); +} + qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels) { // actually paint the frame, flushed with the NEXT frame @@ -285,6 +329,13 @@ qint64 SceneOpenGL::paint(QRegion damage, ToplevelList toplevels) } m_backend->prepareRenderingFrame(); + + const GLenum status = glGetGraphicsResetStatus(); + if (status != GL_NO_ERROR) { + handleGraphicsReset(status); + return 0; + } + int mask = 0; #ifdef CHECK_GL_ERROR checkGLError("Paint1"); diff --git a/scene_opengl.h b/scene_opengl.h index 439414bd48..b8a998358b 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -80,8 +80,14 @@ protected: QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const; virtual void paintDesktop(int desktop, int mask, const QRegion ®ion, ScreenPaintData &data); + void handleGraphicsReset(GLenum status); + virtual void doPaintBackground(const QVector &vertices) = 0; virtual SceneOpenGL::Window *createWindow(Toplevel *t) = 0; + +Q_SIGNALS: + void resetCompositing(); + public Q_SLOTS: virtual void windowOpacityChanged(KWin::Toplevel* c); virtual void windowGeometryShapeChanged(KWin::Toplevel* c);