diff --git a/composite.h b/composite.h --- a/composite.h +++ b/composite.h @@ -239,6 +239,7 @@ Scene *m_scene; bool m_bufferSwapPending; bool m_composeAtSwapCompletion; + bool m_firstFrame = true; KWIN_SINGLETON_VARIABLE(Compositor, s_compositor) }; diff --git a/composite.cpp b/composite.cpp --- a/composite.cpp +++ b/composite.cpp @@ -207,7 +207,6 @@ m_scene = SceneOpenGL::createScene(this); - // TODO: Add 30 second delay to protect against screen freezes as well kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostInit); if (m_scene && !m_scene->initFailed()) { @@ -294,6 +293,7 @@ return; } Q_ASSERT(m_scene); + m_firstFrame = true; connect(workspace(), &Workspace::destroyed, this, [this] { compositeTimer.stop(); }); claimCompositorSelection(); m_xrrRefreshRate = KWin::currentRefreshRate(); @@ -734,7 +734,16 @@ // clear all repaints, so that post-pass can add repaints for the next repaint repaints_region = QRegion(); + if (m_firstFrame && (m_scene->compositingType() & OpenGLCompositing)) { + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PreFirstFrame); + } m_timeSinceLastVBlank = m_scene->paint(repaints, windows); + if (m_firstFrame) { + if (m_scene->compositingType() & OpenGLCompositing) { + kwinApp()->platform()->createOpenGLSafePoint(Platform::OpenGLSafePoint::PostFirstFrame); + } + m_firstFrame = false; + } m_timeSinceStart += m_timeSinceLastVBlank; if (waylandServer()) { diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -142,7 +142,9 @@ virtual bool openGLCompositingIsBroken() const; enum class OpenGLSafePoint { PreInit, - PostInit + PostInit, + PreFirstFrame, + PostFirstFrame }; /** * This method is invoked before and after creating the OpenGL rendering Scene. diff --git a/plugins/platforms/x11/standalone/x11_platform.h b/plugins/platforms/x11/standalone/x11_platform.h --- a/plugins/platforms/x11/standalone/x11_platform.h +++ b/plugins/platforms/x11/standalone/x11_platform.h @@ -62,6 +62,8 @@ static bool hasGlx(); XInputIntegration *m_xinputIntegration = nullptr; + QThread *m_openGLFreezeProtectionThread = nullptr; + QTimer *m_openGLFreezeProtection = nullptr; }; diff --git a/plugins/platforms/x11/standalone/x11_platform.cpp b/plugins/platforms/x11/standalone/x11_platform.cpp --- a/plugins/platforms/x11/standalone/x11_platform.cpp +++ b/plugins/platforms/x11/standalone/x11_platform.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -199,9 +200,30 @@ auto group = KConfigGroup(kwinApp()->config(), "Compositing"); switch (safePoint) { case OpenGLSafePoint::PreInit: + case OpenGLSafePoint::PreFirstFrame: + Q_ASSERT(m_openGLFreezeProtectionThread == nullptr); + m_openGLFreezeProtectionThread = new QThread(this); + m_openGLFreezeProtectionThread->start(); + m_openGLFreezeProtection = new QTimer; + m_openGLFreezeProtection->setInterval(15000); + m_openGLFreezeProtection->setSingleShot(true); + m_openGLFreezeProtection->start(); + m_openGLFreezeProtection->moveToThread(m_openGLFreezeProtectionThread); + connect(m_openGLFreezeProtection, &QTimer::timeout, m_openGLFreezeProtection, + [] { + qFatal("Freeze in OpenGL initialization detected"); + }, Qt::DirectConnection); + group.writeEntry(unsafeKey, true); break; case OpenGLSafePoint::PostInit: + case OpenGLSafePoint::PostFirstFrame: + m_openGLFreezeProtection->deleteLater(); + m_openGLFreezeProtectionThread->quit(); + m_openGLFreezeProtectionThread->wait(); + delete m_openGLFreezeProtectionThread; + m_openGLFreezeProtectionThread = nullptr; + m_openGLFreezeProtection = nullptr; group.writeEntry(unsafeKey, false); break; }