diff --git a/src/3rdparty/wayland/protocols/qt_attribution.json b/src/3rdparty/wayland/protocols/qt_attribution.json index a9fddb84082..657c032827c 100644 --- a/src/3rdparty/wayland/protocols/qt_attribution.json +++ b/src/3rdparty/wayland/protocols/qt_attribution.json @@ -154,5 +154,20 @@ Copyright © 2015, 2016 Jan Arne Petersen" "License": "MIT License", "LicenseFile": "MIT_LICENSE.txt", "Copyright": "Copyright © 2014, 2015 Collabora, Ltd." - } + }, + + { + "Id": "wayland-eglstream-controller", + "Name": "Wayland EGLStream Controller Protocol", + "QDocModule": "qtwaylandcompositor", + "QtUsage": "Used in the Qt Wayland Compositor", + "Files": "wayland-eglstream-controller.xml", + + "Description": "Allows clients to request that the compositor creates its EGLStream.", + "Homepage": "https://github.com/NVIDIA/egl-wayland", + "LicenseId": "MIT", + "License": "MIT License", + "LicenseFile": "MIT_LICENSE.txt", + "Copyright": "Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved." + } ] diff --git a/src/3rdparty/wayland/protocols/wl-eglstream-controller.xml b/src/3rdparty/wayland/protocols/wl-eglstream-controller.xml new file mode 100644 index 00000000000..dea072e64b5 --- /dev/null +++ b/src/3rdparty/wayland/protocols/wl-eglstream-controller.xml @@ -0,0 +1,37 @@ + + + + Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + Creates the corresponding server side EGLStream from the given wl_buffer + and attaches a consumer to it. + + + + + + diff --git a/src/plugins/platforms/wayland/qwaylandintegration.cpp b/src/plugins/platforms/wayland/qwaylandintegration.cpp index 1ffaf3c8930..45957629f77 100644 --- a/src/plugins/platforms/wayland/qwaylandintegration.cpp +++ b/src/plugins/platforms/wayland/qwaylandintegration.cpp @@ -343,6 +343,7 @@ void QWaylandIntegration::initializeClientBufferIntegration() if (targetKey.isEmpty()) { if (mDisplay->hardwareIntegration() + && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("wayland-eglstream-controller") && mDisplay->hardwareIntegration()->clientBufferIntegration() != QLatin1String("linux-dmabuf-unstable-v1")) { targetKey = mDisplay->hardwareIntegration()->clientBufferIntegration(); } else { diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp index 2301875c912..e81221fb5dd 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow.cpp +++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp @@ -359,8 +359,6 @@ void QWaylandWindow::sendExposeEvent(const QRect &rect) { if (!(mShellSurface && mShellSurface->handleExpose(rect))) QWindowSystemInterface::handleExposeEvent(window(), rect); - else - qCDebug(lcQpaWayland) << "sendExposeEvent: intercepted by shell extension, not sending"; mLastExposeGeometry = rect; } @@ -549,11 +547,18 @@ void QWaylandWindow::handleScreenRemoved(QScreen *qScreen) void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y) { Q_ASSERT(!buffer->committed()); + if (mFrameCallback) { + wl_callback_destroy(mFrameCallback); + mFrameCallback = nullptr; + } + if (buffer) { - handleUpdate(); + mFrameCallback = frame(); + wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); + mWaitingForFrameSync = true; buffer->setBusy(); - QtWayland::wl_surface::attach(buffer->buffer(), x, y); + attach(buffer->buffer(), x, y); } else { QtWayland::wl_surface::attach(nullptr, 0, 0); } @@ -623,9 +628,11 @@ void QWaylandWindow::frameCallback(void *data, struct wl_callback *callback, uin Q_UNUSED(callback); QWaylandWindow *self = static_cast(data); - self->mWaitingForFrameCallback = false; - if (self->mUpdateRequested) + self->mWaitingForFrameSync = false; + if (self->mUpdateRequested) { + self->mUpdateRequested = false; self->deliverUpdateRequest(); + } } QMutex QWaylandWindow::mFrameSyncMutex; @@ -633,10 +640,10 @@ QMutex QWaylandWindow::mFrameSyncMutex; void QWaylandWindow::waitForFrameSync() { QMutexLocker locker(&mFrameSyncMutex); - if (!mWaitingForFrameCallback) + if (!mWaitingForFrameSync) return; mDisplay->flushRequests(); - while (mWaitingForFrameCallback) + while (mWaitingForFrameSync) mDisplay->blockingReadEvents(); } @@ -1037,88 +1044,12 @@ QVariant QWaylandWindow::property(const QString &name, const QVariant &defaultVa return m_properties.value(name, defaultValue); } -void QWaylandWindow::timerEvent(QTimerEvent *event) -{ - if (event->timerId() == mFallbackUpdateTimerId) { - killTimer(mFallbackUpdateTimerId); - mFallbackUpdateTimerId = -1; - - if (!isExposed()) { - qCDebug(lcWaylandBackingstore) << "Fallback update timer: Window not exposed," - << "not delivering update request."; - return; - } - - if (mWaitingForUpdate && mUpdateRequested && !mWaitingForFrameCallback) { - qCWarning(lcWaylandBackingstore) << "Delivering update request through fallback timer," - << "may not be in sync with display"; - deliverUpdateRequest(); - } - } -} - void QWaylandWindow::requestUpdate() { - if (mUpdateRequested) - return; - - mUpdateRequested = true; - - // If we have a frame callback all is good and will be taken care of there - if (mWaitingForFrameCallback) - return; - - // If we've already called deliverUpdateRequest(), but haven't seen any attach+commit/swap yet - if (mWaitingForUpdate) { - // Ideally, we should just have returned here, but we're not guaranteed that the client - // will actually update, so start this timer to deliver another request update after a while - // *IF* the client doesn't update. - int fallbackTimeout = 100; - mFallbackUpdateTimerId = startTimer(fallbackTimeout); - return; - } - - // Some applications (such as Qt Quick) depend on updates being delivered asynchronously, - // so use invokeMethod to delay the delivery a bit. - QMetaObject::invokeMethod(this, [this] { - // Things might have changed in the meantime - if (mUpdateRequested && !mWaitingForUpdate && !mWaitingForFrameCallback) - deliverUpdateRequest(); - }, Qt::QueuedConnection); -} - -// Should be called whenever we commit a buffer (directly through wl_surface.commit or indirectly -// with eglSwapBuffers) to know when it's time to commit the next one. -// Can be called from the render thread (without locking anything) so make sure to not make races in this method. -void QWaylandWindow::handleUpdate() -{ - // TODO: Should sync subsurfaces avoid requesting frame callbacks? - - if (mFrameCallback) { - wl_callback_destroy(mFrameCallback); - mFrameCallback = nullptr; - } - - if (mFallbackUpdateTimerId != -1) { - // Ideally, we would stop the fallback timer here, but since we're on another thread, - // it's not allowed. Instead we set mFallbackUpdateTimer to -1 here, so we'll just - // ignore it if it times out before it's cleaned up by the invokeMethod call. - int id = mFallbackUpdateTimerId; - mFallbackUpdateTimerId = -1; - QMetaObject::invokeMethod(this, [=] { killTimer(id); }, Qt::QueuedConnection); - } - - mFrameCallback = frame(); - wl_callback_add_listener(mFrameCallback, &QWaylandWindow::callbackListener, this); - mWaitingForFrameCallback = true; - mWaitingForUpdate = false; -} - -void QWaylandWindow::deliverUpdateRequest() -{ - mUpdateRequested = false; - mWaitingForUpdate = true; - QPlatformWindow::deliverUpdateRequest(); + if (!mWaitingForFrameSync) + QPlatformWindow::requestUpdate(); + else + mUpdateRequested = true; } void QWaylandWindow::addAttachOffset(const QPoint point) diff --git a/src/plugins/platforms/wayland/qwaylandwindow_p.h b/src/plugins/platforms/wayland/qwaylandwindow_p.h index 52cbc3e5920..146767a1e76 100644 --- a/src/plugins/platforms/wayland/qwaylandwindow_p.h +++ b/src/plugins/platforms/wayland/qwaylandwindow_p.h @@ -193,10 +193,7 @@ public: bool startSystemMove(const QPoint &pos) override; - void timerEvent(QTimerEvent *event) override; void requestUpdate() override; - void handleUpdate(); - void deliverUpdateRequest() override; public slots: void applyConfigure(); @@ -216,14 +213,10 @@ protected: Qt::MouseButtons mMousePressedInContentArea = Qt::NoButton; WId mWindowId; - bool mWaitingForFrameCallback = false; + bool mWaitingForFrameSync = false; struct ::wl_callback *mFrameCallback = nullptr; QWaitCondition mFrameSyncWait; - // True when we have called deliverRequestUpdate, but the client has not yet attached a new buffer - bool mWaitingForUpdate = false; - int mFallbackUpdateTimerId = -1; - QMutex mResizeLock; bool mWaitingToApplyConfigure = false; bool mCanResize = true;