From 6636261dbcb647f7605a07a0a7ed658d0187f398 Mon Sep 17 00:00:00 2001 From: Florian RICHER Date: Fri, 31 May 2024 12:15:48 +0200 Subject: [PATCH] kwin: Remove syncobj patch Useless because lot of application run with XWayland and is already patched for NVIDIA 555 --- modules/system/desktop/plasma/default.nix | 7 +- overlays/.gitkeep | 0 overlays/kwin/5511.patch | 2027 --------------------- overlays/kwin/default.nix | 9 - 4 files changed, 1 insertion(+), 2042 deletions(-) create mode 100644 overlays/.gitkeep delete mode 100644 overlays/kwin/5511.patch delete mode 100644 overlays/kwin/default.nix diff --git a/modules/system/desktop/plasma/default.nix b/modules/system/desktop/plasma/default.nix index b0387fe..521f98d 100644 --- a/modules/system/desktop/plasma/default.nix +++ b/modules/system/desktop/plasma/default.nix @@ -33,10 +33,5 @@ in glxinfo clinfo ]; - - # Uncomment when kwin is available in nixpkgs and NVIDIA 555 - nixpkgs.overlays = [ - (import ../../../../overlays/kwin) - ]; }; -} \ No newline at end of file +} diff --git a/overlays/.gitkeep b/overlays/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/overlays/kwin/5511.patch b/overlays/kwin/5511.patch deleted file mode 100644 index 341dc2e..0000000 --- a/overlays/kwin/5511.patch +++ /dev/null @@ -1,2027 +0,0 @@ -From e1791de663807bc93c09418481cb844c7daeb8f7 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl -Date: Wed, 22 Nov 2023 19:51:24 +0100 -Subject: [PATCH 1/5] wayland: implement linux-drm-syncobj-v1 - -linux-drm-syncobj-v1 allows drivers and apps to synchronize KWin's buffer access -to their rendering, and synchronize their rendering to KWin's buffer release. This -fixes severe glitches with the proprietary NVidia driver and allows for some -performance improvements with Mesa too. - -(cherry picked from commit 32addf4d599135678a5120470bc27a881f34a3d9) ---- - src/CMakeLists.txt | 1 + - src/backends/drm/drm_egl_backend.cpp | 16 ++ - src/backends/drm/drm_egl_backend.h | 3 + - src/backends/drm/drm_gpu.cpp | 8 + - src/backends/drm/drm_gpu.h | 2 + - src/compositor_wayland.cpp | 2 +- - src/core/graphicsbuffer.cpp | 6 + - src/core/graphicsbuffer.h | 8 + - src/core/renderbackend.cpp | 11 + - src/core/renderbackend.h | 5 + - src/core/syncobjtimeline.cpp | 83 ++++++ - src/core/syncobjtimeline.h | 72 +++++ - src/opengl/eglnativefence.cpp | 5 + - src/opengl/eglnativefence.h | 1 + - .../scenes/opengl/abstract_egl_backend.cpp | 5 + - .../scenes/opengl/abstract_egl_backend.h | 2 +- - .../scenes/opengl/openglbackend.cpp | 4 + - .../scenes/opengl/openglbackend.h | 3 + - src/scene/item.h | 1 + - src/scene/itemrenderer_opengl.cpp | 20 +- - src/scene/itemrenderer_opengl.h | 9 +- - src/scene/surfaceitem.cpp | 5 + - src/scene/surfaceitem.h | 3 + - src/scene/surfaceitem_wayland.cpp | 6 + - src/scene/surfaceitem_wayland.h | 1 + - src/scene/workspacescene_opengl.cpp | 2 +- - src/wayland/CMakeLists.txt | 8 + - src/wayland/linux_drm_syncobj_v1.cpp | 190 +++++++++++++ - src/wayland/linux_drm_syncobj_v1.h | 63 +++++ - src/wayland/linux_drm_syncobj_v1_p.h | 32 +++ - .../protocols/linux-drm-syncobj-v1.xml | 261 ++++++++++++++++++ - src/wayland/surface.cpp | 20 ++ - src/wayland/surface.h | 8 + - src/wayland/surface_p.h | 9 + - src/wayland/transaction.cpp | 27 +- - src/wayland/transaction_p.h | 15 + - src/wayland_server.cpp | 17 ++ - src/wayland_server.h | 7 + - 38 files changed, 935 insertions(+), 6 deletions(-) - create mode 100644 src/core/syncobjtimeline.cpp - create mode 100644 src/core/syncobjtimeline.h - create mode 100644 src/wayland/linux_drm_syncobj_v1.cpp - create mode 100644 src/wayland/linux_drm_syncobj_v1.h - create mode 100644 src/wayland/linux_drm_syncobj_v1_p.h - create mode 100644 src/wayland/protocols/linux-drm-syncobj-v1.xml - -diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt -index 4e0db4fe9a9..0130caf3b8e 100644 ---- a/src/CMakeLists.txt -+++ b/src/CMakeLists.txt -@@ -73,6 +73,7 @@ target_sources(kwin PRIVATE - core/session_logind.cpp - core/session_noop.cpp - core/shmgraphicsbufferallocator.cpp -+ core/syncobjtimeline.cpp - cursor.cpp - cursorsource.cpp - dbusinterface.cpp -diff --git a/src/backends/drm/drm_egl_backend.cpp b/src/backends/drm/drm_egl_backend.cpp -index cfb7a482a03..943407e1d9b 100644 ---- a/src/backends/drm/drm_egl_backend.cpp -+++ b/src/backends/drm/drm_egl_backend.cpp -@@ -9,6 +9,7 @@ - #include "drm_egl_backend.h" - #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" - // kwin -+#include "core/syncobjtimeline.h" - #include "drm_abstract_output.h" - #include "drm_backend.h" - #include "drm_egl_cursor_layer.h" -@@ -199,6 +200,21 @@ DrmGpu *EglGbmBackend::gpu() const - return m_backend->primaryGpu(); - } - -+bool EglGbmBackend::supportsTimelines() const -+{ -+ return m_backend->primaryGpu()->syncObjTimelinesSupported(); -+} -+ -+std::unique_ptr EglGbmBackend::importTimeline(FileDescriptor &&syncObjFd) -+{ -+ uint32_t handle = 0; -+ if (drmSyncobjFDToHandle(m_backend->primaryGpu()->fd(), syncObjFd.get(), &handle) != 0) { -+ qCWarning(KWIN_DRM) << "importing syncobj timeline failed!" << strerror(errno); -+ return nullptr; -+ } -+ return std::make_unique(m_backend->primaryGpu()->fd(), handle); -+} -+ - } // namespace KWin - - #include "moc_drm_egl_backend.cpp" -diff --git a/src/backends/drm/drm_egl_backend.h b/src/backends/drm/drm_egl_backend.h -index 43c431f07be..4a47e900cd3 100644 ---- a/src/backends/drm/drm_egl_backend.h -+++ b/src/backends/drm/drm_egl_backend.h -@@ -63,6 +63,9 @@ public: - EglDisplay *displayForGpu(DrmGpu *gpu); - std::shared_ptr contextForGpu(DrmGpu *gpu); - -+ bool supportsTimelines() const override; -+ std::unique_ptr importTimeline(FileDescriptor &&syncObjFd) override; -+ - private: - bool initializeEgl(); - bool initRenderingContext(); -diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp -index c5d258a2d7c..7141ed8beac 100644 ---- a/src/backends/drm/drm_gpu.cpp -+++ b/src/backends/drm/drm_gpu.cpp -@@ -76,6 +76,9 @@ DrmGpu::DrmGpu(DrmBackend *backend, const QString &devNode, int fd, dev_t device - m_addFB2ModifiersSupported = drmGetCap(fd, DRM_CAP_ADDFB2_MODIFIERS, &capability) == 0 && capability == 1; - qCDebug(KWIN_DRM) << "drmModeAddFB2WithModifiers is" << (m_addFB2ModifiersSupported ? "supported" : "not supported") << "on GPU" << m_devNode; - -+ m_supportsSyncTimelines = drmGetCap(fd, DRM_CAP_SYNCOBJ_TIMELINE, &capability) == 0 && capability == 1; -+ qCDebug(KWIN_DRM) << "sync obj timelines are" << (m_supportsSyncTimelines ? "supported" : "not supported") << "on GPU" << this; -+ - // find out what driver this kms device is using - DrmUniquePtr version(drmGetVersion(fd)); - m_isI915 = strstr(version->name, "i915"); -@@ -699,6 +702,11 @@ bool DrmGpu::asyncPageflipSupported() const - return m_asyncPageflipSupported; - } - -+bool DrmGpu::syncObjTimelinesSupported() const -+{ -+ return m_supportsSyncTimelines; -+} -+ - bool DrmGpu::isI915() const - { - return m_isI915; -diff --git a/src/backends/drm/drm_gpu.h b/src/backends/drm/drm_gpu.h -index 0cc6b2126a3..c8dbde47af7 100644 ---- a/src/backends/drm/drm_gpu.h -+++ b/src/backends/drm/drm_gpu.h -@@ -77,6 +77,7 @@ public: - bool atomicModeSetting() const; - bool addFB2ModifiersSupported() const; - bool asyncPageflipSupported() const; -+ bool syncObjTimelinesSupported() const; - bool isI915() const; - bool isNVidia() const; - bool isVmwgfx() const; -@@ -146,6 +147,7 @@ private: - bool m_isRemoved = false; - bool m_isActive = true; - bool m_forceModeset = false; -+ bool m_supportsSyncTimelines = false; - clockid_t m_presentationClock; - gbm_device *m_gbmDevice; - FileDescriptor m_gbmFd; -diff --git a/src/compositor_wayland.cpp b/src/compositor_wayland.cpp -index f63ead77964..69916e9d348 100644 ---- a/src/compositor_wayland.cpp -+++ b/src/compositor_wayland.cpp -@@ -86,7 +86,7 @@ bool WaylandCompositor::attemptOpenGLCompositing() - } - - m_scene = std::make_unique(backend.get()); -- m_cursorScene = std::make_unique(std::make_unique()); -+ m_cursorScene = std::make_unique(std::make_unique(backend->eglDisplayObject())); - m_backend = std::move(backend); - - qCDebug(KWIN_CORE) << "OpenGL compositing has been successfully initialized"; -diff --git a/src/core/graphicsbuffer.cpp b/src/core/graphicsbuffer.cpp -index f234d09fa9f..e83fcd7bf8a 100644 ---- a/src/core/graphicsbuffer.cpp -+++ b/src/core/graphicsbuffer.cpp -@@ -40,6 +40,7 @@ void GraphicsBuffer::unref() - if (m_dropped) { - delete this; - } else { -+ m_releasePoints.clear(); - Q_EMIT released(); - } - } -@@ -73,6 +74,11 @@ const ShmAttributes *GraphicsBuffer::shmAttributes() const - return nullptr; - } - -+void GraphicsBuffer::addReleasePoint(const std::shared_ptr &releasePoint) -+{ -+ m_releasePoints.push_back(releasePoint); -+} -+ - bool GraphicsBuffer::alphaChannelFromDrmFormat(uint32_t format) - { - const auto info = FormatInfo::get(format); -diff --git a/src/core/graphicsbuffer.h b/src/core/graphicsbuffer.h -index cacf49dde5a..2e046e58de0 100644 ---- a/src/core/graphicsbuffer.h -+++ b/src/core/graphicsbuffer.h -@@ -16,6 +16,8 @@ - namespace KWin - { - -+class SyncReleasePoint; -+ - struct DmaBufAttributes - { - int planeCount = 0; -@@ -87,6 +89,11 @@ public: - virtual const DmaBufAttributes *dmabufAttributes() const; - virtual const ShmAttributes *shmAttributes() const; - -+ /** -+ * the added release point will be referenced as long as this buffer is referenced -+ */ -+ void addReleasePoint(const std::shared_ptr &releasePoint); -+ - static bool alphaChannelFromDrmFormat(uint32_t format); - - Q_SIGNALS: -@@ -95,6 +102,7 @@ Q_SIGNALS: - protected: - int m_refCount = 0; - bool m_dropped = false; -+ std::vector> m_releasePoints; - }; - - /** -diff --git a/src/core/renderbackend.cpp b/src/core/renderbackend.cpp -index 98276385cec..5bbf37d9a4b 100644 ---- a/src/core/renderbackend.cpp -+++ b/src/core/renderbackend.cpp -@@ -7,6 +7,7 @@ - #include "renderbackend.h" - #include "renderloop_p.h" - #include "scene/surfaceitem.h" -+#include "syncobjtimeline.h" - - #include - -@@ -103,6 +104,16 @@ std::unique_ptr RenderBackend::createSurfaceTextureWayland(Surfa - return nullptr; - } - -+bool RenderBackend::supportsTimelines() const -+{ -+ return false; -+} -+ -+std::unique_ptr RenderBackend::importTimeline(FileDescriptor &&syncObjFd) -+{ -+ return nullptr; -+} -+ - } // namespace KWin - - #include "moc_renderbackend.cpp" -diff --git a/src/core/renderbackend.h b/src/core/renderbackend.h -index b902a28984a..682e35aa0b8 100644 ---- a/src/core/renderbackend.h -+++ b/src/core/renderbackend.h -@@ -8,6 +8,7 @@ - - #include "core/rendertarget.h" - #include "effect/globals.h" -+#include "utils/filedescriptor.h" - - #include - -@@ -26,6 +27,7 @@ class SurfacePixmapX11; - class SurfaceTexture; - class PresentationFeedback; - class RenderLoop; -+class SyncTimeline; - - class PresentationFeedback - { -@@ -88,6 +90,9 @@ public: - - virtual std::unique_ptr createSurfaceTextureX11(SurfacePixmapX11 *pixmap); - virtual std::unique_ptr createSurfaceTextureWayland(SurfacePixmap *pixmap); -+ -+ virtual bool supportsTimelines() const; -+ virtual std::unique_ptr importTimeline(FileDescriptor &&syncObjFd); - }; - - } // namespace KWin -diff --git a/src/core/syncobjtimeline.cpp b/src/core/syncobjtimeline.cpp -new file mode 100644 -index 00000000000..3e2c100370a ---- /dev/null -+++ b/src/core/syncobjtimeline.cpp -@@ -0,0 +1,83 @@ -+/* -+ SPDX-FileCopyrightText: 2024 Xaver Hugl -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#include "syncobjtimeline.h" -+ -+#include -+#include -+ -+namespace KWin -+{ -+ -+SyncReleasePoint::SyncReleasePoint(const std::shared_ptr &timeline, uint64_t timelinePoint) -+ : m_timeline(timeline) -+ , m_timelinePoint(timelinePoint) -+{ -+} -+ -+SyncReleasePoint::~SyncReleasePoint() -+{ -+ m_timeline->signal(m_timelinePoint); -+} -+ -+SyncTimeline *SyncReleasePoint::timeline() const -+{ -+ return m_timeline.get(); -+} -+ -+uint64_t SyncReleasePoint::timelinePoint() const -+{ -+ return m_timelinePoint; -+} -+ -+SyncTimeline::SyncTimeline(int drmFd, uint32_t handle) -+ : m_drmFd(drmFd) -+ , m_handle(handle) -+{ -+} -+ -+SyncTimeline::~SyncTimeline() -+{ -+ drmSyncobjDestroy(m_drmFd, m_handle); -+} -+ -+FileDescriptor SyncTimeline::eventFd(uint64_t timelinePoint) const -+{ -+ FileDescriptor ret{eventfd(0, EFD_CLOEXEC)}; -+ if (!ret.isValid()) { -+ return {}; -+ } -+ struct drm_syncobj_eventfd args -+ { -+ .handle = m_handle, -+ .flags = 0, -+ .point = timelinePoint, -+ .fd = ret.get(), -+ }; -+ if (drmIoctl(m_drmFd, DRM_IOCTL_SYNCOBJ_EVENTFD, &args) != 0) { -+ return {}; -+ } -+ return ret; -+} -+ -+void SyncTimeline::signal(uint64_t timelinePoint) -+{ -+ drmSyncobjTimelineSignal(m_drmFd, &m_handle, &timelinePoint, 1); -+} -+ -+SyncReleasePointHolder::SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set> &&releasePoints) -+ : m_fence(std::move(requirement)) -+ , m_notifier(m_fence.get(), QSocketNotifier::Type::Read) -+ , m_releasePoints(std::move(releasePoints)) -+{ -+ connect(&m_notifier, &QSocketNotifier::activated, this, &SyncReleasePointHolder::signaled); -+ m_notifier.setEnabled(true); -+} -+ -+void SyncReleasePointHolder::signaled() -+{ -+ delete this; -+} -+} -diff --git a/src/core/syncobjtimeline.h b/src/core/syncobjtimeline.h -new file mode 100644 -index 00000000000..cffdb75e330 ---- /dev/null -+++ b/src/core/syncobjtimeline.h -@@ -0,0 +1,72 @@ -+/* -+ SPDX-FileCopyrightText: 2024 Xaver Hugl -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#pragma once -+#include "kwin_export.h" -+#include "utils/filedescriptor.h" -+ -+#include -+#include -+#include -+#include -+#include -+ -+namespace KWin -+{ -+ -+class SyncTimeline; -+ -+/** -+ * A helper to signal the release point when it goes out of scope -+ */ -+class KWIN_EXPORT SyncReleasePoint -+{ -+public: -+ explicit SyncReleasePoint(const std::shared_ptr &timeline, uint64_t timelinePoint); -+ ~SyncReleasePoint(); -+ -+ SyncTimeline *timeline() const; -+ uint64_t timelinePoint() const; -+ -+private: -+ const std::shared_ptr m_timeline; -+ const uint64_t m_timelinePoint; -+}; -+ -+class KWIN_EXPORT SyncTimeline -+{ -+public: -+ explicit SyncTimeline(int drmFd, uint32_t handle); -+ ~SyncTimeline(); -+ -+ /** -+ * @returns an event fd that gets signalled when the timeline point gets signalled -+ */ -+ FileDescriptor eventFd(uint64_t timelinePoint) const; -+ -+ void signal(uint64_t timelinePoint); -+ -+private: -+ const int32_t m_drmFd; -+ const uint32_t m_handle; -+}; -+ -+class SyncReleasePointHolder : public QObject -+{ -+ Q_OBJECT -+public: -+ /** -+ * @param requirement the filedescriptor that needs to be readable before the release points may be signalled. Once that's happened, this object deletes itself!' -+ */ -+ explicit SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set> &&releasePoints); -+ -+private: -+ void signaled(); -+ -+ const FileDescriptor m_fence; -+ QSocketNotifier m_notifier; -+ const std::unordered_set> m_releasePoints; -+}; -+} -diff --git a/src/opengl/eglnativefence.cpp b/src/opengl/eglnativefence.cpp -index e68098bc768..13c42ade543 100644 ---- a/src/opengl/eglnativefence.cpp -+++ b/src/opengl/eglnativefence.cpp -@@ -51,6 +51,11 @@ const FileDescriptor &EGLNativeFence::fileDescriptor() const - return m_fileDescriptor; - } - -+FileDescriptor &&EGLNativeFence::fileDescriptor() -+{ -+ return std::move(m_fileDescriptor); -+} -+ - bool EGLNativeFence::waitSync() const - { - return eglWaitSync(m_display->handle(), m_sync, 0) == EGL_TRUE; -diff --git a/src/opengl/eglnativefence.h b/src/opengl/eglnativefence.h -index d5f6bdbbba2..05c248ff8e0 100644 ---- a/src/opengl/eglnativefence.h -+++ b/src/opengl/eglnativefence.h -@@ -27,6 +27,7 @@ public: - - bool isValid() const; - const FileDescriptor &fileDescriptor() const; -+ FileDescriptor &&fileDescriptor(); - bool waitSync() const; - - static EGLNativeFence importFence(EglDisplay *display, FileDescriptor &&fd); -diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp -index 4e227aef462..4ad2064148b 100644 ---- a/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp -+++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.cpp -@@ -13,6 +13,7 @@ - #include "opengl/egl_context_attribute_builder.h" - #include "utils/common.h" - #include "wayland/drmclientbuffer.h" -+#include "wayland/linux_drm_syncobj_v1.h" - #include "wayland_server.h" - // kwin libs - #include "opengl/eglimagetexture.h" -@@ -217,9 +218,13 @@ void AbstractEglBackend::initWayland() - .formatTable = includeShaderConversions(filterFormats({}, true)), - }); - -+ waylandServer()->setRenderBackend(this); - LinuxDmaBufV1ClientBufferIntegration *dmabuf = waylandServer()->linuxDmabuf(); - dmabuf->setRenderBackend(this); - dmabuf->setSupportedFormatsWithModifiers(m_tranches); -+ if (auto syncObj = waylandServer()->linuxSyncObj()) { -+ syncObj->setRenderBackend(this); -+ } - } - - void AbstractEglBackend::initClientExtensions() -diff --git a/src/platformsupport/scenes/opengl/abstract_egl_backend.h b/src/platformsupport/scenes/opengl/abstract_egl_backend.h -index 0abd331ed6b..1f77898db50 100644 ---- a/src/platformsupport/scenes/opengl/abstract_egl_backend.h -+++ b/src/platformsupport/scenes/opengl/abstract_egl_backend.h -@@ -34,7 +34,7 @@ public: - - EGLSurface surface() const; - EGLConfig config() const; -- EglDisplay *eglDisplayObject() const; -+ EglDisplay *eglDisplayObject() const override; - EglContext *contextObject(); - - bool testImportBuffer(GraphicsBuffer *buffer) override; -diff --git a/src/platformsupport/scenes/opengl/openglbackend.cpp b/src/platformsupport/scenes/opengl/openglbackend.cpp -index 92ca501d96e..0bb6de64021 100644 ---- a/src/platformsupport/scenes/opengl/openglbackend.cpp -+++ b/src/platformsupport/scenes/opengl/openglbackend.cpp -@@ -93,6 +93,10 @@ bool OpenGLBackend::checkGraphicsReset() - return true; - } - -+EglDisplay *OpenGLBackend::eglDisplayObject() const -+{ -+ return nullptr; -+} - } - - #include "moc_openglbackend.cpp" -diff --git a/src/platformsupport/scenes/opengl/openglbackend.h b/src/platformsupport/scenes/opengl/openglbackend.h -index 3318f4da187..e0749561826 100644 ---- a/src/platformsupport/scenes/opengl/openglbackend.h -+++ b/src/platformsupport/scenes/opengl/openglbackend.h -@@ -19,6 +19,7 @@ namespace KWin - class Output; - class OpenGLBackend; - class GLTexture; -+class EglDisplay; - - /** - * @brief The OpenGLBackend creates and holds the OpenGL context and is responsible for Texture from Pixmap. -@@ -97,6 +98,8 @@ public: - - virtual std::pair, ColorDescription> textureForOutput(Output *output) const; - -+ virtual EglDisplay *eglDisplayObject() const; -+ - protected: - /** - * @brief Sets the backend initialization to failed. -diff --git a/src/scene/item.h b/src/scene/item.h -index 5e9e4f1c92a..b77fc91c64b 100644 ---- a/src/scene/item.h -+++ b/src/scene/item.h -@@ -22,6 +22,7 @@ namespace KWin - - class SceneDelegate; - class Scene; -+class SyncReleasePoint; - - /** - * The Item class is the base class for items in the scene. -diff --git a/src/scene/itemrenderer_opengl.cpp b/src/scene/itemrenderer_opengl.cpp -index 44ec0918e33..3fee3863f2c 100644 ---- a/src/scene/itemrenderer_opengl.cpp -+++ b/src/scene/itemrenderer_opengl.cpp -@@ -8,7 +8,9 @@ - #include "core/pixelgrid.h" - #include "core/rendertarget.h" - #include "core/renderviewport.h" -+#include "core/syncobjtimeline.h" - #include "effect/effect.h" -+#include "opengl/eglnativefence.h" - #include "platformsupport/scenes/opengl/openglsurfacetexture.h" - #include "scene/decorationitem.h" - #include "scene/imageitem.h" -@@ -20,7 +22,8 @@ - namespace KWin - { - --ItemRendererOpenGL::ItemRendererOpenGL() -+ItemRendererOpenGL::ItemRendererOpenGL(EglDisplay *eglDisplay) -+ : m_eglDisplay(eglDisplay) - { - const QString visualizeOptionsString = qEnvironmentVariable("KWIN_SCENE_VISUALIZE"); - if (!visualizeOptionsString.isEmpty()) { -@@ -46,6 +49,14 @@ void ItemRendererOpenGL::endFrame() - { - GLVertexBuffer::streamingBuffer()->endOfFrame(); - GLFramebuffer::popFramebuffer(); -+ -+ if (m_eglDisplay) { -+ EGLNativeFence fence(m_eglDisplay); -+ if (fence.isValid()) { -+ new SyncReleasePointHolder(std::move(fence.fileDescriptor()), std::move(m_releasePoints)); -+ } -+ } -+ m_releasePoints.clear(); - } - - QVector4D ItemRendererOpenGL::modulate(float opacity, float brightness) const -@@ -173,6 +184,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = UnnormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = nullptr, - }); - } - } else if (auto decorationItem = qobject_cast(item)) { -@@ -187,6 +199,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = UnnormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = nullptr, - }); - } - } else if (auto surfaceItem = qobject_cast(item)) { -@@ -202,6 +215,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = NormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = surfaceItem->bufferReleasePoint(), - }); - } - } -@@ -216,6 +230,7 @@ void ItemRendererOpenGL::createRenderNode(Item *item, RenderContext *context) - .coordinateType = NormalizedCoordinates, - .scale = scale, - .colorDescription = item->colorDescription(), -+ .bufferReleasePoint = nullptr, - }); - } - } -@@ -407,6 +422,9 @@ void ItemRendererOpenGL::renderItem(const RenderTarget &renderTarget, const Rend - contents.planes[plane]->unbind(); - } - } -+ if (renderNode.bufferReleasePoint) { -+ m_releasePoints.insert(renderNode.bufferReleasePoint); -+ } - } - if (shader) { - ShaderManager::instance()->popShader(); -diff --git a/src/scene/itemrenderer_opengl.h b/src/scene/itemrenderer_opengl.h -index c35839335c6..11ab8cea386 100644 ---- a/src/scene/itemrenderer_opengl.h -+++ b/src/scene/itemrenderer_opengl.h -@@ -10,9 +10,13 @@ - #include "platformsupport/scenes/opengl/openglsurfacetexture.h" - #include "scene/itemrenderer.h" - -+#include -+ - namespace KWin - { - -+class EglDisplay; -+ - class KWIN_EXPORT ItemRendererOpenGL : public ItemRenderer - { - public: -@@ -28,6 +32,7 @@ public: - TextureCoordinateType coordinateType = UnnormalizedCoordinates; - qreal scale = 1.0; - ColorDescription colorDescription; -+ std::shared_ptr bufferReleasePoint; - }; - - struct RenderContext -@@ -41,7 +46,7 @@ public: - const qreal renderTargetScale; - }; - -- ItemRendererOpenGL(); -+ ItemRendererOpenGL(EglDisplay *eglDisplay); - - void beginFrame(const RenderTarget &renderTarget, const RenderViewport &viewport) override; - void endFrame() override; -@@ -58,6 +63,8 @@ private: - void visualizeFractional(const RenderViewport &viewport, const QRegion ®ion, const RenderContext &renderContext); - - bool m_blendingEnabled = false; -+ EglDisplay *const m_eglDisplay; -+ std::unordered_set> m_releasePoints; - - struct - { -diff --git a/src/scene/surfaceitem.cpp b/src/scene/surfaceitem.cpp -index 4404dbc3c6c..f04053f3566 100644 ---- a/src/scene/surfaceitem.cpp -+++ b/src/scene/surfaceitem.cpp -@@ -270,6 +270,11 @@ std::chrono::nanoseconds SurfaceItem::frameTimeEstimation() const - } - } - -+std::shared_ptr SurfaceItem::bufferReleasePoint() const -+{ -+ return m_bufferReleasePoint; -+} -+ - SurfaceTexture::~SurfaceTexture() - { - } -diff --git a/src/scene/surfaceitem.h b/src/scene/surfaceitem.h -index 5dfcfd0ad16..f6c8ca5d56d 100644 ---- a/src/scene/surfaceitem.h -+++ b/src/scene/surfaceitem.h -@@ -38,6 +38,8 @@ public: - QSize bufferSize() const; - void setBufferSize(const QSize &size); - -+ std::shared_ptr bufferReleasePoint() const; -+ - QRegion mapFromBuffer(const QRegion ®ion) const; - - void addDamage(const QRegion ®ion); -@@ -82,6 +84,7 @@ protected: - std::deque m_lastDamageTimeDiffs; - std::optional m_lastDamage; - std::chrono::nanoseconds m_frameTimeEstimation = std::chrono::days(1000); -+ std::shared_ptr m_bufferReleasePoint; - }; - - class KWIN_EXPORT SurfaceTexture -diff --git a/src/scene/surfaceitem_wayland.cpp b/src/scene/surfaceitem_wayland.cpp -index 82863c3a456..6f16c47142f 100644 ---- a/src/scene/surfaceitem_wayland.cpp -+++ b/src/scene/surfaceitem_wayland.cpp -@@ -41,6 +41,7 @@ SurfaceItemWayland::SurfaceItemWayland(SurfaceInterface *surface, Scene *scene, - this, &SurfaceItemWayland::handleColorDescriptionChanged); - connect(surface, &SurfaceInterface::presentationModeHintChanged, - this, &SurfaceItemWayland::handlePresentationModeHintChanged); -+ connect(surface, &SurfaceInterface::bufferReleasePointChanged, this, &SurfaceItemWayland::handleReleasePointChanged); - - SubSurfaceInterface *subsurface = surface->subSurface(); - if (subsurface) { -@@ -184,6 +185,11 @@ void SurfaceItemWayland::handlePresentationModeHintChanged() - setPresentationHint(m_surface->presentationModeHint()); - } - -+void SurfaceItemWayland::handleReleasePointChanged() -+{ -+ m_bufferReleasePoint = m_surface->bufferReleasePoint(); -+} -+ - SurfacePixmapWayland::SurfacePixmapWayland(SurfaceItemWayland *item, QObject *parent) - : SurfacePixmap(Compositor::self()->backend()->createSurfaceTextureWayland(this), parent) - , m_item(item) -diff --git a/src/scene/surfaceitem_wayland.h b/src/scene/surfaceitem_wayland.h -index ab31192cb9a..c428f1ea417 100644 ---- a/src/scene/surfaceitem_wayland.h -+++ b/src/scene/surfaceitem_wayland.h -@@ -48,6 +48,7 @@ private Q_SLOTS: - void handleSubSurfaceMappedChanged(); - void handleColorDescriptionChanged(); - void handlePresentationModeHintChanged(); -+ void handleReleasePointChanged(); - - protected: - std::unique_ptr createPixmap() override; -diff --git a/src/scene/workspacescene_opengl.cpp b/src/scene/workspacescene_opengl.cpp -index 3a024f56bd9..aabee9be151 100644 ---- a/src/scene/workspacescene_opengl.cpp -+++ b/src/scene/workspacescene_opengl.cpp -@@ -40,7 +40,7 @@ namespace KWin - ***********************************************/ - - WorkspaceSceneOpenGL::WorkspaceSceneOpenGL(OpenGLBackend *backend) -- : WorkspaceScene(std::make_unique()) -+ : WorkspaceScene(std::make_unique(backend->eglDisplayObject())) - , m_backend(backend) - { - } -diff --git a/src/wayland/CMakeLists.txt b/src/wayland/CMakeLists.txt -index 41ee1c5581a..9d2add111fc 100644 ---- a/src/wayland/CMakeLists.txt -+++ b/src/wayland/CMakeLists.txt -@@ -231,6 +231,10 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml - PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/xx-color-management-v2.xml - BASENAME xx-color-management-v2 - ) -+ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml -+ PROTOCOL ${PROJECT_SOURCE_DIR}/src/wayland/protocols/linux-drm-syncobj-v1.xml -+ BASENAME linux-drm-syncobj-v1 -+) - - target_sources(kwin PRIVATE - abstract_data_source.cpp -@@ -265,6 +269,7 @@ target_sources(kwin PRIVATE - keyboard_shortcuts_inhibit_v1.cpp - keystate.cpp - layershell_v1.cpp -+ linux_drm_syncobj_v1.cpp - linuxdmabufv1clientbuffer.cpp - lockscreen_overlay_v1.cpp - output.cpp -@@ -344,6 +349,7 @@ install(FILES - keyboard_shortcuts_inhibit_v1.h - keystate.h - layershell_v1.h -+ linux_drm_syncobj_v1.h - lockscreen_overlay_v1.h - output.h - output_order_v1.h -@@ -390,10 +396,12 @@ install(FILES - - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-content-type-v1.h - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-frog-color-management-v1.h -+ ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-linux-drm-syncobj-v1.h - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-presentation-time.h - ${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-xx-color-management-v2.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-content-type-v1-server-protocol.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-frog-color-management-v1-server-protocol.h -+ ${CMAKE_CURRENT_BINARY_DIR}/wayland-linux-drm-syncobj-v1-server-protocol.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-presentation-time-server-protocol.h - ${CMAKE_CURRENT_BINARY_DIR}/wayland-xx-color-management-v2-server-protocol.h - -diff --git a/src/wayland/linux_drm_syncobj_v1.cpp b/src/wayland/linux_drm_syncobj_v1.cpp -new file mode 100644 -index 00000000000..589ccd78c3b ---- /dev/null -+++ b/src/wayland/linux_drm_syncobj_v1.cpp -@@ -0,0 +1,190 @@ -+/* -+ KWin - the KDE window manager -+ This file is part of the KDE project. -+ -+ SPDX-FileCopyrightText: 2024 Xaver Hugl -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#include "linux_drm_syncobj_v1.h" -+#include "core/syncobjtimeline.h" -+#include "display.h" -+#include "linux_drm_syncobj_v1_p.h" -+#include "surface.h" -+#include "surface_p.h" -+#include "transaction.h" -+#include "utils/resource.h" -+ -+#include -+ -+namespace KWin -+{ -+ -+static constexpr uint32_t s_version = 1; -+ -+LinuxDrmSyncObjV1Interface::LinuxDrmSyncObjV1Interface(Display *display, QObject *parent) -+ : QObject(parent) -+ , QtWaylandServer::wp_linux_drm_syncobj_manager_v1(*display, s_version) -+{ -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_get_surface(Resource *resource, uint32_t id, wl_resource *surface) -+{ -+ SurfaceInterface *surf = SurfaceInterface::get(surface); -+ SurfaceInterfacePrivate *priv = SurfaceInterfacePrivate::get(surf); -+ if (priv->syncObjV1) { -+ wl_resource_post_error(resource->handle, error_surface_exists, "surface already exists"); -+ return; -+ } -+ priv->syncObjV1 = new LinuxDrmSyncObjSurfaceV1(surf, resource->client(), id); -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_import_timeline(Resource *resource, uint32_t id, int32_t rawFd) -+{ -+ FileDescriptor fd(rawFd); -+ // TODO add a GPU abstraction, instead of using the render backend -+ if (!m_renderBackend || isGlobalRemoved()) { -+ // to not crash the client, create an inert timeline -+ new LinuxDrmSyncObjTimelineV1(resource->client(), id, nullptr); -+ return; -+ } -+ auto timeline = m_renderBackend->importTimeline(std::move(fd)); -+ if (!timeline) { -+ wl_resource_post_error(resource->handle, WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Importing timeline failed"); -+ return; -+ } -+ new LinuxDrmSyncObjTimelineV1(resource->client(), id, std::move(timeline)); -+} -+ -+void LinuxDrmSyncObjV1Interface::setRenderBackend(RenderBackend *backend) -+{ -+ m_renderBackend = backend; -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_destroy(Resource *resource) -+{ -+ wl_resource_destroy(resource->handle); -+} -+ -+void LinuxDrmSyncObjV1Interface::remove() -+{ -+ QtWaylandServer::wp_linux_drm_syncobj_manager_v1::globalRemove(); -+} -+ -+void LinuxDrmSyncObjV1Interface::wp_linux_drm_syncobj_manager_v1_destroy_global() -+{ -+ delete this; -+} -+ -+LinuxDrmSyncObjTimelineV1::LinuxDrmSyncObjTimelineV1(wl_client *client, uint32_t id, std::unique_ptr &&timeline) -+ : QtWaylandServer::wp_linux_drm_syncobj_timeline_v1(client, id, s_version) -+ , m_timeline(std::move(timeline)) -+{ -+} -+ -+LinuxDrmSyncObjTimelineV1::~LinuxDrmSyncObjTimelineV1() -+{ -+} -+ -+void LinuxDrmSyncObjTimelineV1::wp_linux_drm_syncobj_timeline_v1_destroy_resource(Resource *resource) -+{ -+ delete this; -+} -+ -+void LinuxDrmSyncObjTimelineV1::wp_linux_drm_syncobj_timeline_v1_destroy(Resource *resource) -+{ -+ wl_resource_destroy(resource->handle); -+} -+ -+std::shared_ptr LinuxDrmSyncObjTimelineV1::timeline() const -+{ -+ return m_timeline; -+} -+ -+LinuxDrmSyncObjSurfaceV1::LinuxDrmSyncObjSurfaceV1(SurfaceInterface *surface, wl_client *client, uint32_t id) -+ : QtWaylandServer::wp_linux_drm_syncobj_surface_v1(client, id, s_version) -+ , m_surface(surface) -+{ -+} -+ -+LinuxDrmSyncObjSurfaceV1::~LinuxDrmSyncObjSurfaceV1() -+{ -+ if (m_surface) { -+ SurfaceInterfacePrivate::get(m_surface)->syncObjV1 = nullptr; -+ } -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_set_acquire_point(Resource *resource, wl_resource *timeline_resource, uint32_t point_hi, uint32_t point_lo) -+{ -+ if (!m_surface) { -+ wl_resource_post_error(resource->handle, WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface got destroyed already"); -+ return; -+ } -+ const auto timeline = resource_cast(timeline_resource); -+ if (!timeline->timeline()) { -+ // in the normal case this should never happen, but if it does, -+ // there's nothing we can do about it without killing the client -+ return; -+ } -+ const uint64_t point = (uint64_t(point_hi) << 32) | point_lo; -+ const auto priv = SurfaceInterfacePrivate::get(m_surface); -+ priv->pending->acquirePoint.timeline = timeline->timeline(); -+ priv->pending->acquirePoint.point = point; -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_set_release_point(Resource *resource, wl_resource *timeline_resource, uint32_t point_hi, uint32_t point_lo) -+{ -+ if (!m_surface) { -+ wl_resource_post_error(resource->handle, WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface got destroyed already"); -+ return; -+ } -+ const auto timeline = resource_cast(timeline_resource); -+ if (!timeline->timeline()) { -+ // in the normal case this should never happen, but if it does, -+ // there's nothing we can do about it without killing the client -+ return; -+ } -+ const uint64_t point = (uint64_t(point_hi) << 32) | point_lo; -+ SurfaceInterfacePrivate::get(m_surface)->pending->releasePoint = std::make_unique(timeline->timeline(), point); -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_destroy_resource(Resource *resource) -+{ -+ delete this; -+} -+ -+void LinuxDrmSyncObjSurfaceV1::wp_linux_drm_syncobj_surface_v1_destroy(Resource *resource) -+{ -+ wl_resource_destroy(resource->handle); -+} -+ -+bool LinuxDrmSyncObjSurfaceV1::maybeEmitProtocolErrors() -+{ -+ const auto priv = SurfaceInterfacePrivate::get(m_surface); -+ if (!priv->pending->bufferIsSet && !priv->pending->acquirePoint.timeline && !priv->pending->releasePoint) { -+ return false; -+ } -+ if (!priv->pending->acquirePoint.timeline) { -+ wl_resource_post_error(resource()->handle, error_no_acquire_point, "explicit sync is used, but no acquire point is set"); -+ return true; -+ } -+ if (!priv->pending->releasePoint) { -+ wl_resource_post_error(resource()->handle, error_no_release_point, "explicit sync is used, but no release point is set"); -+ return true; -+ } -+ if (priv->pending->acquirePoint.timeline.get() == priv->pending->releasePoint->timeline() -+ && priv->pending->acquirePoint.point >= priv->pending->releasePoint->timelinePoint()) { -+ wl_resource_post_error(resource()->handle, error_conflicting_points, "acquire and release points are on the same timeline and acquire >= release"); -+ return true; -+ } -+ if (!priv->pending->buffer) { -+ wl_resource_post_error(resource()->handle, error_no_buffer, "explicit sync is used, but no buffer is attached"); -+ return true; -+ } -+ if (!priv->pending->buffer->dmabufAttributes()) { -+ wl_resource_post_error(resource()->handle, error_unsupported_buffer, "only linux dmabuf buffers are allowed to use explicit sync"); -+ return true; -+ } -+ return false; -+} -+} -diff --git a/src/wayland/linux_drm_syncobj_v1.h b/src/wayland/linux_drm_syncobj_v1.h -new file mode 100644 -index 00000000000..ff6ddbe0340 ---- /dev/null -+++ b/src/wayland/linux_drm_syncobj_v1.h -@@ -0,0 +1,63 @@ -+/* -+ KWin - the KDE window manager -+ This file is part of the KDE project. -+ -+ SPDX-FileCopyrightText: 2024 Xaver Hugl -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#pragma once -+ -+#include "kwin_export.h" -+#include "qwayland-server-linux-drm-syncobj-v1.h" -+ -+#include -+#include -+ -+namespace KWin -+{ -+ -+class Display; -+class SurfaceInterface; -+class RenderBackend; -+class SyncTimeline; -+ -+class KWIN_EXPORT LinuxDrmSyncObjV1Interface : public QObject, private QtWaylandServer::wp_linux_drm_syncobj_manager_v1 -+{ -+ Q_OBJECT -+public: -+ explicit LinuxDrmSyncObjV1Interface(Display *display, QObject *parent = nullptr); -+ -+ void setRenderBackend(RenderBackend *backend); -+ void remove(); -+ -+private: -+ void wp_linux_drm_syncobj_manager_v1_get_surface(Resource *resource, uint32_t id, wl_resource *surface) override; -+ void wp_linux_drm_syncobj_manager_v1_import_timeline(Resource *resource, uint32_t id, int32_t fd) override; -+ void wp_linux_drm_syncobj_manager_v1_destroy(Resource *resource) override; -+ void wp_linux_drm_syncobj_manager_v1_destroy_global() override; -+ -+ QPointer m_renderBackend; -+}; -+ -+class LinuxDrmSyncObjSurfaceV1 : private QtWaylandServer::wp_linux_drm_syncobj_surface_v1 -+{ -+public: -+ explicit LinuxDrmSyncObjSurfaceV1(SurfaceInterface *surface, wl_client *client, uint32_t id); -+ ~LinuxDrmSyncObjSurfaceV1() override; -+ -+ /** -+ * checks for protocol errors that may need to be sent at commit time -+ * @returns if any protocol errors were actually emitted -+ */ -+ bool maybeEmitProtocolErrors(); -+ -+private: -+ void wp_linux_drm_syncobj_surface_v1_set_acquire_point(Resource *resource, wl_resource *timeline, uint32_t point_hi, uint32_t point_lo) override; -+ void wp_linux_drm_syncobj_surface_v1_set_release_point(Resource *resource, wl_resource *timeline, uint32_t point_hi, uint32_t point_lo) override; -+ void wp_linux_drm_syncobj_surface_v1_destroy_resource(Resource *resource) override; -+ void wp_linux_drm_syncobj_surface_v1_destroy(Resource *resource) override; -+ -+ const QPointer m_surface; -+}; -+} -diff --git a/src/wayland/linux_drm_syncobj_v1_p.h b/src/wayland/linux_drm_syncobj_v1_p.h -new file mode 100644 -index 00000000000..6efbc12ee30 ---- /dev/null -+++ b/src/wayland/linux_drm_syncobj_v1_p.h -@@ -0,0 +1,32 @@ -+/* -+ KWin - the KDE window manager -+ This file is part of the KDE project. -+ -+ SPDX-FileCopyrightText: 2024 Xaver Hugl -+ -+ SPDX-License-Identifier: GPL-2.0-or-later -+*/ -+#pragma once -+#include "linux_drm_syncobj_v1.h" -+ -+namespace KWin -+{ -+ -+class LinuxDrmSyncObjTimelineV1 : public QtWaylandServer::wp_linux_drm_syncobj_timeline_v1 -+{ -+public: -+ explicit LinuxDrmSyncObjTimelineV1(wl_client *client, uint32_t id, std::unique_ptr &&timeline); -+ ~LinuxDrmSyncObjTimelineV1() override; -+ -+ /** -+ * May return nullptr if the timeline resource is inert -+ */ -+ std::shared_ptr timeline() const; -+ -+private: -+ void wp_linux_drm_syncobj_timeline_v1_destroy_resource(Resource *resource) override; -+ void wp_linux_drm_syncobj_timeline_v1_destroy(Resource *resource) override; -+ -+ const std::shared_ptr m_timeline; -+}; -+} -diff --git a/src/wayland/protocols/linux-drm-syncobj-v1.xml b/src/wayland/protocols/linux-drm-syncobj-v1.xml -new file mode 100644 -index 00000000000..2c491eaf43a ---- /dev/null -+++ b/src/wayland/protocols/linux-drm-syncobj-v1.xml -@@ -0,0 +1,261 @@ -+ -+ -+ -+ Copyright 2016 The Chromium Authors. -+ Copyright 2017 Intel Corporation -+ Copyright 2018 Collabora, Ltd -+ Copyright 2021 Simon Ser -+ -+ 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 (including the next -+ paragraph) 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. -+ -+ -+ -+ This protocol allows clients to request explicit synchronization for -+ buffers. It is tied to the Linux DRM synchronization object framework. -+ -+ Synchronization refers to co-ordination of pipelined operations performed -+ on buffers. Most GPU clients will schedule an asynchronous operation to -+ render to the buffer, then immediately send the buffer to the compositor -+ to be attached to a surface. -+ -+ With implicit synchronization, ensuring that the rendering operation is -+ complete before the compositor displays the buffer is an implementation -+ detail handled by either the kernel or userspace graphics driver. -+ -+ By contrast, with explicit synchronization, DRM synchronization object -+ timeline points mark when the asynchronous operations are complete. When -+ submitting a buffer, the client provides a timeline point which will be -+ waited on before the compositor accesses the buffer, and another timeline -+ point that the compositor will signal when it no longer needs to access the -+ buffer contents for the purposes of the surface commit. -+ -+ Linux DRM synchronization objects are documented at: -+ https://dri.freedesktop.org/docs/drm/gpu/drm-mm.html#drm-sync-objects -+ -+ Warning! The protocol described in this file is currently in the testing -+ phase. Backward compatible changes may be added together with the -+ corresponding interface version bump. Backward incompatible changes can -+ only be done by creating a new major version of the extension. -+ -+ -+ -+ -+ This global is a factory interface, allowing clients to request -+ explicit synchronization for buffers on a per-surface basis. -+ -+ See wp_linux_drm_syncobj_surface_v1 for more information. -+ -+ -+ -+ -+ Destroy this explicit synchronization factory object. Other objects -+ shall not be affected by this request. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Instantiate an interface extension for the given wl_surface to provide -+ explicit synchronization. -+ -+ If the given wl_surface already has an explicit synchronization object -+ associated, the surface_exists protocol error is raised. -+ -+ Graphics APIs, like EGL or Vulkan, that manage the buffer queue and -+ commits of a wl_surface themselves, are likely to be using this -+ extension internally. If a client is using such an API for a -+ wl_surface, it should not directly use this extension on that surface, -+ to avoid raising a surface_exists protocol error. -+ -+ -+ -+ -+ -+ -+ -+ Import a DRM synchronization object timeline. -+ -+ If the FD cannot be imported, the invalid_timeline error is raised. -+ -+ -+ -+ -+ -+ -+ -+ -+ This object represents an explicit synchronization object timeline -+ imported by the client to the compositor. -+ -+ -+ -+ -+ Destroy the synchronization object timeline. Other objects are not -+ affected by this request, in particular timeline points set by -+ set_acquire_point and set_release_point are not unset. -+ -+ -+ -+ -+ -+ -+ This object is an add-on interface for wl_surface to enable explicit -+ synchronization. -+ -+ Each surface can be associated with only one object of this interface at -+ any time. -+ -+ Explicit synchronization is guaranteed to be supported for buffers -+ created with any version of the linux-dmabuf protocol. Compositors are -+ free to support explicit synchronization for additional buffer types. -+ If at surface commit time the attached buffer does not support explicit -+ synchronization, an unsupported_buffer error is raised. -+ -+ As long as the wp_linux_drm_syncobj_surface_v1 object is alive, the -+ compositor may ignore implicit synchronization for buffers attached and -+ committed to the wl_surface. The delivery of wl_buffer.release events -+ for buffers attached to the surface becomes undefined. -+ -+ Clients must set both acquire and release points if and only if a -+ non-null buffer is attached in the same surface commit. See the -+ no_buffer, no_acquire_point and no_release_point protocol errors. -+ -+ If at surface commit time the acquire and release DRM syncobj timelines -+ are identical, the acquire point value must be strictly less than the -+ release point value, or else the conflicting_points protocol error is -+ raised. -+ -+ -+ -+ -+ Destroy this surface synchronization object. -+ -+ Any timeline point set by this object with set_acquire_point or -+ set_release_point since the last commit may be discarded by the -+ compositor. Any timeline point set by this object before the last -+ commit will not be affected. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Set the timeline point that must be signalled before the compositor may -+ sample from the buffer attached with wl_surface.attach. -+ -+ The 64-bit unsigned value combined from point_hi and point_lo is the -+ point value. -+ -+ The acquire point is double-buffered state, and will be applied on the -+ next wl_surface.commit request for the associated surface. Thus, it -+ applies only to the buffer that is attached to the surface at commit -+ time. -+ -+ If an acquire point has already been attached during the same commit -+ cycle, the new point replaces the old one. -+ -+ If the associated wl_surface was destroyed, a no_surface error is -+ raised. -+ -+ If at surface commit time there is a pending acquire timeline point set -+ but no pending buffer attached, a no_buffer error is raised. If at -+ surface commit time there is a pending buffer attached but no pending -+ acquire timeline point set, the no_acquire_point protocol error is -+ raised. -+ -+ -+ -+ -+ -+ -+ -+ -+ Set the timeline point that must be signalled by the compositor when it -+ has finished its usage of the buffer attached with wl_surface.attach -+ for the relevant commit. -+ -+ Once the timeline point is signaled, and assuming the associated buffer -+ is not pending release from other wl_surface.commit requests, no -+ additional explicit or implicit synchronization with the compositor is -+ required to safely re-use the buffer. -+ -+ Note that clients cannot rely on the release point being always -+ signaled after the acquire point: compositors may release buffers -+ without ever reading from them. In addition, the compositor may use -+ different presentation paths for different commits, which may have -+ different release behavior. As a result, the compositor may signal the -+ release points in a different order than the client committed them. -+ -+ Because signaling a timeline point also signals every previous point, -+ it is generally not safe to use the same timeline object for the -+ release points of multiple buffers. The out-of-order signaling -+ described above may lead to a release point being signaled before the -+ compositor has finished reading. To avoid this, it is strongly -+ recommended that each buffer should use a separate timeline for its -+ release points. -+ -+ The 64-bit unsigned value combined from point_hi and point_lo is the -+ point value. -+ -+ The release point is double-buffered state, and will be applied on the -+ next wl_surface.commit request for the associated surface. Thus, it -+ applies only to the buffer that is attached to the surface at commit -+ time. -+ -+ If a release point has already been attached during the same commit -+ cycle, the new point replaces the old one. -+ -+ If the associated wl_surface was destroyed, a no_surface error is -+ raised. -+ -+ If at surface commit time there is a pending release timeline point set -+ but no pending buffer attached, a no_buffer error is raised. If at -+ surface commit time there is a pending buffer attached but no pending -+ release timeline point set, the no_release_point protocol error is -+ raised. -+ -+ -+ -+ -+ -+ -+ -diff --git a/src/wayland/surface.cpp b/src/wayland/surface.cpp -index 23f981f2f81..6a33c5fca10 100644 ---- a/src/wayland/surface.cpp -+++ b/src/wayland/surface.cpp -@@ -13,6 +13,7 @@ - #include "fractionalscale_v1_p.h" - #include "frog_colormanagement_v1.h" - #include "idleinhibit_v1_p.h" -+#include "linux_drm_syncobj_v1.h" - #include "linuxdmabufv1clientbuffer.h" - #include "output.h" - #include "pointerconstraints_v1_p.h" -@@ -342,6 +343,10 @@ void SurfaceInterfacePrivate::surface_commit(Resource *resource) - { - const bool sync = subsurface.handle && subsurface.handle->isSynchronized(); - -+ if (syncObjV1 && syncObjV1->maybeEmitProtocolErrors()) { -+ return; -+ } -+ - Transaction *transaction; - if (sync) { - if (!subsurface.transaction) { -@@ -518,6 +523,9 @@ void SurfaceState::mergeInto(SurfaceState *target) - target->offset = offset; - target->damage = damage; - target->bufferDamage = bufferDamage; -+ target->acquirePoint.timeline = std::exchange(acquirePoint.timeline, nullptr); -+ target->acquirePoint.point = acquirePoint.point; -+ target->releasePoint = std::move(releasePoint); - target->bufferIsSet = true; - } - if (viewport.sourceGeometryIsSet) { -@@ -600,6 +608,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - const bool visibilityChanged = bufferChanged && bool(current->buffer) != bool(next->buffer); - const bool colorDescriptionChanged = next->colorDescriptionIsSet; - const bool presentationModeHintChanged = next->presentationModeHintIsSet; -+ const bool bufferReleasePointChanged = next->releasePointIsSet; - - const QSizeF oldSurfaceSize = surfaceSize; - const QSize oldBufferSize = bufferSize; -@@ -608,6 +617,9 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - - next->mergeInto(current.get()); - bufferRef = current->buffer; -+ if (bufferRef && current->releasePoint) { -+ bufferRef->addReleasePoint(current->releasePoint); -+ } - scaleOverride = pendingScaleOverride; - - if (current->buffer) { -@@ -689,6 +701,9 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - if (presentationModeHintChanged) { - Q_EMIT q->presentationModeHintChanged(); - } -+ if (bufferReleasePointChanged) { -+ Q_EMIT q->bufferReleasePointChanged(); -+ } - - if (bufferChanged) { - if (current->buffer && (!current->damage.isEmpty() || !current->bufferDamage.isEmpty())) { -@@ -1179,6 +1194,11 @@ void SurfaceInterface::traverseTree(std::function SurfaceInterface::bufferReleasePoint() const -+{ -+ return d->current->releasePoint; -+} -+ - } // namespace KWin - - #include "moc_surface.cpp" -diff --git a/src/wayland/surface.h b/src/wayland/surface.h -index 597f06774f8..80d1fa55708 100644 ---- a/src/wayland/surface.h -+++ b/src/wayland/surface.h -@@ -32,6 +32,7 @@ class SlideInterface; - class SubSurfaceInterface; - class SurfaceInterfacePrivate; - class Transaction; -+class SyncReleasePoint; - - /** - * The SurfaceRole class represents a role assigned to a wayland surface. -@@ -342,6 +343,12 @@ public: - - void setPreferredColorDescription(const ColorDescription &descr); - -+ /** -+ * @returns the release point that should be referenced as long as the buffer on this surface -+ * is, or may still be used by the compositor -+ */ -+ std::shared_ptr bufferReleasePoint() const; -+ - /** - * Traverses the surface sub-tree with this surface as the root. - */ -@@ -426,6 +433,7 @@ Q_SIGNALS: - - void colorDescriptionChanged(); - void presentationModeHintChanged(); -+ void bufferReleasePointChanged(); - - /** - * Emitted when the Surface has been committed. -diff --git a/src/wayland/surface_p.h b/src/wayland/surface_p.h -index f78bd107b44..775f9d7bd2e 100644 ---- a/src/wayland/surface_p.h -+++ b/src/wayland/surface_p.h -@@ -28,6 +28,7 @@ class FractionalScaleV1Interface; - class FrogColorManagementSurfaceV1; - class PresentationTimeFeedback; - class XXColorSurfaceV2; -+class LinuxDrmSyncObjSurfaceV1; - - struct SurfaceState - { -@@ -58,6 +59,7 @@ struct SurfaceState - bool contentTypeIsSet = false; - bool presentationModeHintIsSet = false; - bool colorDescriptionIsSet = false; -+ bool releasePointIsSet = false; - qint32 bufferScale = 1; - OutputTransform bufferTransform = OutputTransform::Normal; - wl_list frameCallbacks; -@@ -71,6 +73,12 @@ struct SurfaceState - PresentationModeHint presentationHint = PresentationModeHint::VSync; - ColorDescription colorDescription = ColorDescription::sRGB; - std::unique_ptr presentationFeedback; -+ struct -+ { -+ std::shared_ptr timeline; -+ uint64_t point = 0; -+ } acquirePoint; -+ std::shared_ptr releasePoint; - - struct - { -@@ -169,6 +177,7 @@ public: - TearingControlV1Interface *tearing = nullptr; - FrogColorManagementSurfaceV1 *frogColorManagement = nullptr; - XXColorSurfaceV2 *xxColorSurface = nullptr; -+ LinuxDrmSyncObjSurfaceV1 *syncObjV1 = nullptr; - - struct - { -diff --git a/src/wayland/transaction.cpp b/src/wayland/transaction.cpp -index 93004ba863d..fcd19d4036f 100644 ---- a/src/wayland/transaction.cpp -+++ b/src/wayland/transaction.cpp -@@ -5,7 +5,9 @@ - */ - - #include "wayland/transaction.h" -+#include "core/syncobjtimeline.h" - #include "utils/filedescriptor.h" -+#include "wayland/clientconnection.h" - #include "wayland/subcompositor.h" - #include "wayland/surface_p.h" - #include "wayland/transaction_p.h" -@@ -76,6 +78,24 @@ bool TransactionDmaBufLocker::arm() - return !m_pending.isEmpty(); - } - -+TransactionEventFdLocker::TransactionEventFdLocker(Transaction *transaction, FileDescriptor &&eventFd, ClientConnection *client) -+ : m_transaction(transaction) -+ , m_client(client) -+ , m_eventFd(std::move(eventFd)) -+ , m_notifier(m_eventFd.get(), QSocketNotifier::Type::Read) -+{ -+ transaction->lock(); -+ connect(&m_notifier, &QSocketNotifier::activated, this, &TransactionEventFdLocker::unlock); -+ // when the client quits, the eventfd may never be signaled -+ connect(m_client, &ClientConnection::aboutToBeDestroyed, this, &TransactionEventFdLocker::unlock); -+} -+ -+void TransactionEventFdLocker::unlock() -+{ -+ m_transaction->unlock(); -+ delete this; -+} -+ - Transaction::Transaction() - { - } -@@ -248,7 +268,12 @@ void Transaction::commit() - for (TransactionEntry &entry : m_entries) { - if (entry.state->bufferIsSet && entry.state->buffer) { - // Avoid applying the transaction until all graphics buffers have become idle. -- if (auto locker = TransactionDmaBufLocker::get(entry.state->buffer)) { -+ if (entry.state->acquirePoint.timeline) { -+ auto eventFd = entry.state->acquirePoint.timeline->eventFd(entry.state->acquirePoint.point); -+ if (entry.surface && eventFd.isValid()) { -+ new TransactionEventFdLocker(this, std::move(eventFd), entry.surface->client()); -+ } -+ } else if (auto locker = TransactionDmaBufLocker::get(entry.state->buffer)) { - locker->add(this); - } - } -diff --git a/src/wayland/transaction_p.h b/src/wayland/transaction_p.h -index 5bcf148aaad..29a9921e81f 100644 ---- a/src/wayland/transaction_p.h -+++ b/src/wayland/transaction_p.h -@@ -33,4 +33,19 @@ private: - std::vector> m_notifiers; - }; - -+class TransactionEventFdLocker : public QObject -+{ -+ Q_OBJECT -+public: -+ TransactionEventFdLocker(Transaction *transaction, FileDescriptor &&eventFd, ClientConnection *client); -+ -+private: -+ void unlock(); -+ -+ Transaction *const m_transaction; -+ const QPointer m_client; -+ const FileDescriptor m_eventFd; -+ QSocketNotifier m_notifier; -+}; -+ - } // namespace KWin -diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp -index 2b02eb2fa69..037b633fc6c 100644 ---- a/src/wayland_server.cpp -+++ b/src/wayland_server.cpp -@@ -41,6 +41,7 @@ - #include "wayland/inputmethod_v1.h" - #include "wayland/keyboard_shortcuts_inhibit_v1.h" - #include "wayland/keystate.h" -+#include "wayland/linux_drm_syncobj_v1.h" - #include "wayland/linuxdmabufv1clientbuffer.h" - #include "wayland/lockscreen_overlay_v1.h" - #include "wayland/output.h" -@@ -811,6 +812,22 @@ QString WaylandServer::socketName() const - return QString(); - } - -+LinuxDrmSyncObjV1Interface *WaylandServer::linuxSyncObj() const -+{ -+ return m_linuxDrmSyncObj; -+} -+ -+void WaylandServer::setRenderBackend(RenderBackend *backend) -+{ -+ if (backend->supportsTimelines()) { -+ if (!m_linuxDrmSyncObj) { -+ m_linuxDrmSyncObj = new LinuxDrmSyncObjV1Interface(m_display, m_display); -+ } -+ } else if (m_linuxDrmSyncObj) { -+ m_linuxDrmSyncObj->remove(); -+ } -+} -+ - #if KWIN_BUILD_SCREENLOCKER - WaylandServer::LockScreenPresentationWatcher::LockScreenPresentationWatcher(WaylandServer *server) - { -diff --git a/src/wayland_server.h b/src/wayland_server.h -index 8eb6f31a176..60dc67d9670 100644 ---- a/src/wayland_server.h -+++ b/src/wayland_server.h -@@ -58,6 +58,8 @@ class XdgSurfaceWindow; - class XdgToplevelWindow; - class PresentationTime; - class XXColorManagerV2; -+class LinuxDrmSyncObjV1Interface; -+class RenderBackend; - - class KWIN_EXPORT WaylandServer : public QObject - { -@@ -226,6 +228,10 @@ public: - return m_xdgActivationIntegration; - } - -+ LinuxDrmSyncObjV1Interface *linuxSyncObj() const; -+ -+ void setRenderBackend(RenderBackend *backend); -+ - Q_SIGNALS: - void windowAdded(KWin::Window *); - void windowRemoved(KWin::Window *); -@@ -284,6 +290,7 @@ private: - TearingControlManagerV1Interface *m_tearingControlInterface = nullptr; - XwaylandShellV1Interface *m_xwaylandShell = nullptr; - PresentationTime *m_presentationTime = nullptr; -+ LinuxDrmSyncObjV1Interface *m_linuxDrmSyncObj = nullptr; - QList m_windows; - InitializationFlags m_initFlags; - QHash m_waylandOutputs; --- -GitLab - - -From 489761e5d772ad11d195c3eb679f6747d1aa2e46 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl -Date: Sat, 6 Apr 2024 18:51:01 +0200 -Subject: [PATCH 2/5] core/syncobjtimeline: make explicit sync use - SYNC_IOC_MERGE instead of waiting on the CPU side - -This brings some performance benefits, because the application can potentially reuse -the buffer earlier, and it simplifies the code a bit - -(cherry picked from commit 4c6000b3e1829da5f0ccb81bbccfee37fb28cd24) ---- - src/core/syncobjtimeline.cpp | 63 +++++++++++++++++++++++++------ - src/core/syncobjtimeline.h | 28 ++++---------- - src/scene/itemrenderer_opengl.cpp | 5 ++- - src/wayland/surface.h | 6 ++- - 4 files changed, 67 insertions(+), 35 deletions(-) - -diff --git a/src/core/syncobjtimeline.cpp b/src/core/syncobjtimeline.cpp -index 3e2c100370a..1152e895722 100644 ---- a/src/core/syncobjtimeline.cpp -+++ b/src/core/syncobjtimeline.cpp -@@ -6,8 +6,24 @@ - #include "syncobjtimeline.h" - - #include -+#include - #include - -+#if defined(Q_OS_LINUX) -+#include -+#else -+struct sync_merge_data -+{ -+ char name[32]; -+ __s32 fd2; -+ __s32 fence; -+ __u32 flags; -+ __u32 pad; -+}; -+#define SYNC_IOC_MAGIC '>' -+#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data) -+#endif -+ - namespace KWin - { - -@@ -19,7 +35,39 @@ SyncReleasePoint::SyncReleasePoint(const std::shared_ptr &timeline - - SyncReleasePoint::~SyncReleasePoint() - { -- m_timeline->signal(m_timelinePoint); -+ if (m_releaseFence.isValid()) { -+ m_timeline->moveInto(m_timelinePoint, m_releaseFence); -+ } else { -+ m_timeline->signal(m_timelinePoint); -+ } -+} -+ -+static FileDescriptor mergeSyncFds(const FileDescriptor &fd1, const FileDescriptor &fd2) -+{ -+ struct sync_merge_data data -+ { -+ .name = "merged release fence", -+ .fd2 = fd2.get(), -+ .fence = -1, -+ }; -+ int err = -1; -+ do { -+ err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data); -+ } while (err == -1 && (errno == EINTR || errno == EAGAIN)); -+ if (err < 0) { -+ return FileDescriptor{}; -+ } else { -+ return FileDescriptor(data.fence); -+ } -+} -+ -+void SyncReleasePoint::addReleaseFence(const FileDescriptor &fd) -+{ -+ if (m_releaseFence.isValid()) { -+ m_releaseFence = mergeSyncFds(m_releaseFence, fd); -+ } else { -+ m_releaseFence = fd.duplicate(); -+ } - } - - SyncTimeline *SyncReleasePoint::timeline() const -@@ -67,17 +115,8 @@ void SyncTimeline::signal(uint64_t timelinePoint) - drmSyncobjTimelineSignal(m_drmFd, &m_handle, &timelinePoint, 1); - } - --SyncReleasePointHolder::SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set> &&releasePoints) -- : m_fence(std::move(requirement)) -- , m_notifier(m_fence.get(), QSocketNotifier::Type::Read) -- , m_releasePoints(std::move(releasePoints)) --{ -- connect(&m_notifier, &QSocketNotifier::activated, this, &SyncReleasePointHolder::signaled); -- m_notifier.setEnabled(true); --} -- --void SyncReleasePointHolder::signaled() -+void SyncTimeline::moveInto(uint64_t timelinePoint, const FileDescriptor &fd) - { -- delete this; -+ drmSyncobjImportSyncFile(m_drmFd, m_handle, fd.get()); - } - } -diff --git a/src/core/syncobjtimeline.h b/src/core/syncobjtimeline.h -index cffdb75e330..4ced3e06272 100644 ---- a/src/core/syncobjtimeline.h -+++ b/src/core/syncobjtimeline.h -@@ -7,11 +7,8 @@ - #include "kwin_export.h" - #include "utils/filedescriptor.h" - --#include --#include - #include - #include --#include - - namespace KWin - { -@@ -30,9 +27,16 @@ public: - SyncTimeline *timeline() const; - uint64_t timelinePoint() const; - -+ /** -+ * Adds the fence of a graphics job that this release point should wait for -+ * before the timeline point is signaled -+ */ -+ void addReleaseFence(const FileDescriptor &fd); -+ - private: - const std::shared_ptr m_timeline; - const uint64_t m_timelinePoint; -+ FileDescriptor m_releaseFence; - }; - - class KWIN_EXPORT SyncTimeline -@@ -47,26 +51,10 @@ public: - FileDescriptor eventFd(uint64_t timelinePoint) const; - - void signal(uint64_t timelinePoint); -+ void moveInto(uint64_t timelinePoint, const FileDescriptor &fd); - - private: - const int32_t m_drmFd; - const uint32_t m_handle; - }; -- --class SyncReleasePointHolder : public QObject --{ -- Q_OBJECT --public: -- /** -- * @param requirement the filedescriptor that needs to be readable before the release points may be signalled. Once that's happened, this object deletes itself!' -- */ -- explicit SyncReleasePointHolder(FileDescriptor &&requirement, std::unordered_set> &&releasePoints); -- --private: -- void signaled(); -- -- const FileDescriptor m_fence; -- QSocketNotifier m_notifier; -- const std::unordered_set> m_releasePoints; --}; - } -diff --git a/src/scene/itemrenderer_opengl.cpp b/src/scene/itemrenderer_opengl.cpp -index 3fee3863f2c..ffcc6de3914 100644 ---- a/src/scene/itemrenderer_opengl.cpp -+++ b/src/scene/itemrenderer_opengl.cpp -@@ -53,7 +53,10 @@ void ItemRendererOpenGL::endFrame() - if (m_eglDisplay) { - EGLNativeFence fence(m_eglDisplay); - if (fence.isValid()) { -- new SyncReleasePointHolder(std::move(fence.fileDescriptor()), std::move(m_releasePoints)); -+ for (const auto &releasePoint : m_releasePoints) { -+ releasePoint->addReleaseFence(fence.fileDescriptor()); -+ } -+ m_releasePoints.clear(); - } - } - m_releasePoints.clear(); -diff --git a/src/wayland/surface.h b/src/wayland/surface.h -index 80d1fa55708..152f1accc10 100644 ---- a/src/wayland/surface.h -+++ b/src/wayland/surface.h -@@ -344,8 +344,10 @@ public: - void setPreferredColorDescription(const ColorDescription &descr); - - /** -- * @returns the release point that should be referenced as long as the buffer on this surface -- * is, or may still be used by the compositor -+ * Returns the current release point for the buffer on this surface. The buffer keeps the -+ * release point referenced as long as it's referenced itself; for synchronization on the -+ * GPU side, the compositor has to either keep the release point referenced as long as the -+ * GPU task is running, or add a fence for each GPU task to the release point - */ - std::shared_ptr bufferReleasePoint() const; - --- -GitLab - - -From eef4cbe0278e81c33b496932400854a74a08bfa4 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl -Date: Tue, 16 Apr 2024 13:51:42 +0200 -Subject: [PATCH 3/5] wayland_server: guard against DRM_IOCTL_SYNCOBJ_EVENTFD - being broken - -...either because it's not implemented, or because it's buggy. - -(cherry picked from commit 26afbfb6fa030c3dadf6a22309686f96ca033f59) ---- - src/wayland_server.cpp | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/src/wayland_server.cpp b/src/wayland_server.cpp -index 037b633fc6c..d9240f0e8ce 100644 ---- a/src/wayland_server.cpp -+++ b/src/wayland_server.cpp -@@ -19,6 +19,7 @@ - #include "layershellv1window.h" - #include "main.h" - #include "options.h" -+#include "utils/kernel.h" - #include "utils/serviceutils.h" - #include "virtualdesktops.h" - #include "wayland/appmenu.h" -@@ -820,6 +821,15 @@ LinuxDrmSyncObjV1Interface *WaylandServer::linuxSyncObj() const - void WaylandServer::setRenderBackend(RenderBackend *backend) - { - if (backend->supportsTimelines()) { -+ // ensure the DRM_IOCTL_SYNCOBJ_EVENTFD ioctl is supported -+ const auto linuxVersion = linuxKernelVersion(); -+ if (linuxVersion.majorVersion() < 6 && linuxVersion.minorVersion() < 6) { -+ return; -+ } -+ // also ensure the implementation isn't totally broken, see https://lists.freedesktop.org/archives/dri-devel/2024-January/439101.html -+ if (linuxVersion.majorVersion() == 6 && (linuxVersion.minorVersion() == 7 || (linuxVersion.minorVersion() == 6 && linuxVersion.patchVersion() < 19))) { -+ return; -+ } - if (!m_linuxDrmSyncObj) { - m_linuxDrmSyncObj = new LinuxDrmSyncObjV1Interface(m_display, m_display); - } --- -GitLab - - -From 2e9ecb0edf137309fb526adc7c8504e8c669b17f Mon Sep 17 00:00:00 2001 -From: Erik Kurzinger -Date: Tue, 16 Apr 2024 14:44:50 -0700 -Subject: [PATCH 4/5] core/syncobjtimeline: import release fence at correct - timeline point - -SyncTimeline::moveInto imports the provided fence to the syncobj by -calling drmSyncobjImportSyncFile. However, that function assumes the -syncobj a binary syncobj, meaning the fence will be imported at timeline -point 0, not at the intended timeline point. - -Since there is no timeline equivalent of drmSyncobjImportSyncFile, to -achieve the correct behavior we create a temporary binary syncobj, -import the fence into that, and then use drmSyncobjTransfer to transfer -the fence to the desired timeline point on the destination syncobj. - -Signed-off-by: Erik Kurzinger -(cherry picked from commit 9ca7b9b1cf292e790223419dc197737f875109d4) ---- - src/core/syncobjtimeline.cpp | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/src/core/syncobjtimeline.cpp b/src/core/syncobjtimeline.cpp -index 1152e895722..80054e93480 100644 ---- a/src/core/syncobjtimeline.cpp -+++ b/src/core/syncobjtimeline.cpp -@@ -117,6 +117,10 @@ void SyncTimeline::signal(uint64_t timelinePoint) - - void SyncTimeline::moveInto(uint64_t timelinePoint, const FileDescriptor &fd) - { -- drmSyncobjImportSyncFile(m_drmFd, m_handle, fd.get()); -+ uint32_t tempHandle = 0; -+ drmSyncobjCreate(m_drmFd, 0, &tempHandle); -+ drmSyncobjImportSyncFile(m_drmFd, tempHandle, fd.get()); -+ drmSyncobjTransfer(m_drmFd, m_handle, timelinePoint, tempHandle, 0, 0); -+ drmSyncobjDestroy(m_drmFd, tempHandle); - } - } --- -GitLab - - -From 463ae633e878004b1799f618641a0c44573c10f4 Mon Sep 17 00:00:00 2001 -From: Xaver Hugl -Date: Wed, 17 Apr 2024 03:26:34 +0200 -Subject: [PATCH 5/5] wayland/surface: fix the change signal for release points - not being emitted - -(cherry picked from commit eed7943939524895225ab4cf4eb3a1fa880b42bf) ---- - src/wayland/surface.cpp | 2 +- - src/wayland/surface_p.h | 1 - - 2 files changed, 1 insertion(+), 2 deletions(-) - -diff --git a/src/wayland/surface.cpp b/src/wayland/surface.cpp -index 6a33c5fca10..6a77e98d0ee 100644 ---- a/src/wayland/surface.cpp -+++ b/src/wayland/surface.cpp -@@ -608,7 +608,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next) - const bool visibilityChanged = bufferChanged && bool(current->buffer) != bool(next->buffer); - const bool colorDescriptionChanged = next->colorDescriptionIsSet; - const bool presentationModeHintChanged = next->presentationModeHintIsSet; -- const bool bufferReleasePointChanged = next->releasePointIsSet; -+ const bool bufferReleasePointChanged = next->bufferIsSet && current->releasePoint != next->releasePoint; - - const QSizeF oldSurfaceSize = surfaceSize; - const QSize oldBufferSize = bufferSize; -diff --git a/src/wayland/surface_p.h b/src/wayland/surface_p.h -index 775f9d7bd2e..7bcf95c0bef 100644 ---- a/src/wayland/surface_p.h -+++ b/src/wayland/surface_p.h -@@ -59,7 +59,6 @@ struct SurfaceState - bool contentTypeIsSet = false; - bool presentationModeHintIsSet = false; - bool colorDescriptionIsSet = false; -- bool releasePointIsSet = false; - qint32 bufferScale = 1; - OutputTransform bufferTransform = OutputTransform::Normal; - wl_list frameCallbacks; --- -GitLab - diff --git a/overlays/kwin/default.nix b/overlays/kwin/default.nix deleted file mode 100644 index d766a6e..0000000 --- a/overlays/kwin/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -self: super: { - kdePackages = super.kdePackages.overrideScope (kde-self: kde-super: rec { - kwin = kde-super.kwin.overrideAttrs (oldAttrs: rec { - patches = oldAttrs.patches ++ [ - ./5511.patch # https://invent.kde.org/plasma/kwin/-/merge_requests/5511 - ]; - }); - }); -} \ No newline at end of file