animation: improve animations on multi refresh rate monitors (#12418)

This commit is contained in:
bea4dev 2025-11-24 00:48:15 +09:00 committed by GitHub
parent 56904edbd2
commit 2b0fd417d3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 34 additions and 22 deletions

View file

@ -18,16 +18,7 @@
static int wlTick(SP<CEventLoopTimer> self, void* data) {
if (g_pAnimationManager)
g_pAnimationManager->onTicked();
if (g_pCompositor->m_sessionActive && g_pAnimationManager && g_pHookSystem && !g_pCompositor->m_unsafeState &&
std::ranges::any_of(g_pCompositor->m_monitors, [](const auto& mon) { return mon->m_enabled && mon->m_output; })) {
g_pAnimationManager->tick();
EMIT_HOOK_EVENT("tick", nullptr);
}
if (g_pAnimationManager && g_pAnimationManager->shouldTickForNext())
g_pAnimationManager->scheduleTick();
g_pAnimationManager->frameTick();
return 0;
}
@ -249,26 +240,40 @@ void CHyprAnimationManager::tick() {
tickDone();
}
void CHyprAnimationManager::frameTick() {
onTicked();
if (!shouldTickForNext())
return;
if (!g_pCompositor->m_sessionActive || !g_pHookSystem || g_pCompositor->m_unsafeState ||
!std::ranges::any_of(g_pCompositor->m_monitors, [](const auto& mon) { return mon->m_enabled && mon->m_output; }))
return;
if (!m_lastTickValid || m_lastTickTimer.getMillis() >= 1.0f) {
m_lastTickTimer.reset();
m_lastTickValid = true;
tick();
EMIT_HOOK_EVENT("tick", nullptr);
}
if (shouldTickForNext())
scheduleTick();
}
void CHyprAnimationManager::scheduleTick() {
if (m_tickScheduled)
return;
m_tickScheduled = true;
const auto PMOSTHZ = g_pHyprRenderer->m_mostHzMonitor;
if (!PMOSTHZ) {
m_animationTimer->updateTimeout(std::chrono::milliseconds(16));
if (!m_animationTimer || !g_pEventLoopManager) {
m_tickScheduled = false;
return;
}
float refreshDelayMs = std::floor(1000.f / PMOSTHZ->m_refreshRate);
const float SINCEPRES = std::chrono::duration_cast<std::chrono::microseconds>(Time::steadyNow() - PMOSTHZ->m_lastPresentationTimer.chrono()).count() / 1000.F;
const auto TOPRES = std::clamp(refreshDelayMs - SINCEPRES, 1.1f, 1000.f); // we can't send 0, that will disarm it
m_animationTimer->updateTimeout(std::chrono::milliseconds(sc<int>(std::floor(TOPRES))));
m_animationTimer->updateTimeout(std::chrono::milliseconds(1));
}
void CHyprAnimationManager::onTicked() {

View file

@ -6,6 +6,7 @@
#include "../../defines.hpp"
#include "../../helpers/AnimatedVariable.hpp"
#include "../../desktop/DesktopTypes.hpp"
#include "../../helpers/time/Timer.hpp"
#include "../eventLoop/EventLoopTimer.hpp"
class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager {
@ -13,6 +14,7 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager {
CHyprAnimationManager();
void tick();
void frameTick();
virtual void scheduleTick();
virtual void onTicked();
@ -52,7 +54,9 @@ class CHyprAnimationManager : public Hyprutils::Animation::CAnimationManager {
float m_lastTickTimeMs;
private:
bool m_tickScheduled = false;
bool m_tickScheduled = false;
bool m_lastTickValid = false;
CTimer m_lastTickTimer;
};
inline UP<CHyprAnimationManager> g_pAnimationManager;

View file

@ -1247,6 +1247,9 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
if (!g_pCompositor->m_sessionActive)
return;
if (g_pAnimationManager)
g_pAnimationManager->frameTick();
if (pMonitor->m_id == m_mostHzMonitor->m_id ||
*PVFR == 1) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that