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)
{
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

@ -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<std::chrono::nanoseconds> m_log;
int m_size = 15;
std::chrono::nanoseconds m_result{0};
std::optional<std::chrono::steady_clock::time_point> m_lastAdd;
};
} // namespace KWin

@ -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;

@ -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.

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

@ -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();
}

@ -171,42 +171,6 @@ you can reset this protection but be aware that this might result in an immediat
</item>
</widget>
</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>
</widget>
<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[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"
]
}

@ -33,16 +33,5 @@
<entry name="WindowsBlockCompositing" type="Bool">
<default>true</default>
</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>
</kcfg>

@ -261,24 +261,6 @@
<entry name="WindowsBlockCompositing" type="Bool">
<default>true</default>
</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">
<default>true</default>
</entry>

@ -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());
}

@ -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;

Loading…
Cancel
Save