diff --git a/src/composite.cpp b/src/composite.cpp index 26bbce65e5..31d08e3e61 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -307,7 +307,6 @@ bool Compositor::setupStart() QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software); } - connect(m_scene, &Scene::resetCompositing, this, &Compositor::reinitialize); Q_EMIT sceneCreated(); return true; @@ -619,8 +618,14 @@ QList Compositor::windowsToRender() const void Compositor::composite(RenderLoop *renderLoop) { - const auto &output = m_renderLoops[renderLoop]; + if (m_backend->checkGraphicsReset()) { + qCDebug(KWIN_CORE) << "Graphics reset occurred"; + KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset")); + reinitialize(); + return; + } + const auto &output = m_renderLoops[renderLoop]; fTraceDuration("Paint (", output ? output->name() : QStringLiteral("screens"), ")"); const auto windows = windowsToRender(); diff --git a/src/platformsupport/scenes/opengl/openglbackend.cpp b/src/platformsupport/scenes/opengl/openglbackend.cpp index d78154e6ef..15190dd7ce 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.cpp +++ b/src/platformsupport/scenes/opengl/openglbackend.cpp @@ -13,7 +13,21 @@ #include "screens.h" #include "utils.h" +#include + #include +#include + +// HACK: workaround for libepoxy < 1.3 +#ifndef GL_GUILTY_CONTEXT_RESET +#define GL_GUILTY_CONTEXT_RESET 0x8253 +#endif +#ifndef GL_INNOCENT_CONTEXT_RESET +#define GL_INNOCENT_CONTEXT_RESET 0x8254 +#endif +#ifndef GL_UNKNOWN_CONTEXT_RESET +#define GL_UNKNOWN_CONTEXT_RESET 0x8255 +#endif namespace KWin { @@ -97,4 +111,36 @@ SurfaceTexture *OpenGLBackend::createSurfaceTextureWayland(SurfacePixmapWayland return nullptr; } +bool OpenGLBackend::checkGraphicsReset() +{ + const GLenum status = glGetGraphicsResetStatus(); + if (Q_LIKELY(status == GL_NO_ERROR)) { + return false; + } + + switch (status) { + case GL_GUILTY_CONTEXT_RESET: + qCDebug(KWIN_OPENGL) << "A graphics reset attributable to the current GL context occurred."; + break; + case GL_INNOCENT_CONTEXT_RESET: + qCDebug(KWIN_OPENGL) << "A graphics reset not attributable to the current GL context occurred."; + break; + case GL_UNKNOWN_CONTEXT_RESET: + qCDebug(KWIN_OPENGL) << "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); + } + + return true; +} + } diff --git a/src/platformsupport/scenes/opengl/openglbackend.h b/src/platformsupport/scenes/opengl/openglbackend.h index 03251658a4..00388f9681 100644 --- a/src/platformsupport/scenes/opengl/openglbackend.h +++ b/src/platformsupport/scenes/opengl/openglbackend.h @@ -49,6 +49,7 @@ public: virtual void init() = 0; CompositingType compositingType() const override final; + bool checkGraphicsReset() override final; virtual SurfaceTexture *createSurfaceTextureInternal(SurfacePixmapInternal *pixmap); virtual SurfaceTexture *createSurfaceTextureX11(SurfacePixmapX11 *pixmap); diff --git a/src/renderbackend.cpp b/src/renderbackend.cpp index f20d460b02..54c0ceb8bd 100644 --- a/src/renderbackend.cpp +++ b/src/renderbackend.cpp @@ -19,4 +19,9 @@ OverlayWindow *RenderBackend::overlayWindow() const return nullptr; } +bool RenderBackend::checkGraphicsReset() +{ + return false; +} + } // namespace KWin diff --git a/src/renderbackend.h b/src/renderbackend.h index d8bd0f46cb..096a91c286 100644 --- a/src/renderbackend.h +++ b/src/renderbackend.h @@ -29,6 +29,8 @@ public: virtual CompositingType compositingType() const = 0; virtual OverlayWindow *overlayWindow() const; + virtual bool checkGraphicsReset(); + virtual QRegion beginFrame(AbstractOutput *output) = 0; virtual void endFrame(AbstractOutput *output, const QRegion &renderedRegion, const QRegion &damagedRegion) = 0; }; diff --git a/src/scene.h b/src/scene.h index af07982bb0..8306f51b78 100644 --- a/src/scene.h +++ b/src/scene.h @@ -193,7 +193,6 @@ public: Q_SIGNALS: void frameRendered(); - void resetCompositing(); public Q_SLOTS: // a window has been closed diff --git a/src/scenes/opengl/scene_opengl.cpp b/src/scenes/opengl/scene_opengl.cpp index cc476e87eb..0dd766cac2 100644 --- a/src/scenes/opengl/scene_opengl.cpp +++ b/src/scenes/opengl/scene_opengl.cpp @@ -37,7 +37,6 @@ #include #include -#include #include #include @@ -45,23 +44,8 @@ #include #include #include - -#include -#include -#include #include -// HACK: workaround for libepoxy < 1.3 -#ifndef GL_GUILTY_CONTEXT_RESET -#define GL_GUILTY_CONTEXT_RESET 0x8253 -#endif -#ifndef GL_INNOCENT_CONTEXT_RESET -#define GL_INNOCENT_CONTEXT_RESET 0x8254 -#endif -#ifndef GL_UNKNOWN_CONTEXT_RESET -#define GL_UNKNOWN_CONTEXT_RESET 0x8255 -#endif - namespace KWin { @@ -113,40 +97,6 @@ bool SceneOpenGL::initFailed() const return !init_ok; } -void SceneOpenGL::handleGraphicsReset(GLenum status) -{ - switch (status) { - case GL_GUILTY_CONTEXT_RESET: - qCDebug(KWIN_OPENGL) << "A graphics reset attributable to the current GL context occurred."; - break; - - case GL_INNOCENT_CONTEXT_RESET: - qCDebug(KWIN_OPENGL) << "A graphics reset not attributable to the current GL context occurred."; - break; - - case GL_UNKNOWN_CONTEXT_RESET: - qCDebug(KWIN_OPENGL) << "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); - - qCDebug(KWIN_OPENGL) << "Attempting to reset compositing."; - QMetaObject::invokeMethod(this, "resetCompositing", Qt::QueuedConnection); - - KNotification::event(QStringLiteral("graphicsreset"), i18n("Desktop effects were restarted due to a graphics reset")); - - m_resetOccurred = true; -} - /** * Render cursor texture in case hardware cursor is disabled. * Useful for screen recording apps or backends that can't do planes. @@ -237,10 +187,6 @@ static SurfaceItem *findTopMostSurface(SurfaceItem *item) void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QList &toplevels, RenderLoop *renderLoop) { - if (m_resetOccurred) { - return; // A graphics reset has occurred, do nothing. - } - painted_screen = output; // actually paint the frame, flushed with the NEXT frame createStackingOrder(toplevels); @@ -258,71 +204,66 @@ void SceneOpenGL::paint(AbstractOutput *output, const QRegion &damage, const QLi scaling = 1; } - const GLenum status = glGetGraphicsResetStatus(); - if (status != GL_NO_ERROR) { - handleGraphicsReset(status); - } else { - renderLoop->beginFrame(); + renderLoop->beginFrame(); - SurfaceItem *fullscreenSurface = nullptr; - for (int i = stacking_order.count() - 1; i >=0; i--) { - Window *window = stacking_order[i]; - Toplevel *toplevel = window->window(); - if (output && toplevel->isOnOutput(output) && window->isVisible() && toplevel->opacity() > 0) { - AbstractClient *c = dynamic_cast(toplevel); - if (!c || !c->isFullScreen()) { - break; - } - if (!window->surfaceItem()) { - break; - } - SurfaceItem *topMost = findTopMostSurface(window->surfaceItem()); - auto pixmap = topMost->pixmap(); - if (!pixmap) { - break; - } - pixmap->update(); - // the subsurface has to be able to cover the whole window - if (topMost->position() != QPoint(0, 0)) { - break; - } - // and it has to be completely opaque - if (!window->isOpaque() && !topMost->opaque().contains(QRect(0, 0, window->width(), window->height()))) { - break; - } - fullscreenSurface = topMost; + SurfaceItem *fullscreenSurface = nullptr; + for (int i = stacking_order.count() - 1; i >=0; i--) { + Window *window = stacking_order[i]; + Toplevel *toplevel = window->window(); + if (output && toplevel->isOnOutput(output) && window->isVisible() && toplevel->opacity() > 0) { + AbstractClient *c = dynamic_cast(toplevel); + if (!c || !c->isFullScreen()) { break; } + if (!window->surfaceItem()) { + break; + } + SurfaceItem *topMost = findTopMostSurface(window->surfaceItem()); + auto pixmap = topMost->pixmap(); + if (!pixmap) { + break; + } + pixmap->update(); + // the subsurface has to be able to cover the whole window + if (topMost->position() != QPoint(0, 0)) { + break; + } + // and it has to be completely opaque + if (!window->isOpaque() && !topMost->opaque().contains(QRect(0, 0, window->width(), window->height()))) { + break; + } + fullscreenSurface = topMost; + break; } - renderLoop->setFullscreenSurface(fullscreenSurface); + } + renderLoop->setFullscreenSurface(fullscreenSurface); - bool directScanout = false; - if (m_backend->directScanoutAllowed(output) && !static_cast(effects)->blocksDirectScanout()) { - directScanout = m_backend->scanout(output, fullscreenSurface); - } - if (directScanout) { - renderLoop->endFrame(); - } else { - // prepare rendering makescontext current on the output - repaint = m_backend->beginFrame(output); - GLVertexBuffer::streamingBuffer()->beginFrame(); + bool directScanout = false; + if (m_backend->directScanoutAllowed(output) && !static_cast(effects)->blocksDirectScanout()) { + directScanout = m_backend->scanout(output, fullscreenSurface); + } + if (directScanout) { + renderLoop->endFrame(); + } else { + // prepare rendering makescontext current on the output + repaint = m_backend->beginFrame(output); + GLVertexBuffer::streamingBuffer()->beginFrame(); - GLVertexBuffer::setVirtualScreenGeometry(geo); - GLRenderTarget::setVirtualScreenGeometry(geo); - GLVertexBuffer::setVirtualScreenScale(scaling); - GLRenderTarget::setVirtualScreenScale(scaling); + GLVertexBuffer::setVirtualScreenGeometry(geo); + GLRenderTarget::setVirtualScreenGeometry(geo); + GLVertexBuffer::setVirtualScreenScale(scaling); + GLRenderTarget::setVirtualScreenScale(scaling); - updateProjectionMatrix(geo); + updateProjectionMatrix(geo); - paintScreen(damage.intersected(geo), repaint, &update, &valid, - renderLoop, projectionMatrix()); // call generic implementation - paintCursor(output, valid); + paintScreen(damage.intersected(geo), repaint, &update, &valid, + renderLoop, projectionMatrix()); // call generic implementation + paintCursor(output, valid); - renderLoop->endFrame(); + renderLoop->endFrame(); - GLVertexBuffer::streamingBuffer()->endOfFrame(); - m_backend->endFrame(output, valid, update); - } + GLVertexBuffer::streamingBuffer()->endOfFrame(); + m_backend->endFrame(output, valid, update); } // do cleanup diff --git a/src/scenes/opengl/scene_opengl.h b/src/scenes/opengl/scene_opengl.h index 79418cc528..a43cdf39f1 100644 --- a/src/scenes/opengl/scene_opengl.h +++ b/src/scenes/opengl/scene_opengl.h @@ -77,10 +77,8 @@ private: void doPaintBackground(const QVector< float >& vertices); void updateProjectionMatrix(const QRect &geometry); void performPaintWindow(EffectWindowImpl* w, int mask, const QRegion ®ion, WindowPaintData& data); - void handleGraphicsReset(GLenum status); bool init_ok = true; - bool m_resetOccurred = false; OpenGLBackend *m_backend; LanczosFilter *m_lanczosFilter = nullptr; QScopedPointer m_cursorTexture;