summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2023-12-17 07:50:19 -0500
committerRay Strode <rstrode@redhat.com>2023-12-17 07:57:47 -0500
commit5e33469e877e89795b5b28d9f2377ed02d1c38a8 (patch)
treec1bd41e85634f923a74642fbc29f6c2cefc9f502
parentcdc81fd4f700bb6e0392cf42653f8a40f319b6f0 (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.c84
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)