28#include <KGlobalAccel>
29#include <KLocalizedString>
30#include <KSelectionOwner>
33#include <QOpenGLContext>
47 : KSelectionOwner(selection, kwinApp()->x11Connection(), kwinApp()->x11RootWindow())
50 connect(
this, &X11CompositorSelectionOwner::lostOwnership,
this, [
this]() {
75X11Compositor::X11Compositor(QObject *parent)
77 , m_suspended(
options->isUseCompositing() ? NoReasonSuspend : UserSuspend)
79 if (qEnvironmentVariableIsSet(
"KWIN_MAX_FRAMES_TESTED")) {
80 m_framesToTestForSafety = qEnvironmentVariableIntValue(
"KWIN_MAX_FRAMES_TESTED");
91 m_releaseSelectionTimer.setSingleShot(
true);
92 m_releaseSelectionTimer.setInterval(2000);
93 connect(&m_releaseSelectionTimer, &QTimer::timeout,
this, &X11Compositor::releaseCompositorSelection);
95 QAction *toggleAction =
new QAction(
this);
96 toggleAction->setProperty(
"componentName", QStringLiteral(
"kwin"));
97 toggleAction->setObjectName(
"Suspend Compositing");
98 toggleAction->setText(i18n(
"Suspend Compositing"));
99 KGlobalAccel::self()->setDefaultShortcut(toggleAction, QList<QKeySequence>() << (Qt::SHIFT | Qt::ALT | Qt::Key_F12));
100 KGlobalAccel::self()->setShortcut(toggleAction, QList<QKeySequence>() << (Qt::SHIFT | Qt::ALT | Qt::Key_F12));
107 if (m_openGLFreezeProtectionThread) {
108 m_openGLFreezeProtectionThread->quit();
109 m_openGLFreezeProtectionThread->wait();
112 destroyCompositorSelection();
117 return m_syncManager.get();
135 m_inhibitors.clear();
142 m_suspended |= reason;
149 m_suspended &= ~reason;
151 m_inhibitors.clear();
156void X11Compositor::destroyCompositorSelection()
158 m_selectionOwner.reset();
161void X11Compositor::releaseCompositorSelection()
168 if (m_selectionOwner) {
169 qCDebug(KWIN_CORE) <<
"Releasing compositor selection";
170 m_selectionOwner->setOwning(
false);
171 m_selectionOwner->release();
178 m_releaseSelectionTimer.start();
183bool X11Compositor::attemptOpenGLCompositing()
187 qCWarning(KWIN_CORE) <<
"KWin has detected that your OpenGL library is unsafe to use";
192 auto safePointScope = qScopeGuard([
this]() {
196 std::unique_ptr<OpenGLBackend>
backend = kwinApp()->outputBackend()->createOpenGLBackend();
207 const QByteArray forceEnv = qgetenv(
"KWIN_COMPOSE");
208 if (!forceEnv.isEmpty()) {
209 if (qstrcmp(forceEnv,
"O2") == 0 || qstrcmp(forceEnv,
"O2ES") == 0) {
210 qCDebug(KWIN_CORE) <<
"OpenGL 2 compositing enforced by environment variable";
217 qCDebug(KWIN_CORE) <<
"Driver does not recommend OpenGL compositing";
224 qCDebug(KWIN_CORE) <<
"OpenGL 2.0 is not supported";
236 qCDebug(KWIN_CORE) <<
"OpenGL compositing has been successfully initialized";
245 reasons << QStringLiteral(
"Disabled by User");
248 reasons << QStringLiteral(
"Disabled by Window");
250 qCInfo(KWIN_CORE) <<
"Compositing is suspended, reason:" << reasons;
253 qCWarning(KWIN_CORE) <<
"Compositing is not possible";
257 if (kwinApp()->isTerminating()) {
268 if (!m_selectionOwner) {
269 m_selectionOwner = std::make_unique<X11CompositorSelectionOwner>(
"_NET_WM_CM_S0");
270 connect(m_selectionOwner.get(), &X11CompositorSelectionOwner::lostOwnership,
this, &
X11Compositor::stop);
272 if (!m_selectionOwner->owning()) {
274 m_selectionOwner->claim(
true);
275 m_selectionOwner->setOwning(
true);
278 xcb_composite_redirect_subwindows(kwinApp()->x11Connection(),
279 kwinApp()->x11RootWindow(),
280 XCB_COMPOSITE_REDIRECT_MANUAL);
283 QList<CompositingType> candidateCompositors = kwinApp()->outputBackend()->supportedCompositors();
284 const auto userConfigIt = std::find(candidateCompositors.begin(), candidateCompositors.end(),
options->
compositingMode());
285 if (userConfigIt != candidateCompositors.end()) {
286 candidateCompositors.erase(userConfigIt);
289 qCWarning(KWIN_CORE) <<
"Configured compositor not supported by Platform. Falling back to defaults";
292 for (
auto type : std::as_const(candidateCompositors)) {
296 qCDebug(KWIN_CORE) <<
"Attempting to load the OpenGL scene";
297 stop = attemptOpenGLCompositing();
300 qCDebug(KWIN_CORE) <<
"QPainter compositing is unsupported on X11";
303 qCDebug(KWIN_CORE) <<
"Starting without compositing...";
310 }
else if (qEnvironmentVariableIsSet(
"KWIN_COMPOSE")) {
311 qCCritical(KWIN_CORE) <<
"Could not fulfill the requested compositing mode in KWIN_COMPOSE:" <<
type <<
". Exiting.";
319 xcb_composite_unredirect_subwindows(kwinApp()->x11Connection(),
320 kwinApp()->x11RootWindow(),
321 XCB_COMPOSITE_REDIRECT_MANUAL);
322 if (m_selectionOwner) {
323 m_selectionOwner->setOwning(
false);
324 m_selectionOwner->release();
331 kwinApp()->setX11CompositeWindow(
backend()->overlayWindow()->window());
334 workspaceLayer->setDelegate(std::make_unique<SceneDelegate>(
m_scene.get(),
nullptr));
335 workspaceLayer->setGeometry(
workspace()->geometry());
337 workspaceLayer->setGeometry(
workspace()->geometry());
344 for (
Window *window : windows) {
345 window->setupCompositing();
349 kwinApp()->createEffectsHandler(
this,
m_scene.get());
352 if (m_releaseSelectionTimer.isActive()) {
353 m_releaseSelectionTimer.stop();
367 m_releaseSelectionTimer.start();
377 for (
Window *window : windows) {
378 window->finishCompositing();
380 xcb_composite_unredirect_subwindows(kwinApp()->x11Connection(),
381 kwinApp()->x11RootWindow(),
382 XCB_COMPOSITE_REDIRECT_MANUAL);
391 for (
auto it = superlayers.begin(); it != superlayers.end(); ++it) {
395 m_syncManager.reset();
399 kwinApp()->setX11CompositeWindow(XCB_WINDOW_NONE);
407 if (
backend()->overlayWindow() && !
backend()->overlayWindow()->isVisible()) {
413 QList<SurfaceItemX11 *> dirtyItems;
417 for (
Window *window : std::as_const(windows)) {
420 dirtyItems.append(surfaceItem);
424 if (dirtyItems.count() > 0) {
426 m_syncManager->triggerFence();
428 xcb_flush(kwinApp()->x11Connection());
433 item->waitForDamage();
443 if (!m_syncManager->endFrame()) {
444 qCDebug(KWIN_CORE) <<
"Aborting explicit synchronization with the X command stream.";
445 qCDebug(KWIN_CORE) <<
"Future frames will be rendered unsynchronized.";
446 m_syncManager.reset();
450 if (m_framesToTestForSafety > 0) {
454 m_framesToTestForSafety--;
463 m_inhibitors.insert(window);
466 QMetaObject::invokeMethod(
470 Qt::QueuedConnection);
476 if (!m_inhibitors.remove(window)) {
480 if (m_inhibitors.isEmpty()) {
482 QMetaObject::invokeMethod(
486 Qt::QueuedConnection);
498 auto timestamp = KConfigGroup(kwinApp()->config(), QStringLiteral(
"Compositing")).readEntry(QLatin1String(
"LastFailureTimestamp"), 0);
500 if (QDateTime::currentSecsSinceEpoch() - timestamp < 60) {
511 KConfigGroup gl_workaround_group(kwinApp()->config(), QStringLiteral(
"Compositing"));
513 return i18n(
"<b>OpenGL compositing (the default) has crashed KWin in the past.</b><br>"
514 "This was most likely due to a driver bug."
515 "<p>If you think that you have meanwhile upgraded to a stable driver,<br>"
516 "you can reset this protection but <b>be aware that this might result in an immediate crash!</b></p>");
520 return i18n(
"Required X extensions (XComposite and XDamage) are not available.");
523 return i18n(
"GLX/OpenGL is not available.");
531 KConfigGroup gl_workaround_group(kwinApp()->config(), QStringLiteral(
"Compositing"));
533 qCWarning(KWIN_CORE) <<
"Compositing disabled: video driver seems unstable. If you think it's a false positive, please try again in a few minutes.";
538 qCWarning(KWIN_CORE) <<
"Compositing disabled: no composite extension available";
542 qCWarning(KWIN_CORE) <<
"Compositing disabled: no damage extension available";
548 if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) {
550 }
else if (qstrcmp(qgetenv(
"KWIN_COMPOSE"),
"O2ES") == 0) {
553 qCWarning(KWIN_CORE) <<
"Compositing disabled: no OpenGL support";
559 auto group = KConfigGroup(kwinApp()->config(), QStringLiteral(
"Compositing"));
564 group.writeEntry(QLatin1String(
"LastFailureTimestamp"), QDateTime::currentSecsSinceEpoch());
569 if (m_openGLFreezeProtectionThread ==
nullptr) {
570 Q_ASSERT(m_openGLFreezeProtection ==
nullptr);
571 m_openGLFreezeProtectionThread = std::make_unique<QThread>();
572 m_openGLFreezeProtectionThread->setObjectName(
"FreezeDetector");
573 m_openGLFreezeProtectionThread->start();
574 m_openGLFreezeProtection = std::make_unique<QTimer>();
575 m_openGLFreezeProtection->setInterval(15000);
576 m_openGLFreezeProtection->setSingleShot(
true);
577 m_openGLFreezeProtection->start();
578 const QString configName = kwinApp()->config()->name();
579 m_openGLFreezeProtection->moveToThread(m_openGLFreezeProtectionThread.get());
581 m_openGLFreezeProtection.get(), &QTimer::timeout, m_openGLFreezeProtection.get(),
583 auto group = KConfigGroup(KSharedConfig::openConfig(configName), QStringLiteral(
"Compositing"));
584 group.writeEntry(QLatin1String(
"LastFailureTimestamp"), QDateTime::currentSecsSinceEpoch());
586 KCrash::setDrKonqiEnabled(false);
587 qFatal(
"Freeze in OpenGL initialization detected");
589 Qt::DirectConnection);
591 Q_ASSERT(m_openGLFreezeProtection);
592 QMetaObject::invokeMethod(m_openGLFreezeProtection.get(), QOverload<>::of(&QTimer::start), Qt::QueuedConnection);
596 group.deleteEntry(QLatin1String(
"LastFailureTimestamp"));
601 QMetaObject::invokeMethod(m_openGLFreezeProtection.get(), &QTimer::stop, Qt::QueuedConnection);
604 m_openGLFreezeProtectionThread->quit();
605 m_openGLFreezeProtectionThread->wait();
606 m_openGLFreezeProtectionThread.reset();
607 m_openGLFreezeProtection.reset();
614#include "compositor_x11.moc"
615#include "moc_compositor_x11.cpp"
void compositingToggled(bool active)
static Compositor * s_compositor
std::unique_ptr< RenderBackend > m_backend
void aboutToToggleCompositing()
void removeSuperLayer(RenderLayer *layer)
virtual void composite(RenderLoop *renderLoop)
virtual void reinitialize()
RenderBackend * backend() const
std::unique_ptr< WorkspaceScene > m_scene
QHash< RenderLoop *, RenderLayer * > m_superlayers
void addSuperLayer(RenderLayer *layer)
static Compositor * self()
The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap.
bool isGlStrictBindingFollowsDriver() const
void setGlStrictBinding(bool glStrictBinding)
const QList< Window * > & stackingOrder() const
static Workspace * self()
const QList< Window * > windows() const
~X11Compositor() override
void reinitialize() override
QString compositingNotPossibleReason() const override
void inhibit(Window *window) override
bool openGLCompositingIsBroken() const override
void resume(SuspendReason reason)
Resumes the Compositor if it is currently suspended.
void createOpenGLSafePoint(OpenGLSafePoint safePoint)
static X11Compositor * create(QObject *parent=nullptr)
static X11Compositor * self()
X11SyncManager * syncManager() const
bool compositingPossible() const override
void uninhibit(Window *window) override
void composite(RenderLoop *renderLoop) override
void suspend(SuspendReason reason)
Suspends the Compositor if it is currently active.
X11CompositorSelectionOwner(const char *selection)
static X11SyncManager * create()
static Extensions * self()
bool hasGLVersion(int major, int minor, int release)