From 604b3082f31f1a3cf20f8ef0586b3977f2d03233 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 6 Aug 2026 18:17:34 +1000 Subject: [PATCH] [client] overlay: coalesce pointer redraws during splash fade Pointer updates bypassed the paced overlay render and woke the renderer for every cursor packet. On the default single-buffer EGL surface, each full fade redraw could expose the desktop before the splash was blended again. Coalesce pointer redraws into the existing fade cadence while keeping the latest cursor state. Immediate cursor redraw resumes when the fade ends. --- client/src/main.c | 7 +++++-- client/src/overlay/splash.c | 13 +++++++++++++ client/src/overlays.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/src/main.c b/client/src/main.c index 432a79fa..356e05f0 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -916,7 +916,9 @@ int main_cursorThread(void * unused) (g_cursor.draw || !g_params.useSpiceInput), g_cursor.guest.x, g_cursor.guest.y, g_cursor.guest.hx, g_cursor.guest.hy); - if (!g_state.stopVideo) + /* The active fade already schedules a render. Coalesce pointer + * changes into it instead of exposing rapid single-buffer redraws. */ + if (!g_state.stopVideo && !overlaySplash_isFading()) lgSignalEvent(g_state.frameEvent); } continue; @@ -990,7 +992,8 @@ int main_cursorThread(void * unused) if ((g_params.mouseRedraw || (pointer.flags & LG_TRANSPORT_POINTER_COLOR_TRANSFORM)) && - g_cursor.guest.visible && !g_state.stopVideo) + g_cursor.guest.visible && !g_state.stopVideo && + !overlaySplash_isFading()) lgSignalEvent(g_state.frameEvent); g_state.transportOps->releasePointer(g_state.transport, &pointer); diff --git a/client/src/overlay/splash.c b/client/src/overlay/splash.c index f6f2d003..446fb88f 100644 --- a/client/src/overlay/splash.c +++ b/client/src/overlay/splash.c @@ -49,6 +49,7 @@ enum SplashState }; static _Atomic(bool) l_requestedShow; +static _Atomic(bool) l_fading; static bool l_appliedShow; static enum SplashState l_state; static uint64_t l_fadeStart; @@ -99,6 +100,7 @@ static void drawRadialGradient(ImDrawList * list, int x, int y, int w, int h, static bool splash_init(void ** udata, const void * params) { atomic_store_explicit(&l_requestedShow, true, memory_order_relaxed); + atomic_store_explicit(&l_fading, false, memory_order_relaxed); l_appliedShow = true; l_state = SPLASH_VISIBLE; l_fadeStart = 0; @@ -176,6 +178,7 @@ static int splash_render(void * udata, bool interactive, struct Rect * windowRec if (elapsed >= FADE_TIME_NS) { l_state = SPLASH_HIDDEN; + atomic_store_explicit(&l_fading, false, memory_order_release); return 0; } alpha -= (float)elapsed / (float)FADE_TIME_NS; @@ -267,13 +270,18 @@ static bool splash_needsFullRender(void * udata) { l_state = SPLASH_VISIBLE; l_fadeStart = 0; + atomic_store_explicit(&l_fading, false, memory_order_release); } else if (g_params.quickSplash) + { l_state = SPLASH_HIDDEN; + atomic_store_explicit(&l_fading, false, memory_order_release); + } else { l_state = SPLASH_FADING; l_fadeStart = nanotime(); + atomic_store_explicit(&l_fading, true, memory_order_release); } } @@ -298,3 +306,8 @@ void overlaySplash_show(bool show) app_invalidateWindow(true); } + +bool overlaySplash_isFading(void) +{ + return atomic_load_explicit(&l_fading, memory_order_acquire); +} diff --git a/client/src/overlays.h b/client/src/overlays.h index de4629a6..df118415 100644 --- a/client/src/overlays.h +++ b/client/src/overlays.h @@ -122,6 +122,7 @@ typedef enum LG_UserStatus LGUserStatus; void overlaySplash_show(bool show); +bool overlaySplash_isFading(void); void overlayStatus_set(LGUserStatus, bool value); #endif