diff options
author | Ray Strode <rstrode@redhat.com> | 2023-12-17 07:50:19 -0500 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2023-12-17 07:57:47 -0500 |
commit | 5e33469e877e89795b5b28d9f2377ed02d1c38a8 (patch) | |
tree | c1bd41e85634f923a74642fbc29f6c2cefc9f502 | |
parent | cdc81fd4f700bb6e0392cf42653f8a40f319b6f0 (diff) |
ply-boot-splash: Flush display updates at fixed framerate
At the moment the splash plugins have a lot of leeway when
updates can go to the screen. They can pause and unpause
updates by themselves, and draw at any point.
This rope has a little too much slack, it's actually kind
of complicated for the splash plugins to manage drawing
when they have more than one moving part.
For instance, a spinner animation may be drawing autonomously
from the splash plugin itself. To avoid flicker, everything
needs to be synchronized.
This commit adds that synchronization a layer higher than
the plugins themselves, in ply-boot-splash. It accumulates
drawing updates continuously without doing any drawing, until
a given deadline, then flushes the updates out all at once.
-rw-r--r-- | src/libply-splash-core/ply-boot-splash.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/libply-splash-core/ply-boot-splash.c b/src/libply-splash-core/ply-boot-splash.c index 9084b1f4..12fb6c10 100644 --- a/src/libply-splash-core/ply-boot-splash.c +++ b/src/libply-splash-core/ply-boot-splash.c @@ -47,6 +47,10 @@ #define UPDATES_PER_SECOND 30 #endif +#ifndef FRAMES_PER_SECOND +#define FRAMES_PER_SECOND 60 +#endif + struct _ply_boot_splash { ply_event_loop_t *loop; @@ -70,6 +74,7 @@ struct _ply_boot_splash void *idle_handler_user_data; uint32_t is_loaded : 1; + uint32_t is_shown : 1; uint32_t should_force_text_mode : 1; }; @@ -136,6 +141,11 @@ ply_boot_splash_add_pixel_display (ply_boot_splash_t *splash, ply_trace ("adding %lux%lu pixel display", width, height); + if (splash->is_shown) { + ply_trace ("Splash already shown, so pausing display until next frame update"); + ply_pixel_display_pause_updates (display); + } + splash->plugin_interface->add_pixel_display (splash->plugin, display); ply_list_append_data (splash->pixel_displays, display); } @@ -456,6 +466,52 @@ ply_boot_splash_attach_progress (ply_boot_splash_t *splash, splash->progress = progress; } +static void +ply_boot_splash_pause_pixel_displays (ply_boot_splash_t *splash) +{ + ply_list_node_t *node; + + ply_list_foreach (splash->pixel_displays, node) { + ply_pixel_display_t *display = ply_list_node_get_data (node); + ply_pixel_display_pause_updates (display); + } +} + +static void +ply_boot_splash_unpause_pixel_displays (ply_boot_splash_t *splash) +{ + ply_list_node_t *node; + + ply_list_foreach (splash->pixel_displays, node) { + ply_pixel_display_t *display = ply_list_node_get_data (node); + ply_pixel_display_unpause_updates (display); + } +} + +static void +ply_boot_splash_flush_displays (ply_boot_splash_t *splash) +{ + if (!splash->is_shown) + return; + + ply_boot_splash_unpause_pixel_displays (splash); + ply_boot_splash_pause_pixel_displays (splash); +} + +static void +on_new_frame (ply_boot_splash_t *splash) +{ + if (!splash->is_shown) + return; + + ply_boot_splash_flush_displays (splash); + + ply_event_loop_watch_for_timeout (splash->loop, + 1.0 / FRAMES_PER_SECOND, + (ply_event_loop_timeout_handler_t) + on_new_frame, + splash); +} bool ply_boot_splash_show (ply_boot_splash_t *splash, @@ -493,6 +549,25 @@ ply_boot_splash_show (ply_boot_splash_t *splash, return false; } + if (!splash->is_shown) { + size_t number_of_displays; + ply_trace ("(this is an initial showing)"); + number_of_displays = ply_list_get_length (splash->pixel_displays); + + if (number_of_displays > 0) { + ply_trace ("Pausing %ld already added displays", + number_of_displays); + ply_boot_splash_pause_pixel_displays (splash); + } + + ply_event_loop_watch_for_timeout (splash->loop, + 1.0 / FRAMES_PER_SECOND, + (ply_event_loop_timeout_handler_t) + on_new_frame, + splash); + splash->is_shown = true; + } + if (splash->plugin_interface->on_boot_progress != NULL) ply_boot_splash_update_progress (splash); @@ -575,6 +650,15 @@ ply_boot_splash_hide (ply_boot_splash_t *splash) splash->mode = PLY_BOOT_SPLASH_MODE_INVALID; if (splash->loop != NULL) { + if (splash->is_shown) { + ply_boot_splash_unpause_pixel_displays (splash); + + ply_event_loop_stop_watching_for_timeout (splash->loop, + (ply_event_loop_timeout_handler_t) + on_new_frame, splash); + splash->is_shown = false; + } + if (splash->plugin_interface->on_boot_progress != NULL) { ply_event_loop_stop_watching_for_timeout (splash->loop, (ply_event_loop_timeout_handler_t) |