Pull in upstream fixes

This commit is contained in:
Jan Grulich 2019-06-27 15:39:59 +02:00
parent 7c6c8a496e
commit 287f373520
5 changed files with 245 additions and 1 deletions

View File

@ -3,13 +3,19 @@
Summary: Qt5 - Wayland platform support and QtCompositor module
Name: qt5-%{qt_module}
Version: 5.12.4
Release: 1%{?dist}
Release: 2%{?dist}
License: LGPLv3
Url: http://www.qt.io
%global majmin %(echo %{version} | cut -d. -f1-2)
Source0: https://download.qt.io/official_releases/qt/%{majmin}/%{version}/submodules/%{qt_module}-everywhere-src-%{version}.tar.xz
# Upstream patches
Patch0: qtwayland-fix-stuttering-when-gui-thread-is-busy.patch
Patch1: qtwayland-reset-frame-callback-timer-when-hiding-window.patch
Patch2: qtwayland-emit-wl-surfare-lifetime-signals.patch
Patch3: qtwayland-dont-send-fake-surface-created-destroyed-events.patch
# filter qml provides
%global __provides_exclude_from ^%{_qt5_archdatadir}/qml/.*\\.so$
@ -112,6 +118,9 @@ popd
%changelog
* Thu Jun 27 2019 Jan Grulich <jgrulich@redhat.com> -5.12.4-2
- Pull in upstream fixes
* Fri Jun 14 2019 Jan Grulich <jgrulich@redhat.com> - 5.12.4-1
- 5.12.4

View File

@ -0,0 +1,49 @@
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 731ed7f..ed0fe87 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -98,7 +98,7 @@ QWaylandWindow::~QWaylandWindow()
delete mWindowDecoration;
if (isInitialized())
- reset(false);
+ reset();
QList<QWaylandInputDevice *> inputDevices = mDisplay->inputDevices();
for (int i = 0; i < inputDevices.size(); ++i)
@@ -128,8 +128,6 @@ void QWaylandWindow::initWindow()
if (!isInitialized()) {
initializeWlSurface();
- QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceCreated);
- QGuiApplication::sendEvent(window(), &e);
}
if (shouldCreateSubSurface()) {
@@ -237,12 +235,8 @@ bool QWaylandWindow::shouldCreateSubSurface() const
return QPlatformWindow::parent() != nullptr;
}
-void QWaylandWindow::reset(bool sendDestroyEvent)
+void QWaylandWindow::reset()
{
- if (isInitialized() && sendDestroyEvent) {
- QPlatformSurfaceEvent e(QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed);
- QGuiApplication::sendEvent(window(), &e);
- }
delete mShellSurface;
mShellSurface = nullptr;
delete mSubSurfaceWindow;
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 0e32b59..746a7a5 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -259,7 +259,7 @@ private:
void initializeWlSurface();
bool shouldCreateShellSurface() const;
bool shouldCreateSubSurface() const;
- void reset(bool sendDestroyEvent = true);
+ void reset();
void sendExposeEvent(const QRect &rect);
static void closePopups(QWaylandWindow *parent);
QWaylandScreen *calculateScreenFromSurfaceEvents() const;

View File

@ -0,0 +1,41 @@
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index e3785f5..731ed7f 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -210,7 +210,9 @@ void QWaylandWindow::initWindow()
void QWaylandWindow::initializeWlSurface()
{
+ Q_ASSERT(!isInitialized());
init(mDisplay->createSurface(static_cast<QtWayland::wl_surface *>(this)));
+ emit wlSurfaceCreated();
}
bool QWaylandWindow::shouldCreateShellSurface() const
@@ -245,8 +247,10 @@ void QWaylandWindow::reset(bool sendDestroyEvent)
mShellSurface = nullptr;
delete mSubSurfaceWindow;
mSubSurfaceWindow = nullptr;
- if (isInitialized())
+ if (isInitialized()) {
+ emit wlSurfaceDestroyed();
destroy();
+ }
mScreens.clear();
if (mFrameCallback) {
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index c47123d..0e32b59 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -199,6 +199,10 @@ public:
public slots:
void applyConfigure();
+signals:
+ void wlSurfaceCreated();
+ void wlSurfaceDestroyed();
+
protected:
void surface_enter(struct ::wl_output *output) override;
void surface_leave(struct ::wl_output *output) override;

View File

@ -0,0 +1,127 @@
From ec9057081f1094fbfeb11449bc533997731e4079 Mon Sep 17 00:00:00 2001
From: Johan Klokkhammer Helsing <johan.helsing@qt.io>
Date: Wed, 19 Jun 2019 14:05:22 +0200
Subject: Client: Fix stuttering when the GUI thread is busy
When we did invokeMethod for handling the frame callbacks, we had to wait for
the GUI thread to finish whatever it's doing before we would stop blocking.
Fix it by clearing the frame callback timer and stop blocking immediately,
while delaying the rest of the work until it can be run on the other thread.
Fixes: QTBUG-76397
Change-Id: I343e4feac4838926b4fa2ccac2948988bc6c3bb7
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index cecdbda9..7c8ecada 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -610,29 +610,34 @@ const wl_callback_listener QWaylandWindow::callbackListener = {
Q_UNUSED(callback);
Q_UNUSED(time);
auto *window = static_cast<QWaylandWindow*>(data);
- if (window->thread() != QThread::currentThread())
- QMetaObject::invokeMethod(window, [=] { window->handleFrameCallback(); }, Qt::QueuedConnection);
- else
- window->handleFrameCallback();
+ window->handleFrameCallback();
}
};
void QWaylandWindow::handleFrameCallback()
{
- bool wasExposed = isExposed();
+ // Stop the timer and stop waiting immediately
+ int timerId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1);
+ mWaitingForFrameCallback = false;
- if (mFrameCallbackTimerId != -1) {
- killTimer(mFrameCallbackTimerId);
- mFrameCallbackTimerId = -1;
- }
+ // The rest can wait until we can run it on the correct thread
+ auto doHandleExpose = [this, timerId]() {
+ if (timerId != -1)
+ killTimer(timerId);
- mWaitingForFrameCallback = false;
- mFrameCallbackTimedOut = false;
+ bool wasExposed = isExposed();
+ mFrameCallbackTimedOut = false;
+ if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
+ sendExposeEvent(QRect(QPoint(), geometry().size()));
+ if (wasExposed && hasPendingUpdateRequest())
+ deliverUpdateRequest();
+ };
- if (!wasExposed && isExposed())
- sendExposeEvent(QRect(QPoint(), geometry().size()));
- if (wasExposed && hasPendingUpdateRequest())
- deliverUpdateRequest();
+ if (thread() != QThread::currentThread()) {
+ QMetaObject::invokeMethod(this, doHandleExpose);
+ } else {
+ doHandleExpose();
+ }
}
QMutex QWaylandWindow::mFrameSyncMutex;
@@ -654,11 +659,11 @@ bool QWaylandWindow::waitForFrameSync(int timeout)
}
// Stop current frame timer if any, can't use killTimer directly, because we might be on a diffent thread
- if (mFrameCallbackTimerId != -1) {
- int id = mFrameCallbackTimerId;
- mFrameCallbackTimerId = -1;
- QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
- }
+ // Ordered semantics is needed to avoid stopping the timer twice and not miss it when it's
+ // started by other writes
+ int fcbId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1);
+ if (fcbId != -1)
+ QMetaObject::invokeMethod(this, [=] { killTimer(fcbId); }, Qt::QueuedConnection);
return !mWaitingForFrameCallback;
}
@@ -1090,9 +1095,9 @@ void QWaylandWindow::timerEvent(QTimerEvent *event)
}
}
- if (event->timerId() == mFrameCallbackTimerId) {
- killTimer(mFrameCallbackTimerId);
- mFrameCallbackTimerId = -1;
+
+ if (mFrameCallbackTimerId.testAndSetOrdered(event->timerId(), -1)) {
+ killTimer(event->timerId());
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
mFrameCallbackTimedOut = true;
mWaitingForUpdate = false;
@@ -1154,11 +1159,9 @@ void QWaylandWindow::handleUpdate()
mWaitingForUpdate = false;
// Stop current frame timer if any, can't use killTimer directly, see comment above.
- if (mFrameCallbackTimerId != -1) {
- int id = mFrameCallbackTimerId;
- mFrameCallbackTimerId = -1;
- QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection);
- }
+ int fcbId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1);
+ if (fcbId != -1)
+ QMetaObject::invokeMethod(this, [=] { killTimer(fcbId); }, Qt::QueuedConnection);
// Start a timer for handling the case when the compositor stops sending frame callbacks.
QMetaObject::invokeMethod(this, [=] { // Again; can't do it directly
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index c47123dc..e8c9d568 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -216,7 +216,7 @@ protected:
WId mWindowId;
bool mWaitingForFrameCallback = false;
bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
- int mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback
+ QAtomicInt mFrameCallbackTimerId = -1; // Started on commit, reset on frame callback
struct ::wl_callback *mFrameCallback = nullptr;
struct ::wl_event_queue *mFrameQueue = nullptr;
QWaitCondition mFrameSyncWait;

View File

@ -0,0 +1,18 @@
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index cecdbda..e3785f5 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -254,6 +254,13 @@ void QWaylandWindow::reset(bool sendDestroyEvent)
mFrameCallback = nullptr;
}
+ int timerId = mFrameCallbackTimerId.fetchAndStoreOrdered(-1);
+ if (timerId != -1) {
+ killTimer(timerId);
+ }
+ mWaitingForFrameCallback = false;
+ mFrameCallbackTimedOut = false;
+
mMask = QRegion();
mQueuedBuffer = nullptr;
}