From 74ae2f503ef20b9ef387b7e0a7697cd35c7196dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Mon, 18 May 2015 11:33:00 +0200 Subject: [PATCH] [wayland] Flush QtWaylands wl_display and KWin's wayland server when processing events QtWayland and mesa might dead lock KWin if we start rendering a QWindow before Qt/Mesa got the last frame callback. They perform blocking wayland event reading on the main gui thread which makes it impossible for KWin to do the compositing and send the callback. To workaround this problem we fake a frameRendered directly after each damage event for a Qt internal window. Unfortunately this is not yet completely sufficient, thus we also need to ensure that the wayland events are processed before any events are processed which would cause a repaint and block. Thus we first flush QtWayland's wl_display and then our Server connection. If there were any damage events we can be sure that the frameRendered is sent before Qt attempts to render. --- main_wayland.cpp | 1 + wayland_server.cpp | 23 +++++++++++++++++++++++ wayland_server.h | 2 ++ 3 files changed, 26 insertions(+) diff --git a/main_wayland.cpp b/main_wayland.cpp index ce0a7a7832..e7b2b43c85 100644 --- a/main_wayland.cpp +++ b/main_wayland.cpp @@ -324,6 +324,7 @@ EventDispatcher::~EventDispatcher() = default; bool EventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { + waylandServer()->dispatch(); const bool didSendEvents = QEventDispatcherUNIX::processEvents(flags); return QWindowSystemInterface::sendWindowSystemEvents(flags) || didSendEvents; } diff --git a/wayland_server.cpp b/wayland_server.cpp index e33f278278..c0a625a52e 100644 --- a/wayland_server.cpp +++ b/wayland_server.cpp @@ -104,6 +104,13 @@ void WaylandServer::init(const QByteArray &socketName) fakeDummyQtWindowInput(); return; } + // HACK: in order to get Qt to not block for frame rendered, we immediatelly emit the + // frameRendered once we get a new damage event. + auto s = surface->surface(); + connect(s, &SurfaceInterface::damaged, this, [this, s] { + s->frameRendered(0); + m_qtConnection->flush(); + }); } auto client = new ShellClient(surface); if (auto c = Compositor::self()) { @@ -238,4 +245,20 @@ void WaylandServer::fakeDummyQtWindowInput() #endif } +void WaylandServer::dispatch() +{ + if (!m_display) { + return; + } + if (!m_qtClientConnection) { + if (m_qtConnection && QGuiApplication::instance()) { + m_qtClientConnection = KWayland::Client::ConnectionThread::fromApplication(this); + } + } + if (m_qtClientConnection) { + m_qtClientConnection->flush(); + } + m_display->dispatchEvents(0); +} + } diff --git a/wayland_server.h b/wayland_server.h index f18b7c893e..11c204f6b6 100644 --- a/wayland_server.h +++ b/wayland_server.h @@ -106,6 +106,7 @@ public: KWayland::Client::ConnectionThread *internalClientConection() { return m_internalConnection.client; } + void dispatch(); Q_SIGNALS: void shellClientAdded(ShellClient*); @@ -119,6 +120,7 @@ private: KWayland::Server::ShellInterface *m_shell = nullptr; KWayland::Server::ClientConnection *m_xwaylandConnection = nullptr; KWayland::Server::ClientConnection *m_qtConnection = nullptr; + KWayland::Client::ConnectionThread *m_qtClientConnection = nullptr; struct { KWayland::Server::ClientConnection *server = nullptr; KWayland::Client::ConnectionThread *client = nullptr;