From c6be2b51a935b15f84ed9187db98effbfc52fcef Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 13 Feb 2024 16:29:48 +0100 Subject: [PATCH] backends/wayland: support direct scanout This allows for (mostly) overhead-less pass-through of fullscreen content to the host compositor --- src/backends/wayland/wayland_egl_backend.cpp | 25 +++++++++++++++++--- src/backends/wayland/wayland_egl_backend.h | 4 ++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/backends/wayland/wayland_egl_backend.cpp b/src/backends/wayland/wayland_egl_backend.cpp index 0f75f024ea..11cd60168d 100644 --- a/src/backends/wayland/wayland_egl_backend.cpp +++ b/src/backends/wayland/wayland_egl_backend.cpp @@ -14,6 +14,8 @@ #include "opengl/glrendertimequery.h" #include "opengl/glutils.h" #include "platformsupport/scenes/opengl/basiceglsurfacetexture_wayland.h" +#include "scene/surfaceitem_wayland.h" +#include "wayland/surface.h" #include "wayland_backend.h" #include "wayland_display.h" #include "wayland_logging.h" @@ -109,17 +111,34 @@ bool WaylandEglPrimaryLayer::endFrame(const QRegion &renderedRegion, const QRegi return true; } +bool WaylandEglPrimaryLayer::scanout(SurfaceItem *surfaceItem) +{ + Q_ASSERT(!m_presentationBuffer); + if (surfaceItem->size() != m_waylandOutput->modeSize()) { + return false; + } + SurfaceItemWayland *item = qobject_cast(surfaceItem); + if (!item || !item->surface() || item->surface()->bufferTransform() != OutputTransform::Kind::Normal) { + return false; + } + m_presentationBuffer = m_backend->backend()->importBuffer(item->surface()->buffer()); + return m_presentationBuffer; +} + void WaylandEglPrimaryLayer::present() { - wl_buffer *buffer = m_backend->backend()->importBuffer(m_buffer->buffer()); - Q_ASSERT(buffer); + if (!m_presentationBuffer) { + m_presentationBuffer = m_backend->backend()->importBuffer(m_buffer->buffer()); + Q_ASSERT(m_presentationBuffer); + } KWayland::Client::Surface *surface = m_waylandOutput->surface(); - surface->attachBuffer(buffer); + surface->attachBuffer(m_presentationBuffer); surface->damage(m_damageJournal.lastDamage()); surface->setScale(std::ceil(m_waylandOutput->scale())); surface->commit(); Q_EMIT m_waylandOutput->outputChange(m_damageJournal.lastDamage()); + m_presentationBuffer = nullptr; m_swapchain->release(m_buffer); } diff --git a/src/backends/wayland/wayland_egl_backend.h b/src/backends/wayland/wayland_egl_backend.h index c4da34c46e..3a7bdac382 100644 --- a/src/backends/wayland/wayland_egl_backend.h +++ b/src/backends/wayland/wayland_egl_backend.h @@ -15,6 +15,8 @@ #include +struct wl_buffer; + namespace KWin { class EglSwapchainSlot; @@ -42,6 +44,7 @@ public: std::optional beginFrame() override; bool endFrame(const QRegion &renderedRegion, const QRegion &damagedRegion) override; std::chrono::nanoseconds queryRenderTime() const override; + bool scanout(SurfaceItem *surfaceItem) override; private: WaylandOutput *m_waylandOutput; @@ -50,6 +53,7 @@ private: std::shared_ptr m_buffer; std::unique_ptr m_query; WaylandEglBackend *const m_backend; + wl_buffer *m_presentationBuffer = nullptr; friend class WaylandEglBackend; };