Skip to content

core: start fade-in animation in onLockLocked to prevent skipped frames - #1065

Open
fhmzzddnn wants to merge 1 commit into
hyprwm:mainfrom
fhmzzddnn:fix-fade-in-sync
Open

fhmzzddnn wants to merge 1 commit into
hyprwm:mainfrom
fhmzzddnn:fix-fade-in-sync

Conversation

@fhmzzddnn

Copy link
Copy Markdown

PR: core: synchronize fade-in animation start with onLockLocked event

Summary

Fixes an issue where the first ~400–500ms of the fade-in animation is skipped due to the asynchronous Wayland ext-session-lock-v1 protocol handshake.


Problem & Timing Evidence

Previously, g_pRenderer->startFadeIn() was called in CHyprlock::run() right before entering the main event loop. At this point, the session lock handshake with the compositor (fractional scale negotiation, surface creation, dimensions configuration) has not finished yet.

Because the animation clock (opacity) started ticking immediately, the first ~470ms of the animation was calculated and rendered into an unmapped surface. When the compositor finally granted the lock and displayed the first frame on the monitor, the animation was already halfway complete, resulting in a noticeable jump/skip.

High-Precision Journal Logs (journalctl -o short-precise)

Before Patch (Unsynchronized):

23:29:33.464722 hyprlock[61319]: DEBUG ]: Starting fade in        <-- [T = 0.0ms] Animation clock begins
23:29:33.505677 hyprlock[61319]: DEBUG ]: PAMPROMPT: Password:
23:29:33.904627 hyprlock[61319]: DEBUG ]: Got fractional scale: 100.0%
23:29:33.904627 hyprlock[61319]: DEBUG ]: configure with serial 41506
23:29:33.942011 hyprlock[61319]: DEBUG ]: onLockLocked called     <-- [T = +477.3ms] Surface becomes visible
  • Dead Time: 477.289 ms of animation played into an unmapped surface before the first frame was displayed.

After Patch (Synchronized):

06:27:43.055947 hyprlock[72523]: DEBUG ]: Got dma frame with size [Vector2D: x: 1920, y: 1080]
06:27:43.439950 hyprlock[72523]: DEBUG ]: configure with serial 50014
06:27:43.477427 hyprlock[72523]: DEBUG ]: onLockLocked called     <-- Surface becomes visible
06:27:43.477427 hyprlock[72523]: DEBUG ]: Starting fade in        <-- [T = 0.0ms] Animation starts simultaneously
  • Dead Time: 0.000 ms — 100% of the fade-in animation renders on the visible screen starting from $T=0$ ($0%$ opacity).

Changes

Moved g_pRenderer->startFadeIn() from CHyprlock::run() into the CHyprlock::onLockLocked() callback.

diff --git a/src/core/hyprlock.cpp b/src/core/hyprlock.cpp
index 105ec37..4753dc9 100644
--- a/src/core/hyprlock.cpp
+++ b/src/core/hyprlock.cpp
@@ -455,7 +455,6 @@ void CHyprlock::run() {
     });
 
     m_sLoopState.event = true; // let it process once
-    g_pRenderer->startFadeIn();
 
     while (!m_bTerminate) {
         std::unique_lock lk(m_sLoopState.eventRequestMutex);
@@ -823,6 +822,7 @@ void CHyprlock::onLockLocked() {
     Log::logger->log(Log::INFO, "onLockLocked called");
 
     m_sLockState.locked = true;
+    g_pRenderer->startFadeIn();
 }
 
 void CHyprlock::onLockFinished() {

Safety & Concurrency

  • onLockLocked() is dispatched synchronously from wl_display_dispatch_pending() on the main thread, exactly like CHyprlock::run().
  • opacity is initialized to 0.f, so the surface remains transparent while negotiating the lock with the compositor.
  • If the lock fails or is aborted, onLockFinished() terminates cleanly without triggering the fade.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant