From 743e2bc943918a4ab4faecaa2f9ab23e7cfab21d Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 3 May 2018 16:37:37 +0100 Subject: [PATCH] If GL context creation fails fall back to the software renderer Summary: If we cannot create a GL context, instead of showing an error and quitting, switch to using the QtQuick software renderer and restart. If software mode is already set, then show the error as before. This could happen in the case of the software renderer not being installed. Test Plan: After doing some driver changing, I ended up with the annoying "plasma can't start" message. Without the entry in kdeglobals I now start plasma and it seamlessly comes up working. Reviewers: #plasma Subscribers: mart, broulik, graesslin, plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D11722 --- shell/desktopview.cpp | 4 ++-- shell/main.cpp | 24 ++++++++++++++++++++++++ shell/shellcorona.cpp | 26 +++++++------------------- shell/shellcorona.h | 4 +++- shell/shellmanager.cpp | 2 ++ shell/shellmanager.h | 1 + 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/shell/desktopview.cpp b/shell/desktopview.cpp index 2352fe46e..023a2de2c 100644 --- a/shell/desktopview.cpp +++ b/shell/desktopview.cpp @@ -66,14 +66,14 @@ DesktopView::DesktopView(Plasma::Corona *corona, QScreen *targetScreen) QObject::connect(m_activityController, &KActivities::Controller::activityRemoved, this, &DesktopView::candidateContainmentsChanged); - if (QQuickWindow::sceneGraphBackend() != QLatin1String("software")) { + if (rendererInterface()->graphicsApi() != QSGRendererInterface::Software) { connect(this, &DesktopView::sceneGraphInitialized, this, [this, corona]() { // check whether the GL Context supports OpenGL // Note: hasOpenGLShaderPrograms is broken, see QTBUG--39730 if (!QOpenGLShaderProgram::hasOpenGLShaderPrograms(openglContext())) { qWarning() << "GLSL not available, Plasma won't be functional"; - QMetaObject::invokeMethod(corona, "showOpenGLNotCompatibleWarning", Qt::QueuedConnection); + QMetaObject::invokeMethod(corona, "glInitialisationFailed", Qt::QueuedConnection); } }, Qt::DirectConnection); } diff --git a/shell/main.cpp b/shell/main.cpp index b2c8b3183..d656ef4df 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -182,6 +183,29 @@ int main(int argc, char *argv[]) KDBusService service(KDBusService::Unique); + + QObject::connect(ShellManager::instance(), &ShellManager::glInitialisationFailed, &app, [&app]() { + //scene graphs errors come from a thread + //even though we process them in the main thread, app.exit could still process these events + static bool s_multipleInvokations = false; + if (s_multipleInvokations) { + return; + } + s_multipleInvokations = true; + + qCritical("Open GL context could not be created"); + auto configGroup = KSharedConfig::openConfig()->group("QtQuickRendererSettings"); + if (configGroup.readEntry("SceneGraphBackend") != QLatin1String("software")) { + configGroup.writeEntry("SceneGraphBackend", "software", KConfigBase::Global | KConfigBase::Persistent); + configGroup.sync(); + QProcess::startDetached("plasmashell", app.arguments()); + } else { + QCoreApplication::setAttribute(Qt::AA_ForceRasterWidgets); + QMessageBox::critical(nullptr, i18n("Plasma Failed To Start"), + i18n("Plasma is unable to start as it could not correctly use OpenGL 2 or software fallback\nPlease check that your graphic drivers are set up correctly.")); + } + app.exit(-1); + }); QObject::connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, ShellManager::instance(), &QObject::deleteLater); return app.exec(); diff --git a/shell/shellcorona.cpp b/shell/shellcorona.cpp index 9fdd7d7aa..02cdabddd 100644 --- a/shell/shellcorona.cpp +++ b/shell/shellcorona.cpp @@ -1191,7 +1191,10 @@ void ShellCorona::addOutput(QScreen* screen) } DesktopView *view = new DesktopView(this, screen); - connect(view, &QQuickWindow::sceneGraphError, this, &ShellCorona::showOpenGLNotCompatibleWarning); + + if (view->rendererInterface()->graphicsApi() != QSGRendererInterface::Software) { + connect(view, &QQuickWindow::sceneGraphError, this, &ShellCorona::glInitialisationFailed); + } connect(screen, &QScreen::geometryChanged, this, [=]() { const int id = m_screenPool->id(screen->name()); if (id >= 0) { @@ -1279,7 +1282,9 @@ void ShellCorona::createWaitingPanels() //Q_ASSERT(qBound(0, requestedScreen, m_screenPool->count() - 1) == requestedScreen); QScreen *screen = m_desktopViewforId.value(requestedScreen)->screenToFollow(); PanelView* panel = new PanelView(this, screen); - connect(panel, &QQuickWindow::sceneGraphError, this, &ShellCorona::showOpenGLNotCompatibleWarning); + if (panel->rendererInterface()->graphicsApi() != QSGRendererInterface::Software) { + connect(panel, &QQuickWindow::sceneGraphError, this, &ShellCorona::glInitialisationFailed); + } connect(panel, &QWindow::visibleChanged, this, &Plasma::Corona::availableScreenRectChanged); connect(panel, &PanelView::locationChanged, this, &Plasma::Corona::availableScreenRectChanged); connect(panel, &PanelView::visibilityModeChanged, this, &Plasma::Corona::availableScreenRectChanged); @@ -1962,23 +1967,6 @@ void ShellCorona::insertContainment(const QString &activity, int screenNum, Plas } } -void ShellCorona::showOpenGLNotCompatibleWarning() -{ - static bool s_multipleInvokations = false; - if (s_multipleInvokations) { - return; - } - s_multipleInvokations = true; - - QCoreApplication::setAttribute(Qt::AA_ForceRasterWidgets); - QMessageBox::critical(nullptr, i18n("Plasma Failed To Start"), - i18n("Plasma is unable to start as it could not correctly use OpenGL 2.\n Please check that your graphic drivers are set up correctly.")); - qCritical("Open GL context could not be created"); - - // this doesn't work and I have no idea why. - QCoreApplication::exit(1); -} - void ShellCorona::setupWaylandIntegration() { if (!KWindowSystem::isPlatformWayland()) { diff --git a/shell/shellcorona.h b/shell/shellcorona.h index 1ff514e9e..9349e3959 100644 --- a/shell/shellcorona.h +++ b/shell/shellcorona.h @@ -113,6 +113,9 @@ public: QString defaultContainmentPlugin() const; +Q_SIGNALS: + void glInitialisationFailed(); + public Q_SLOTS: /** * Request saving applicationConfig on disk, it's event compressed, not immediate @@ -200,7 +203,6 @@ private Q_SLOTS: void primaryOutputChanged(); void panelContainmentDestroyed(QObject* cont); - void showOpenGLNotCompatibleWarning(); void interactiveConsoleVisibilityChanged(bool visible); void handleScreenRemoved(QScreen* screen); diff --git a/shell/shellmanager.cpp b/shell/shellmanager.cpp index b6ace081d..a1996a403 100644 --- a/shell/shellmanager.cpp +++ b/shell/shellmanager.cpp @@ -91,6 +91,8 @@ void ShellManager::loadHandlers() Q_ASSERT(!d->corona); d->corona = new ShellCorona(this); + connect(d->corona, &ShellCorona::glInitialisationFailed, + this, &ShellManager::glInitialisationFailed); connect( this, &ShellManager::shellChanged, diff --git a/shell/shellmanager.h b/shell/shellmanager.h index 76440573d..ae698ce99 100644 --- a/shell/shellmanager.h +++ b/shell/shellmanager.h @@ -58,6 +58,7 @@ public Q_SLOTS: Q_SIGNALS: void shellChanged(const QString & shell); + void glInitialisationFailed(); private Q_SLOTS: void loadHandlers();