summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/qwaylanddisplay.cpp32
-rw-r--r--src/client/qwaylanddisplay_p.h12
-rw-r--r--src/client/qwaylandwindow.cpp50
-rw-r--r--src/client/qwaylandwindow_p.h5
-rw-r--r--tests/auto/client/surface/tst_surface.cpp2
5 files changed, 73 insertions, 28 deletions
diff --git a/src/client/qwaylanddisplay.cpp b/src/client/qwaylanddisplay.cpp
index e39f9128..e759c5d6 100644
--- a/src/client/qwaylanddisplay.cpp
+++ b/src/client/qwaylanddisplay.cpp
@@ -225,6 +225,17 @@ void QWaylandDisplay::flushRequests()
if (wl_display_dispatch_pending(mDisplay) < 0)
checkError();
+ {
+ QReadLocker locker(&m_frameQueueLock);
+ for (const FrameQueue &q : mExternalQueues) {
+ QMutexLocker locker(q.mutex);
+ while (wl_display_prepare_read_queue(mDisplay, q.queue) != 0)
+ wl_display_dispatch_queue_pending(mDisplay, q.queue);
+ wl_display_read_events(mDisplay);
+ wl_display_dispatch_queue_pending(mDisplay, q.queue);
+ }
+ }
+
wl_display_flush(mDisplay);
}
@@ -234,6 +245,27 @@ void QWaylandDisplay::blockingReadEvents()
checkError();
}
+void QWaylandDisplay::destroyFrameQueue(const QWaylandDisplay::FrameQueue &q)
+{
+ QWriteLocker locker(&m_frameQueueLock);
+ auto it = std::find_if(mExternalQueues.begin(),
+ mExternalQueues.end(),
+ [&q] (const QWaylandDisplay::FrameQueue &other){ return other.queue == q.queue; });
+ Q_ASSERT(it != mExternalQueues.end());
+ mExternalQueues.erase(it);
+ if (q.queue != nullptr)
+ wl_event_queue_destroy(q.queue);
+ delete q.mutex;
+}
+
+QWaylandDisplay::FrameQueue QWaylandDisplay::createFrameQueue()
+{
+ QWriteLocker locker(&m_frameQueueLock);
+ FrameQueue q{createEventQueue()};
+ mExternalQueues.append(q);
+ return q;
+}
+
wl_event_queue *QWaylandDisplay::createEventQueue()
{
return wl_display_create_queue(mDisplay);
diff --git a/src/client/qwaylanddisplay_p.h b/src/client/qwaylanddisplay_p.h
index 68d72812..86e3b729 100644
--- a/src/client/qwaylanddisplay_p.h
+++ b/src/client/qwaylanddisplay_p.h
@@ -55,6 +55,8 @@
#include <QtCore/QObject>
#include <QtCore/QPointer>
#include <QtCore/QRect>
+#include <QtCore/QMutex>
+#include <QtCore/QReadWriteLock>
#include <QtCore/QWaitCondition>
#include <QtCore/QLoggingCategory>
@@ -119,6 +121,12 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandDisplay : public QObject, public QtWayland
Q_OBJECT
public:
+ struct FrameQueue {
+ FrameQueue(wl_event_queue *q = nullptr) : queue(q), mutex(new QMutex) {}
+ wl_event_queue *queue;
+ QMutex *mutex;
+ };
+
QWaylandDisplay(QWaylandIntegration *waylandIntegration);
~QWaylandDisplay(void) override;
@@ -207,6 +215,8 @@ public:
void handleWindowDestroyed(QWaylandWindow *window);
wl_event_queue *createEventQueue();
+ FrameQueue createFrameQueue();
+ void destroyFrameQueue(const FrameQueue &q);
void dispatchQueueWhile(wl_event_queue *queue, std::function<bool()> condition, int timeout = -1);
public slots:
@@ -284,8 +294,10 @@ private:
QPointer<QWaylandWindow> mLastInputWindow;
QPointer<QWaylandWindow> mLastKeyboardFocus;
QList<QWaylandWindow *> mActiveWindows;
+ QList<FrameQueue> mExternalQueues;
struct wl_callback *mSyncCallback = nullptr;
static const wl_callback_listener syncCallbackListener;
+ QReadWriteLock m_frameQueueLock;
bool mClientSideInputContextRequested = !QPlatformInputContextFactory::requested().isNull();
bool mUsingInputContextFromCompositor = false;
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 382c258f..76f9e9f7 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -76,7 +76,7 @@ QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
: QPlatformWindow(window)
, mDisplay(display)
- , mFrameQueue(mDisplay->createEventQueue())
+ , mFrameQueue(mDisplay->createFrameQueue())
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
{
{
@@ -95,6 +95,7 @@ QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
QWaylandWindow::~QWaylandWindow()
{
+ mDisplay->destroyFrameQueue(mFrameQueue);
mDisplay->handleWindowDestroyed(this);
delete mWindowDecoration;
@@ -624,33 +625,29 @@ void QWaylandWindow::handleFrameCallback()
mFrameCallbackElapsedTimer.invalidate();
// The rest can wait until we can run it on the correct thread
- auto doHandleExpose = [this]() {
- 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 (thread() != QThread::currentThread()) {
- QMetaObject::invokeMethod(this, doHandleExpose);
- } else {
- doHandleExpose();
+ if (!mWaitingForUpdateDelivery) {
+ auto doHandleExpose = [this]() {
+ bool wasExposed = isExposed();
+ mFrameCallbackTimedOut = false;
+ if (!wasExposed && isExposed()) // Did setting mFrameCallbackTimedOut make the window exposed?
+ sendExposeEvent(QRect(QPoint(), geometry().size()));
+ if (wasExposed && hasPendingUpdateRequest())
+ deliverUpdateRequest();
+
+ mWaitingForUpdateDelivery = false;
+ };
+
+ // Queued connection, to make sure we don't call handleUpdate() from inside waitForFrameSync()
+ // in the single-threaded case.
+ mWaitingForUpdateDelivery = true;
+ QMetaObject::invokeMethod(this, doHandleExpose, Qt::QueuedConnection);
}
}
-QMutex QWaylandWindow::mFrameSyncMutex;
-
bool QWaylandWindow::waitForFrameSync(int timeout)
{
- if (!mWaitingForFrameCallback)
- return true;
-
- QMutexLocker locker(&mFrameSyncMutex);
-
- wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(mFrameCallback), mFrameQueue);
- mDisplay->dispatchQueueWhile(mFrameQueue, [&]() { return mWaitingForFrameCallback; }, timeout);
+ QMutexLocker locker(mFrameQueue.mutex);
+ mDisplay->dispatchQueueWhile(mFrameQueue.queue, [&]() { return mWaitingForFrameCallback; }, timeout);
if (mWaitingForFrameCallback) {
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
@@ -1124,6 +1121,7 @@ void QWaylandWindow::timerEvent(QTimerEvent *event)
}
if (mFrameCallbackElapsedTimer.isValid() && callbackTimerExpired) {
mFrameCallbackElapsedTimer.invalidate();
+
qCDebug(lcWaylandBackingstore) << "Didn't receive frame callback in time, window should now be inexposed";
mFrameCallbackTimedOut = true;
mWaitingForUpdate = false;
@@ -1172,7 +1170,11 @@ void QWaylandWindow::handleUpdate()
mFrameCallback = nullptr;
}
- mFrameCallback = mSurface->frame();
+ QMutexLocker locker(mFrameQueue.mutex);
+ struct ::wl_surface *wrappedSurface = reinterpret_cast<struct ::wl_surface *>(wl_proxy_create_wrapper(mSurface->object()));
+ wl_proxy_set_queue(reinterpret_cast<wl_proxy *>(wrappedSurface), mFrameQueue.queue);
+ mFrameCallback = wl_surface_frame(wrappedSurface);
+ wl_proxy_wrapper_destroy(wrappedSurface);
wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this);
mWaitingForFrameCallback = true;
mWaitingForUpdate = false;
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 9272d368..8b9a11e7 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -63,6 +63,7 @@
#include <qpa/qplatformwindow.h>
#include <QtWaylandClient/private/qwayland-wayland.h>
+#include <QtWaylandClient/private/qwaylanddisplay_p.h>
#include <QtWaylandClient/qtwaylandclientglobal.h>
struct wl_egl_window;
@@ -226,10 +227,11 @@ protected:
WId mWindowId;
bool mWaitingForFrameCallback = false;
bool mFrameCallbackTimedOut = false; // Whether the frame callback has timed out
+ bool mWaitingForUpdateDelivery = false;
int mFrameCallbackCheckIntervalTimerId = -1;
QElapsedTimer mFrameCallbackElapsedTimer;
struct ::wl_callback *mFrameCallback = nullptr;
- struct ::wl_event_queue *mFrameQueue = nullptr;
+ QWaylandDisplay::FrameQueue mFrameQueue;
QWaitCondition mFrameSyncWait;
// True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer
@@ -280,7 +282,6 @@ private:
static const wl_callback_listener callbackListener;
void handleFrameCallback();
- static QMutex mFrameSyncMutex;
static QWaylandWindow *mMouseGrab;
QReadWriteLock mSurfaceLock;
diff --git a/tests/auto/client/surface/tst_surface.cpp b/tests/auto/client/surface/tst_surface.cpp
index 289fbd62..c7b02e2c 100644
--- a/tests/auto/client/surface/tst_surface.cpp
+++ b/tests/auto/client/surface/tst_surface.cpp
@@ -64,7 +64,6 @@ void tst_surface::createDestroySurface()
void tst_surface::waitForFrameCallbackRaster()
{
- QSKIP("TODO: This currently fails, needs a fix");
class TestWindow : public QRasterWindow {
public:
explicit TestWindow() { resize(40, 40); }
@@ -100,7 +99,6 @@ void tst_surface::waitForFrameCallbackRaster()
#if QT_CONFIG(opengl)
void tst_surface::waitForFrameCallbackGl()
{
- QSKIP("TODO: This currently fails, needs a fix");
class TestWindow : public QOpenGLWindow {
public:
explicit TestWindow()