[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.
icc-effect-5.14.5
Martin Gräßlin 2015-05-18 11:33:00 +02:00
parent 29c2ae57e0
commit 74ae2f503e
3 changed files with 26 additions and 0 deletions

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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;