From 15080192f747d361d295b752b66e2241e5bad6a8 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 12 Sep 2023 18:13:49 +0200 Subject: [PATCH] Remove latency policy and render time estimator settings As KWin measures render times properly now, these settings and estimations should no longer be necessary, so this commit replaces them with one hardcoded algorithm that should prevent most dropped frames and reduce latency --- src/core/renderjournal.cpp | 36 ++++--------- src/core/renderjournal.h | 19 ++----- src/core/renderloop.cpp | 52 ++----------------- src/core/renderloop.h | 27 ---------- src/core/renderloop_p.h | 1 - src/effects.cpp | 9 ---- src/kcms/compositing/compositing.ui | 36 ------------- src/kcms/compositing/kwincompositing.json | 5 +- .../compositing/kwincompositing_setting.kcfg | 11 ---- src/kwin.kcfg | 18 ------- src/options.cpp | 32 ------------ src/options.h | 28 ---------- 12 files changed, 21 insertions(+), 253 deletions(-) diff --git a/src/core/renderjournal.cpp b/src/core/renderjournal.cpp index 492602e66f..756eafe8ac 100644 --- a/src/core/renderjournal.cpp +++ b/src/core/renderjournal.cpp @@ -15,36 +15,20 @@ RenderJournal::RenderJournal() void RenderJournal::add(std::chrono::nanoseconds renderTime) { - if (m_log.count() >= m_size) { - m_log.dequeue(); + if (renderTime > m_result || !m_lastAdd) { + m_result = renderTime; + } else { + static constexpr std::chrono::nanoseconds timeConstant = std::chrono::milliseconds(500); + const auto timeDifference = std::chrono::steady_clock::now() - *m_lastAdd; + const double ratio = std::min(0.1, double(timeDifference.count()) / double(timeConstant.count())); + m_result = std::chrono::nanoseconds(int64_t(renderTime.count() * ratio + m_result.count() * (1 - ratio))); } - m_log.enqueue(renderTime); + m_lastAdd = std::chrono::steady_clock::now(); } -std::chrono::nanoseconds RenderJournal::minimum() const +std::chrono::nanoseconds RenderJournal::result() const { - auto it = std::min_element(m_log.constBegin(), m_log.constEnd()); - return it != m_log.constEnd() ? (*it) : std::chrono::nanoseconds::zero(); -} - -std::chrono::nanoseconds RenderJournal::maximum() const -{ - auto it = std::max_element(m_log.constBegin(), m_log.constEnd()); - return it != m_log.constEnd() ? (*it) : std::chrono::nanoseconds::zero(); -} - -std::chrono::nanoseconds RenderJournal::average() const -{ - if (m_log.isEmpty()) { - return std::chrono::nanoseconds::zero(); - } - - std::chrono::nanoseconds result = std::chrono::nanoseconds::zero(); - for (const std::chrono::nanoseconds &entry : m_log) { - result += entry; - } - - return result / m_log.count(); + return m_result; } } // namespace KWin diff --git a/src/core/renderjournal.h b/src/core/renderjournal.h index dfbb059126..244cf7d5c2 100644 --- a/src/core/renderjournal.h +++ b/src/core/renderjournal.h @@ -25,24 +25,11 @@ public: void add(std::chrono::nanoseconds renderTime); - /** - * Returns the maximum estimated amount of time that it takes to render a single frame. - */ - std::chrono::nanoseconds maximum() const; - - /** - * Returns the minimum estimated amount of time that it takes to render a single frame. - */ - std::chrono::nanoseconds minimum() const; - - /** - * Returns the average estimated amount of time that it takes to render a single frame. - */ - std::chrono::nanoseconds average() const; + std::chrono::nanoseconds result() const; private: - QQueue m_log; - int m_size = 15; + std::chrono::nanoseconds m_result{0}; + std::optional m_lastAdd; }; } // namespace KWin diff --git a/src/core/renderloop.cpp b/src/core/renderloop.cpp index 77484f2946..90d50c77bc 100644 --- a/src/core/renderloop.cpp +++ b/src/core/renderloop.cpp @@ -56,40 +56,11 @@ void RenderLoopPrivate::scheduleRepaint() } // Estimate when it's a good time to perform the next compositing cycle. + // this safety margin is required for + // - the buffer readiness deadline in the drm backend, which is 1.8ms before vblank + // - scheduling and timer inaccuracies (estimated to be up to 1.2ms here) const std::chrono::nanoseconds safetyMargin = std::chrono::milliseconds(3); - - std::chrono::nanoseconds renderTime; - switch (q->latencyPolicy()) { - case KWin::RenderLoop::LatencyExtremelyLow: - renderTime = std::chrono::nanoseconds(long(vblankInterval.count() * 0.1)); - break; - case KWin::RenderLoop::LatencyLow: - renderTime = std::chrono::nanoseconds(long(vblankInterval.count() * 0.25)); - break; - case KWin::RenderLoop::LatencyMedium: - renderTime = std::chrono::nanoseconds(long(vblankInterval.count() * 0.5)); - break; - case KWin::RenderLoop::LatencyHigh: - renderTime = std::chrono::nanoseconds(long(vblankInterval.count() * 0.75)); - break; - case KWin::RenderLoop::LatencyExtremelyHigh: - renderTime = std::chrono::nanoseconds(long(vblankInterval.count() * 0.9)); - break; - } - - switch (options->renderTimeEstimator()) { - case RenderTimeEstimatorMinimum: - renderTime = std::max(renderTime, renderJournal.minimum()); - break; - case RenderTimeEstimatorMaximum: - renderTime = std::max(renderTime, renderJournal.maximum()); - break; - case RenderTimeEstimatorAverage: - renderTime = std::max(renderTime, renderJournal.average()); - break; - } - - std::chrono::nanoseconds nextRenderTimestamp = nextPresentationTimestamp - renderTime - safetyMargin; + std::chrono::nanoseconds nextRenderTimestamp = nextPresentationTimestamp - renderJournal.result() - safetyMargin; // If we can't render the frame before the deadline, start compositing immediately. if (nextRenderTimestamp < currentTime) { @@ -239,21 +210,6 @@ void RenderLoop::scheduleRepaint(Item *item) } } -KWin::RenderLoop::LatencyPolicy RenderLoop::latencyPolicy() const -{ - return d->latencyPolicy.value_or(options->latencyPolicy()); -} - -void RenderLoop::setLatencyPolicy(LatencyPolicy policy) -{ - d->latencyPolicy = policy; -} - -void RenderLoop::resetLatencyPolicy() -{ - d->latencyPolicy.reset(); -} - std::chrono::nanoseconds RenderLoop::lastPresentationTimestamp() const { return d->lastPresentationTimestamp; diff --git a/src/core/renderloop.h b/src/core/renderloop.h index 19fd02a908..4f726b6644 100644 --- a/src/core/renderloop.h +++ b/src/core/renderloop.h @@ -109,33 +109,6 @@ public: */ void setVrrPolicy(VrrPolicy vrrPolicy); - /** - * This enum type specifies the latency level configured by the user. - */ - enum LatencyPolicy { - LatencyExtremelyLow, - LatencyLow, - LatencyMedium, - LatencyHigh, - LatencyExtremelyHigh, - }; - Q_ENUM(LatencyPolicy) - /** - * Returns the latency policy for this render loop. - */ - LatencyPolicy latencyPolicy() const; - - /** - * Sets the latecy policy of this render loop to @a policy. By default, - * the latency policy of this render loop matches options->latencyPolicy(). - */ - void setLatencyPolicy(LatencyPolicy policy); - - /** - * Resets the latency policy to the default value. - */ - void resetLatencyPolicy(); - Q_SIGNALS: /** * This signal is emitted when the refresh rate of this RenderLoop has changed. diff --git a/src/core/renderloop_p.h b/src/core/renderloop_p.h index 763be9d289..ca1b3be979 100644 --- a/src/core/renderloop_p.h +++ b/src/core/renderloop_p.h @@ -44,7 +44,6 @@ public: bool pendingReschedule = false; bool pendingRepaint = false; RenderLoop::VrrPolicy vrrPolicy = RenderLoop::VrrPolicy::Never; - std::optional latencyPolicy; Item *fullscreenItem = nullptr; bool allowTearing = false; diff --git a/src/effects.cpp b/src/effects.cpp index 5189f83ea5..f6dbbcbb90 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -386,15 +386,6 @@ void EffectsHandlerImpl::setActiveFullScreenEffect(Effect *e) fullscreen_effect = e; Q_EMIT activeFullScreenEffectChanged(); if (activeChanged) { - const auto delegates = m_scene->delegates(); - for (SceneDelegate *delegate : delegates) { - RenderLoop *loop = delegate->layer()->loop(); - if (fullscreen_effect) { - loop->setLatencyPolicy(KWin::RenderLoop::LatencyPolicy::LatencyExtremelyHigh); - } else { - loop->resetLatencyPolicy(); - } - } Q_EMIT hasActiveFullScreenEffectChanged(); workspace()->screenEdges()->checkBlocking(); } diff --git a/src/kcms/compositing/compositing.ui b/src/kcms/compositing/compositing.ui index 2810f6676d..d8bf341f24 100644 --- a/src/kcms/compositing/compositing.ui +++ b/src/kcms/compositing/compositing.ui @@ -171,42 +171,6 @@ you can reset this protection but be aware that this might result in an immediat - - - - Latency: - - - - - - - - Force lowest latency (may cause dropped frames) - - - - - Prefer lower latency - - - - - Balance of latency and smoothness - - - - - Prefer smoother animations - - - - - Force smoothest animations - - - - diff --git a/src/kcms/compositing/kwincompositing.json b/src/kcms/compositing/kwincompositing.json index c18d552b55..4224d7c5f9 100644 --- a/src/kcms/compositing/kwincompositing.json +++ b/src/kcms/compositing/kwincompositing.json @@ -114,5 +114,8 @@ "X-KDE-Keywords[x-test]": "xxkwinxx,xxwindowxx,xxmanagerxx,xxcompositingxx,xxcompositorxx,xxeffectxx,xx3D effectsxx,xx2D effectsxx,xxOpenGLxx,xxXRenderxx,xxvideo settingsxx,xxgraphical effectsxx,xxdesktop effectsxx,xxgraphicsxx,xxlatencyxx,xxvsyncxx,xxtearingxx,xxwindow thumbnailsxx,xxscale methodxx,xxscaling methodxx,xxbackendxx", "X-KDE-Keywords[zh_CN]": "kwin,window,manager,compositing,compositor,effect,3D effects,2D effects,OpenGL,XRender,video settings,graphical effects,desktop effects,graphics,latency,vsync,tearing,window thumbnails,scale method,scaling method,backend,窗口,管理器,显示特效混合器,混合器,构图,混成,效果,特效,视效,动效,3D 特效,2D 特效,视频设置,图形效果,图形特效,图形延迟,延迟,垂直同步,撕裂,窗口缩略图,缩放方式,后端,后端程序", "X-KDE-System-Settings-Parent-Category": "display", - "X-KDE-Weight": 60 + "X-KDE-Weight": 60, + "X-KDE-OnlyShowOnQtPlatforms": [ + "xcb" + ] } diff --git a/src/kcms/compositing/kwincompositing_setting.kcfg b/src/kcms/compositing/kwincompositing_setting.kcfg index c8dac2af22..01ac32431a 100644 --- a/src/kcms/compositing/kwincompositing_setting.kcfg +++ b/src/kcms/compositing/kwincompositing_setting.kcfg @@ -33,16 +33,5 @@ true - - - - - - - - - - LatencyExtremelyHigh - diff --git a/src/kwin.kcfg b/src/kwin.kcfg index 9d1a782a6c..8ee4cf67f5 100644 --- a/src/kwin.kcfg +++ b/src/kwin.kcfg @@ -261,24 +261,6 @@ true - - - - - - - - - KWin::RenderLoop::LatencyExtremelyHigh - - - - - - - - RenderTimeEstimatorMaximum - true diff --git a/src/options.cpp b/src/options.cpp index 0589ac809c..0ba03ca9e3 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -55,8 +55,6 @@ Options::Options(QObject *parent) , m_xwaylandCrashPolicy(Options::defaultXwaylandCrashPolicy()) , m_xwaylandMaxCrashCount(Options::defaultXwaylandMaxCrashCount()) , m_xwaylandEavesdrops(Options::defaultXwaylandEavesdrops()) - , m_latencyPolicy(Options::defaultLatencyPolicy()) - , m_renderTimeEstimator(Options::defaultRenderTimeEstimator()) , m_compositingMode(Options::defaultCompositingMode()) , m_useCompositing(Options::defaultUseCompositing()) , m_hiddenPreviews(Options::defaultHiddenPreviews()) @@ -619,34 +617,6 @@ void Options::setGlPreferBufferSwap(char glPreferBufferSwap) Q_EMIT glPreferBufferSwapChanged(); } -KWin::RenderLoop::LatencyPolicy Options::latencyPolicy() const -{ - return m_latencyPolicy; -} - -void Options::setLatencyPolicy(KWin::RenderLoop::LatencyPolicy policy) -{ - if (m_latencyPolicy == policy) { - return; - } - m_latencyPolicy = policy; - Q_EMIT latencyPolicyChanged(); -} - -RenderTimeEstimator Options::renderTimeEstimator() const -{ - return m_renderTimeEstimator; -} - -void Options::setRenderTimeEstimator(RenderTimeEstimator estimator) -{ - if (m_renderTimeEstimator == estimator) { - return; - } - m_renderTimeEstimator = estimator; - Q_EMIT renderTimeEstimatorChanged(); -} - bool Options::allowTearing() const { return m_allowTearing; @@ -875,8 +845,6 @@ void Options::syncFromKcfgc() setElectricBorderTiling(m_settings->electricBorderTiling()); setElectricBorderCornerRatio(m_settings->electricBorderCornerRatio()); setWindowsBlockCompositing(m_settings->windowsBlockCompositing()); - setLatencyPolicy(m_settings->latencyPolicy()); - setRenderTimeEstimator(m_settings->renderTimeEstimator()); setAllowTearing(m_settings->allowTearing()); } diff --git a/src/options.h b/src/options.h index 9dfe1813a7..63e39b947d 100644 --- a/src/options.h +++ b/src/options.h @@ -48,15 +48,6 @@ enum XwaylandCrashPolicy { Restart, }; -/** - * This enum type specifies the method for estimating the expected render time. - */ -enum RenderTimeEstimator { - RenderTimeEstimatorMinimum, - RenderTimeEstimatorMaximum, - RenderTimeEstimatorAverage, -}; - /** * Placement policies. How workspace decides the way windows get positioned * on the screen. The better the policy, the heavier the resource use. @@ -82,7 +73,6 @@ class KWIN_EXPORT Options : public QObject { Q_OBJECT Q_ENUM(XwaylandCrashPolicy) - Q_ENUM(RenderTimeEstimator) Q_ENUM(PlacementPolicy) Q_PROPERTY(FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy NOTIFY focusPolicyChanged) Q_PROPERTY(XwaylandCrashPolicy xwaylandCrashPolicy READ xwaylandCrashPolicy WRITE setXwaylandCrashPolicy NOTIFY xwaylandCrashPolicyChanged) @@ -207,8 +197,6 @@ class KWIN_EXPORT Options : public QObject Q_PROPERTY(GlSwapStrategy glPreferBufferSwap READ glPreferBufferSwap WRITE setGlPreferBufferSwap NOTIFY glPreferBufferSwapChanged) Q_PROPERTY(KWin::OpenGLPlatformInterface glPlatformInterface READ glPlatformInterface WRITE setGlPlatformInterface NOTIFY glPlatformInterfaceChanged) Q_PROPERTY(bool windowsBlockCompositing READ windowsBlockCompositing WRITE setWindowsBlockCompositing NOTIFY windowsBlockCompositingChanged) - Q_PROPERTY(KWin::RenderLoop::LatencyPolicy latencyPolicy READ latencyPolicy WRITE setLatencyPolicy NOTIFY latencyPolicyChanged) - Q_PROPERTY(RenderTimeEstimator renderTimeEstimator READ renderTimeEstimator WRITE setRenderTimeEstimator NOTIFY renderTimeEstimatorChanged) Q_PROPERTY(bool allowTearing READ allowTearing WRITE setAllowTearing NOTIFY allowTearingChanged) public: explicit Options(QObject *parent = nullptr); @@ -697,8 +685,6 @@ public: } QStringList modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const; - KWin::RenderLoop::LatencyPolicy latencyPolicy() const; - RenderTimeEstimator renderTimeEstimator() const; bool allowTearing() const; // setters @@ -757,8 +743,6 @@ public: void setGlPreferBufferSwap(char glPreferBufferSwap); void setGlPlatformInterface(OpenGLPlatformInterface interface); void setWindowsBlockCompositing(bool set); - void setLatencyPolicy(KWin::RenderLoop::LatencyPolicy policy); - void setRenderTimeEstimator(RenderTimeEstimator estimator); void setAllowTearing(bool allow); // default values @@ -886,14 +870,6 @@ public: { return None; } - static KWin::RenderLoop::LatencyPolicy defaultLatencyPolicy() - { - return KWin::RenderLoop::LatencyExtremelyHigh; - } - static RenderTimeEstimator defaultRenderTimeEstimator() - { - return RenderTimeEstimatorMaximum; - } static ActivationDesktopPolicy defaultActivationDesktopPolicy() { return ActivationDesktopPolicy::SwitchToOtherDesktop; @@ -964,9 +940,7 @@ Q_SIGNALS: void glPlatformInterfaceChanged(); void windowsBlockCompositingChanged(); void animationSpeedChanged(); - void latencyPolicyChanged(); void configChanged(); - void renderTimeEstimatorChanged(); void allowTearingChanged(); private: @@ -998,8 +972,6 @@ private: XwaylandCrashPolicy m_xwaylandCrashPolicy; int m_xwaylandMaxCrashCount; XwaylandEavesdropsMode m_xwaylandEavesdrops; - KWin::RenderLoop::LatencyPolicy m_latencyPolicy; - RenderTimeEstimator m_renderTimeEstimator; CompositingType m_compositingMode; bool m_useCompositing;