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
master
Xaver Hugl 1 year ago
parent d52ba8c3fe
commit 15080192f7

@ -15,36 +15,20 @@ RenderJournal::RenderJournal()
void RenderJournal::add(std::chrono::nanoseconds renderTime) void RenderJournal::add(std::chrono::nanoseconds renderTime)
{ {
if (m_log.count() >= m_size) { if (renderTime > m_result || !m_lastAdd) {
m_log.dequeue(); 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 m_result;
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();
} }
} // namespace KWin } // namespace KWin

@ -25,24 +25,11 @@ public:
void add(std::chrono::nanoseconds renderTime); void add(std::chrono::nanoseconds renderTime);
/** std::chrono::nanoseconds result() const;
* 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;
private: private:
QQueue<std::chrono::nanoseconds> m_log; std::chrono::nanoseconds m_result{0};
int m_size = 15; std::optional<std::chrono::steady_clock::time_point> m_lastAdd;
}; };
} // namespace KWin } // namespace KWin

@ -56,40 +56,11 @@ void RenderLoopPrivate::scheduleRepaint()
} }
// Estimate when it's a good time to perform the next compositing cycle. // 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); const std::chrono::nanoseconds safetyMargin = std::chrono::milliseconds(3);
std::chrono::nanoseconds nextRenderTimestamp = nextPresentationTimestamp - renderJournal.result() - safetyMargin;
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;
// If we can't render the frame before the deadline, start compositing immediately. // If we can't render the frame before the deadline, start compositing immediately.
if (nextRenderTimestamp < currentTime) { 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 std::chrono::nanoseconds RenderLoop::lastPresentationTimestamp() const
{ {
return d->lastPresentationTimestamp; return d->lastPresentationTimestamp;

@ -109,33 +109,6 @@ public:
*/ */
void setVrrPolicy(VrrPolicy vrrPolicy); 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: Q_SIGNALS:
/** /**
* This signal is emitted when the refresh rate of this RenderLoop has changed. * This signal is emitted when the refresh rate of this RenderLoop has changed.

@ -44,7 +44,6 @@ public:
bool pendingReschedule = false; bool pendingReschedule = false;
bool pendingRepaint = false; bool pendingRepaint = false;
RenderLoop::VrrPolicy vrrPolicy = RenderLoop::VrrPolicy::Never; RenderLoop::VrrPolicy vrrPolicy = RenderLoop::VrrPolicy::Never;
std::optional<KWin::RenderLoop::LatencyPolicy> latencyPolicy;
Item *fullscreenItem = nullptr; Item *fullscreenItem = nullptr;
bool allowTearing = false; bool allowTearing = false;

@ -386,15 +386,6 @@ void EffectsHandlerImpl::setActiveFullScreenEffect(Effect *e)
fullscreen_effect = e; fullscreen_effect = e;
Q_EMIT activeFullScreenEffectChanged(); Q_EMIT activeFullScreenEffectChanged();
if (activeChanged) { 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(); Q_EMIT hasActiveFullScreenEffectChanged();
workspace()->screenEdges()->checkBlocking(); workspace()->screenEdges()->checkBlocking();
} }

@ -171,42 +171,6 @@ you can reset this protection but be aware that this might result in an immediat
</item> </item>
</widget> </widget>
</item> </item>
<item row="12" column="0">
<widget class="QLabel" name="latencyLabel">
<property name="text">
<string>Latency:</string>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QComboBox" name="kcfg_LatencyPolicy">
<item>
<property name="text">
<string>Force lowest latency (may cause dropped frames)</string>
</property>
</item>
<item>
<property name="text">
<string>Prefer lower latency</string>
</property>
</item>
<item>
<property name="text">
<string>Balance of latency and smoothness</string>
</property>
</item>
<item>
<property name="text">
<string>Prefer smoother animations</string>
</property>
</item>
<item>
<property name="text">
<string>Force smoothest animations</string>
</property>
</item>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<customwidgets> <customwidgets>

@ -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[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-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-System-Settings-Parent-Category": "display",
"X-KDE-Weight": 60 "X-KDE-Weight": 60,
"X-KDE-OnlyShowOnQtPlatforms": [
"xcb"
]
} }

@ -33,16 +33,5 @@
<entry name="WindowsBlockCompositing" type="Bool"> <entry name="WindowsBlockCompositing" type="Bool">
<default>true</default> <default>true</default>
</entry> </entry>
<entry name="LatencyPolicy" type="Enum">
<choices name="LatencyPolicy">
<choice name="LatencyExtremelyLow" value="ExtremelyLow"/>
<choice name="LatencyLow" value="Low"/>
<choice name="LatencyMedium" value="Medium"/>
<choice name="LatencyHigh" value="High"/>
<choice name="LatencyExtremelyHigh" value="ExtremelyHigh"/>
</choices>
<default>LatencyExtremelyHigh</default>
</entry>
</group> </group>
</kcfg> </kcfg>

@ -261,24 +261,6 @@
<entry name="WindowsBlockCompositing" type="Bool"> <entry name="WindowsBlockCompositing" type="Bool">
<default>true</default> <default>true</default>
</entry> </entry>
<entry name="LatencyPolicy" type="Enum">
<choices name="KWin::RenderLoop::LatencyPolicy">
<choice name="LatencyExtremelyLow" value="ExtremelyLow"/>
<choice name="LatencyLow" value="Low"/>
<choice name="LatencyMedium" value="Medium"/>
<choice name="LatencyHigh" value="High"/>
<choice name="LatencyExtremelyHigh" value="ExtremelyHigh"/>
</choices>
<default>KWin::RenderLoop::LatencyExtremelyHigh</default>
</entry>
<entry name="RenderTimeEstimator" type="Enum">
<choices name="KWin::RenderTimeEstimator">
<choice name="RenderTimeEstimatorMinimum" value="Minimum"/>
<choice name="RenderTimeEstimatorMaximum" value="Maximum"/>
<choice name="RenderTimeEstimatorAverage" value="Average"/>
</choices>
<default>RenderTimeEstimatorMaximum</default>
</entry>
<entry name="AllowTearing" type="Bool"> <entry name="AllowTearing" type="Bool">
<default>true</default> <default>true</default>
</entry> </entry>

@ -55,8 +55,6 @@ Options::Options(QObject *parent)
, m_xwaylandCrashPolicy(Options::defaultXwaylandCrashPolicy()) , m_xwaylandCrashPolicy(Options::defaultXwaylandCrashPolicy())
, m_xwaylandMaxCrashCount(Options::defaultXwaylandMaxCrashCount()) , m_xwaylandMaxCrashCount(Options::defaultXwaylandMaxCrashCount())
, m_xwaylandEavesdrops(Options::defaultXwaylandEavesdrops()) , m_xwaylandEavesdrops(Options::defaultXwaylandEavesdrops())
, m_latencyPolicy(Options::defaultLatencyPolicy())
, m_renderTimeEstimator(Options::defaultRenderTimeEstimator())
, m_compositingMode(Options::defaultCompositingMode()) , m_compositingMode(Options::defaultCompositingMode())
, m_useCompositing(Options::defaultUseCompositing()) , m_useCompositing(Options::defaultUseCompositing())
, m_hiddenPreviews(Options::defaultHiddenPreviews()) , m_hiddenPreviews(Options::defaultHiddenPreviews())
@ -619,34 +617,6 @@ void Options::setGlPreferBufferSwap(char glPreferBufferSwap)
Q_EMIT glPreferBufferSwapChanged(); 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 bool Options::allowTearing() const
{ {
return m_allowTearing; return m_allowTearing;
@ -875,8 +845,6 @@ void Options::syncFromKcfgc()
setElectricBorderTiling(m_settings->electricBorderTiling()); setElectricBorderTiling(m_settings->electricBorderTiling());
setElectricBorderCornerRatio(m_settings->electricBorderCornerRatio()); setElectricBorderCornerRatio(m_settings->electricBorderCornerRatio());
setWindowsBlockCompositing(m_settings->windowsBlockCompositing()); setWindowsBlockCompositing(m_settings->windowsBlockCompositing());
setLatencyPolicy(m_settings->latencyPolicy());
setRenderTimeEstimator(m_settings->renderTimeEstimator());
setAllowTearing(m_settings->allowTearing()); setAllowTearing(m_settings->allowTearing());
} }

@ -48,15 +48,6 @@ enum XwaylandCrashPolicy {
Restart, 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 * Placement policies. How workspace decides the way windows get positioned
* on the screen. The better the policy, the heavier the resource use. * 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_OBJECT
Q_ENUM(XwaylandCrashPolicy) Q_ENUM(XwaylandCrashPolicy)
Q_ENUM(RenderTimeEstimator)
Q_ENUM(PlacementPolicy) Q_ENUM(PlacementPolicy)
Q_PROPERTY(FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy NOTIFY focusPolicyChanged) Q_PROPERTY(FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy NOTIFY focusPolicyChanged)
Q_PROPERTY(XwaylandCrashPolicy xwaylandCrashPolicy READ xwaylandCrashPolicy WRITE setXwaylandCrashPolicy NOTIFY xwaylandCrashPolicyChanged) 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(GlSwapStrategy glPreferBufferSwap READ glPreferBufferSwap WRITE setGlPreferBufferSwap NOTIFY glPreferBufferSwapChanged)
Q_PROPERTY(KWin::OpenGLPlatformInterface glPlatformInterface READ glPlatformInterface WRITE setGlPlatformInterface NOTIFY glPlatformInterfaceChanged) Q_PROPERTY(KWin::OpenGLPlatformInterface glPlatformInterface READ glPlatformInterface WRITE setGlPlatformInterface NOTIFY glPlatformInterfaceChanged)
Q_PROPERTY(bool windowsBlockCompositing READ windowsBlockCompositing WRITE setWindowsBlockCompositing NOTIFY windowsBlockCompositingChanged) 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) Q_PROPERTY(bool allowTearing READ allowTearing WRITE setAllowTearing NOTIFY allowTearingChanged)
public: public:
explicit Options(QObject *parent = nullptr); explicit Options(QObject *parent = nullptr);
@ -697,8 +685,6 @@ public:
} }
QStringList modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const; QStringList modifierOnlyDBusShortcut(Qt::KeyboardModifier mod) const;
KWin::RenderLoop::LatencyPolicy latencyPolicy() const;
RenderTimeEstimator renderTimeEstimator() const;
bool allowTearing() const; bool allowTearing() const;
// setters // setters
@ -757,8 +743,6 @@ public:
void setGlPreferBufferSwap(char glPreferBufferSwap); void setGlPreferBufferSwap(char glPreferBufferSwap);
void setGlPlatformInterface(OpenGLPlatformInterface interface); void setGlPlatformInterface(OpenGLPlatformInterface interface);
void setWindowsBlockCompositing(bool set); void setWindowsBlockCompositing(bool set);
void setLatencyPolicy(KWin::RenderLoop::LatencyPolicy policy);
void setRenderTimeEstimator(RenderTimeEstimator estimator);
void setAllowTearing(bool allow); void setAllowTearing(bool allow);
// default values // default values
@ -886,14 +870,6 @@ public:
{ {
return None; return None;
} }
static KWin::RenderLoop::LatencyPolicy defaultLatencyPolicy()
{
return KWin::RenderLoop::LatencyExtremelyHigh;
}
static RenderTimeEstimator defaultRenderTimeEstimator()
{
return RenderTimeEstimatorMaximum;
}
static ActivationDesktopPolicy defaultActivationDesktopPolicy() static ActivationDesktopPolicy defaultActivationDesktopPolicy()
{ {
return ActivationDesktopPolicy::SwitchToOtherDesktop; return ActivationDesktopPolicy::SwitchToOtherDesktop;
@ -964,9 +940,7 @@ Q_SIGNALS:
void glPlatformInterfaceChanged(); void glPlatformInterfaceChanged();
void windowsBlockCompositingChanged(); void windowsBlockCompositingChanged();
void animationSpeedChanged(); void animationSpeedChanged();
void latencyPolicyChanged();
void configChanged(); void configChanged();
void renderTimeEstimatorChanged();
void allowTearingChanged(); void allowTearingChanged();
private: private:
@ -998,8 +972,6 @@ private:
XwaylandCrashPolicy m_xwaylandCrashPolicy; XwaylandCrashPolicy m_xwaylandCrashPolicy;
int m_xwaylandMaxCrashCount; int m_xwaylandMaxCrashCount;
XwaylandEavesdropsMode m_xwaylandEavesdrops; XwaylandEavesdropsMode m_xwaylandEavesdrops;
KWin::RenderLoop::LatencyPolicy m_latencyPolicy;
RenderTimeEstimator m_renderTimeEstimator;
CompositingType m_compositingMode; CompositingType m_compositingMode;
bool m_useCompositing; bool m_useCompositing;

Loading…
Cancel
Save