backends/drm: delay cursor updates with adaptive sync
While the primary plane delivers a high enough refresh rate for the cursor to be at least usable, delay cursor updates to be in sync with the primary plane. This avoids stutter of the content being shown on the primary plane. Because amdgpu doesn't handle this correctly at the moment, this feature is guarded behind the KWIN_DRM_DELAY_VRR_CURSOR_UPDATES environment variable. See https://gitlab.freedesktop.org/drm/amd/-/issues/2186 for more details on that.
This commit is contained in:
parent
080d28b3f9
commit
039fd39e34
1 changed files with 28 additions and 0 deletions
|
@ -22,6 +22,10 @@ namespace KWin
|
|||
*/
|
||||
static constexpr auto s_pageflipTimeout = 5s;
|
||||
|
||||
// amdgpu doesn't handle this correctly, so it's off by default
|
||||
// https://gitlab.freedesktop.org/drm/amd/-/issues/2186
|
||||
static const bool s_delayVrrCursorUpdates = qEnvironmentVariableIntValue("KWIN_DRM_DELAY_VRR_CURSOR_UPDATES") == 1;
|
||||
|
||||
DrmCommitThread::DrmCommitThread(DrmGpu *gpu, const QString &name)
|
||||
{
|
||||
if (!gpu->atomicModeSetting()) {
|
||||
|
@ -73,6 +77,30 @@ DrmCommitThread::DrmCommitThread(DrmGpu *gpu, const QString &name)
|
|||
}
|
||||
continue;
|
||||
}
|
||||
if (m_commits.front()->isCursorOnly() && m_vrr && s_delayVrrCursorUpdates) {
|
||||
// wait for a primary plane commit to be in, while still enforcing
|
||||
// a minimum cursor refresh rate of 30Hz
|
||||
const auto cursorTarget = m_lastPageflip + std::chrono::duration_cast<std::chrono::nanoseconds>(1s) / 30;
|
||||
const bool cursorOnly = std::all_of(m_commits.begin(), m_commits.end(), [](const auto &commit) {
|
||||
return commit->isCursorOnly();
|
||||
});
|
||||
if (cursorOnly) {
|
||||
// no primary plane commit, just wait until a new one gets added or the cursorTarget time is reached
|
||||
if (m_commitPending.wait_until(lock, cursorTarget) == std::cv_status::no_timeout) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
bool timeout = true;
|
||||
while (std::chrono::steady_clock::now() < cursorTarget && timeout && m_commits.front()->isCursorOnly()) {
|
||||
timeout = m_commitPending.wait_for(lock, 50us) == std::cv_status::timeout;
|
||||
optimizeCommits();
|
||||
}
|
||||
if (!timeout) {
|
||||
// some new commit was added, process that
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
submit();
|
||||
}
|
||||
}));
|
||||
|
|
Loading…
Reference in a new issue