2027 lines
73 KiB
Diff
2027 lines
73 KiB
Diff
From e1791de663807bc93c09418481cb844c7daeb8f7 Mon Sep 17 00:00:00 2001
|
|
From: Xaver Hugl <xaver.hugl@gmail.com>
|
|
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<SyncTimeline> 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<SyncTimeline>(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<EglContext> contextForGpu(DrmGpu *gpu);
|
|
|
|
+ bool supportsTimelines() const override;
|
|
+ std::unique_ptr<SyncTimeline> 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<drmVersion> 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<WorkspaceSceneOpenGL>(backend.get());
|
|
- m_cursorScene = std::make_unique<CursorScene>(std::make_unique<ItemRendererOpenGL>());
|
|
+ m_cursorScene = std::make_unique<CursorScene>(std::make_unique<ItemRendererOpenGL>(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<SyncReleasePoint> &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<SyncReleasePoint> &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<std::shared_ptr<SyncReleasePoint>> 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 <drm_fourcc.h>
|
|
|
|
@@ -103,6 +104,16 @@ std::unique_ptr<SurfaceTexture> RenderBackend::createSurfaceTextureWayland(Surfa
|
|
return nullptr;
|
|
}
|
|
|
|
+bool RenderBackend::supportsTimelines() const
|
|
+{
|
|
+ return false;
|
|
+}
|
|
+
|
|
+std::unique_ptr<SyncTimeline> 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 <QObject>
|
|
|
|
@@ -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<SurfaceTexture> createSurfaceTextureX11(SurfacePixmapX11 *pixmap);
|
|
virtual std::unique_ptr<SurfaceTexture> createSurfaceTextureWayland(SurfacePixmap *pixmap);
|
|
+
|
|
+ virtual bool supportsTimelines() const;
|
|
+ virtual std::unique_ptr<SyncTimeline> 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 <xaver.hugl@gmail.com>
|
|
+
|
|
+ SPDX-License-Identifier: GPL-2.0-or-later
|
|
+*/
|
|
+#include "syncobjtimeline.h"
|
|
+
|
|
+#include <sys/eventfd.h>
|
|
+#include <xf86drm.h>
|
|
+
|
|
+namespace KWin
|
|
+{
|
|
+
|
|
+SyncReleasePoint::SyncReleasePoint(const std::shared_ptr<SyncTimeline> &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<std::shared_ptr<SyncReleasePoint>> &&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 <xaver.hugl@gmail.com>
|
|
+
|
|
+ SPDX-License-Identifier: GPL-2.0-or-later
|
|
+*/
|
|
+#pragma once
|
|
+#include "kwin_export.h"
|
|
+#include "utils/filedescriptor.h"
|
|
+
|
|
+#include <QObject>
|
|
+#include <QSocketNotifier>
|
|
+#include <memory>
|
|
+#include <stdint.h>
|
|
+#include <unordered_set>
|
|
+
|
|
+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<SyncTimeline> &timeline, uint64_t timelinePoint);
|
|
+ ~SyncReleasePoint();
|
|
+
|
|
+ SyncTimeline *timeline() const;
|
|
+ uint64_t timelinePoint() const;
|
|
+
|
|
+private:
|
|
+ const std::shared_ptr<SyncTimeline> 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<std::shared_ptr<SyncReleasePoint>> &&releasePoints);
|
|
+
|
|
+private:
|
|
+ void signaled();
|
|
+
|
|
+ const FileDescriptor m_fence;
|
|
+ QSocketNotifier m_notifier;
|
|
+ const std::unordered_set<std::shared_ptr<SyncReleasePoint>> 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<std::shared_ptr<GLTexture>, 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<DecorationItem *>(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<SurfaceItem *>(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 <unordered_set>
|
|
+
|
|
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<SyncReleasePoint> 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<std::shared_ptr<SyncReleasePoint>> 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<SyncReleasePoint> 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<SyncReleasePoint> bufferReleasePoint() const;
|
|
+
|
|
QRegion mapFromBuffer(const QRegion ®ion) const;
|
|
|
|
void addDamage(const QRegion ®ion);
|
|
@@ -82,6 +84,7 @@ protected:
|
|
std::deque<std::chrono::nanoseconds> m_lastDamageTimeDiffs;
|
|
std::optional<std::chrono::steady_clock::time_point> m_lastDamage;
|
|
std::chrono::nanoseconds m_frameTimeEstimation = std::chrono::days(1000);
|
|
+ std::shared_ptr<SyncReleasePoint> 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<SurfacePixmap> 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<ItemRendererOpenGL>())
|
|
+ : WorkspaceScene(std::make_unique<ItemRendererOpenGL>(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 <xaver.hugl@gmail.com>
|
|
+
|
|
+ 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 <xf86drm.h>
|
|
+
|
|
+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<SyncTimeline> &&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<SyncTimeline> 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<LinuxDrmSyncObjTimelineV1 *>(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<LinuxDrmSyncObjTimelineV1 *>(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<SyncReleasePoint>(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 <xaver.hugl@gmail.com>
|
|
+
|
|
+ SPDX-License-Identifier: GPL-2.0-or-later
|
|
+*/
|
|
+#pragma once
|
|
+
|
|
+#include "kwin_export.h"
|
|
+#include "qwayland-server-linux-drm-syncobj-v1.h"
|
|
+
|
|
+#include <QObject>
|
|
+#include <QPointer>
|
|
+
|
|
+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<RenderBackend> 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<SurfaceInterface> 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 <xaver.hugl@gmail.com>
|
|
+
|
|
+ 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<SyncTimeline> &&timeline);
|
|
+ ~LinuxDrmSyncObjTimelineV1() override;
|
|
+
|
|
+ /**
|
|
+ * May return nullptr if the timeline resource is inert
|
|
+ */
|
|
+ std::shared_ptr<SyncTimeline> 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<SyncTimeline> 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 @@
|
|
+<?xml version="1.0" encoding="UTF-8"?>
|
|
+<protocol name="linux_drm_syncobj_v1">
|
|
+ <copyright>
|
|
+ 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.
|
|
+ </copyright>
|
|
+
|
|
+ <description summary="protocol for providing explicit synchronization">
|
|
+ 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.
|
|
+ </description>
|
|
+
|
|
+ <interface name="wp_linux_drm_syncobj_manager_v1" version="1">
|
|
+ <description summary="global for providing explicit synchronization">
|
|
+ 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.
|
|
+ </description>
|
|
+
|
|
+ <request name="destroy" type="destructor">
|
|
+ <description summary="destroy explicit synchronization factory object">
|
|
+ Destroy this explicit synchronization factory object. Other objects
|
|
+ shall not be affected by this request.
|
|
+ </description>
|
|
+ </request>
|
|
+
|
|
+ <enum name="error">
|
|
+ <entry name="surface_exists" value="0"
|
|
+ summary="the surface already has a synchronization object associated"/>
|
|
+ <entry name="invalid_timeline" value="1"
|
|
+ summary="the timeline object could not be imported"/>
|
|
+ </enum>
|
|
+
|
|
+ <request name="get_surface">
|
|
+ <description summary="extend surface interface for explicit synchronization">
|
|
+ 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.
|
|
+ </description>
|
|
+ <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_surface_v1"
|
|
+ summary="the new synchronization surface object id"/>
|
|
+ <arg name="surface" type="object" interface="wl_surface"
|
|
+ summary="the surface"/>
|
|
+ </request>
|
|
+
|
|
+ <request name="import_timeline">
|
|
+ <description summary="import a DRM syncobj timeline">
|
|
+ Import a DRM synchronization object timeline.
|
|
+
|
|
+ If the FD cannot be imported, the invalid_timeline error is raised.
|
|
+ </description>
|
|
+ <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_timeline_v1"/>
|
|
+ <arg name="fd" type="fd" summary="drm_syncobj file descriptor"/>
|
|
+ </request>
|
|
+ </interface>
|
|
+
|
|
+ <interface name="wp_linux_drm_syncobj_timeline_v1" version="1">
|
|
+ <description summary="synchronization object timeline">
|
|
+ This object represents an explicit synchronization object timeline
|
|
+ imported by the client to the compositor.
|
|
+ </description>
|
|
+
|
|
+ <request name="destroy" type="destructor">
|
|
+ <description summary="destroy the timeline">
|
|
+ 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.
|
|
+ </description>
|
|
+ </request>
|
|
+ </interface>
|
|
+
|
|
+ <interface name="wp_linux_drm_syncobj_surface_v1" version="1">
|
|
+ <description summary="per-surface explicit synchronization">
|
|
+ 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.
|
|
+ </description>
|
|
+
|
|
+ <request name="destroy" type="destructor">
|
|
+ <description summary="destroy the surface synchronization object">
|
|
+ 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.
|
|
+ </description>
|
|
+ </request>
|
|
+
|
|
+ <enum name="error">
|
|
+ <entry name="no_surface" value="1"
|
|
+ summary="the associated wl_surface was destroyed"/>
|
|
+ <entry name="unsupported_buffer" value="2"
|
|
+ summary="the buffer does not support explicit synchronization"/>
|
|
+ <entry name="no_buffer" value="3" summary="no buffer was attached"/>
|
|
+ <entry name="no_acquire_point" value="4"
|
|
+ summary="no acquire timeline point was set"/>
|
|
+ <entry name="no_release_point" value="5"
|
|
+ summary="no release timeline point was set"/>
|
|
+ <entry name="conflicting_points" value="6"
|
|
+ summary="acquire and release timeline points are in conflict"/>
|
|
+ </enum>
|
|
+
|
|
+ <request name="set_acquire_point">
|
|
+ <description summary="set the acquire timeline point">
|
|
+ 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.
|
|
+ </description>
|
|
+ <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
|
|
+ <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
|
|
+ <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
|
|
+ </request>
|
|
+
|
|
+ <request name="set_release_point">
|
|
+ <description summary="set the release timeline point">
|
|
+ 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.
|
|
+ </description>
|
|
+ <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
|
|
+ <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
|
|
+ <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
|
|
+ </request>
|
|
+ </interface>
|
|
+</protocol>
|
|
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<void(SurfaceInterface *surface
|
|
}
|
|
}
|
|
|
|
+std::shared_ptr<SyncReleasePoint> 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<SyncReleasePoint> 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<PresentationTimeFeedback> presentationFeedback;
|
|
+ struct
|
|
+ {
|
|
+ std::shared_ptr<SyncTimeline> timeline;
|
|
+ uint64_t point = 0;
|
|
+ } acquirePoint;
|
|
+ std::shared_ptr<SyncReleasePoint> 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<std::unique_ptr<QSocketNotifier>> 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<ClientConnection> 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<Window *> m_windows;
|
|
InitializationFlags m_initFlags;
|
|
QHash<Output *, OutputInterface *> m_waylandOutputs;
|
|
--
|
|
GitLab
|
|
|
|
|
|
From 489761e5d772ad11d195c3eb679f6747d1aa2e46 Mon Sep 17 00:00:00 2001
|
|
From: Xaver Hugl <xaver.hugl@gmail.com>
|
|
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 <sys/eventfd.h>
|
|
+#include <sys/ioctl.h>
|
|
#include <xf86drm.h>
|
|
|
|
+#if defined(Q_OS_LINUX)
|
|
+#include <linux/sync_file.h>
|
|
+#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<SyncTimeline> &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<std::shared_ptr<SyncReleasePoint>> &&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 <QObject>
|
|
-#include <QSocketNotifier>
|
|
#include <memory>
|
|
#include <stdint.h>
|
|
-#include <unordered_set>
|
|
|
|
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<SyncTimeline> 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<std::shared_ptr<SyncReleasePoint>> &&releasePoints);
|
|
-
|
|
-private:
|
|
- void signaled();
|
|
-
|
|
- const FileDescriptor m_fence;
|
|
- QSocketNotifier m_notifier;
|
|
- const std::unordered_set<std::shared_ptr<SyncReleasePoint>> 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<SyncReleasePoint> bufferReleasePoint() const;
|
|
|
|
--
|
|
GitLab
|
|
|
|
|
|
From eef4cbe0278e81c33b496932400854a74a08bfa4 Mon Sep 17 00:00:00 2001
|
|
From: Xaver Hugl <xaver.hugl@gmail.com>
|
|
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 <ekurzinger@nvidia.com>
|
|
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 <ekurzinger@nvidia.com>
|
|
(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 <xaver.hugl@gmail.com>
|
|
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
|
|
|