From b89009f9e18af6ce9331487f7a6a7308c5e2be26 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 17 Jan 2023 16:27:58 +0100 Subject: [PATCH] plugins/screencast: send frame callbacks if the window is otherwise invisible If we don't send frame callbacks, the application might stop rendering or throttle to single digit fps. BUG: 464217 --- .../screencast/windowscreencastsource.cpp | 2 +- .../screencast/windowscreencastsource.h | 5 ++- src/window.cpp | 40 +++++++++++++++++++ src/window.h | 19 +++++++++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/src/plugins/screencast/windowscreencastsource.cpp b/src/plugins/screencast/windowscreencastsource.cpp index b675bf0b9a..1d1f345a19 100644 --- a/src/plugins/screencast/windowscreencastsource.cpp +++ b/src/plugins/screencast/windowscreencastsource.cpp @@ -18,7 +18,6 @@ #include "scene/itemrenderer.h" #include "scene/windowitem.h" #include "scene/workspacescene.h" -#include "window.h" namespace KWin { @@ -26,6 +25,7 @@ namespace KWin WindowScreenCastSource::WindowScreenCastSource(Window *window, QObject *parent) : ScreenCastSource(parent) , m_window(window) + , m_offscreenRef(window) { connect(m_window, &Window::windowClosed, this, &ScreenCastSource::closed); } diff --git a/src/plugins/screencast/windowscreencastsource.h b/src/plugins/screencast/windowscreencastsource.h index 6d10eb58cb..3e8bf8595f 100644 --- a/src/plugins/screencast/windowscreencastsource.h +++ b/src/plugins/screencast/windowscreencastsource.h @@ -7,14 +7,14 @@ #pragma once #include "screencastsource.h" +#include "window.h" #include +#include namespace KWin { -class Window; - class WindowScreenCastSource : public ScreenCastSource { Q_OBJECT @@ -31,6 +31,7 @@ public: private: QPointer m_window; + WindowOffscreenRenderRef m_offscreenRef; }; } // namespace KWin diff --git a/src/window.cpp b/src/window.cpp index 73a006b1d2..d3b59906db 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -119,6 +119,7 @@ Window::Window() connect(Workspace::self()->applicationMenu(), &ApplicationMenu::applicationMenuEnabledChanged, this, [this] { Q_EMIT hasApplicationMenuChanged(hasApplicationMenu()); }); + connect(&m_offscreenFramecallbackTimer, &QTimer::timeout, this, &Window::maybeSendFrameCallback); } Window::~Window() @@ -4537,6 +4538,45 @@ bool Window::isLockScreenOverlay() const return m_lockScreenOverlay; } +void Window::refOffscreenRendering() +{ + if (m_offscreenRenderCount == 0) { + m_offscreenFramecallbackTimer.start(1'000'000 / output()->refreshRate()); + } + m_offscreenRenderCount++; +} + +void Window::unrefOffscreenRendering() +{ + Q_ASSERT(m_offscreenRenderCount); + m_offscreenRenderCount--; + if (m_offscreenRenderCount == 0) { + m_offscreenFramecallbackTimer.stop(); + } +} + +void Window::maybeSendFrameCallback() +{ + if (m_surface && !m_windowItem->isVisible()) { + m_surface->frameRendered(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count()); + // update refresh rate, it might have changed + m_offscreenFramecallbackTimer.start(1'000'000 / output()->refreshRate()); + } +} + +WindowOffscreenRenderRef::WindowOffscreenRenderRef(Window *window) + : m_window(window) +{ + window->refOffscreenRendering(); +} + +WindowOffscreenRenderRef::~WindowOffscreenRenderRef() +{ + if (m_window) { + m_window->unrefOffscreenRendering(); + } +} + } // namespace KWin #include "moc_window.cpp" diff --git a/src/window.h b/src/window.h index 2b3a94e5cb..8c91ca0da2 100644 --- a/src/window.h +++ b/src/window.h @@ -27,6 +27,7 @@ #include #include #include +#include #include class QMouseEvent; @@ -1429,6 +1430,9 @@ public: void setTile(Tile *tile); + void refOffscreenRendering(); + void unrefOffscreenRendering(); + public Q_SLOTS: virtual void closeWindow() = 0; @@ -1913,6 +1917,8 @@ private Q_SLOTS: void shadeUnhover(); private: + void maybeSendFrameCallback(); + // when adding new data members, check also copyToDeleted() QUuid m_internalId; Xcb::Window m_client; @@ -2029,6 +2035,8 @@ private: WindowRules m_rules; quint32 m_lastUsageSerial = 0; bool m_lockScreenOverlay = false; + uint32_t m_offscreenRenderCount = 0; + QTimer m_offscreenFramecallbackTimer; }; /** @@ -2375,6 +2383,17 @@ inline void Window::setPendingMoveResizeMode(MoveResizeMode mode) KWIN_EXPORT QDebug operator<<(QDebug debug, const Window *window); +class KWIN_EXPORT WindowOffscreenRenderRef +{ +public: + WindowOffscreenRenderRef(Window *window); + WindowOffscreenRenderRef() = default; + ~WindowOffscreenRenderRef(); + +private: + QPointer m_window; +}; + } // namespace KWin Q_DECLARE_METATYPE(KWin::Window *)