From 1a36c4e61d39b56fb230e5deba4f85d0502aaa56 Mon Sep 17 00:00:00 2001 From: VIFEX Date: Tue, 17 Jun 2025 04:42:13 +0800 Subject: [PATCH] feat(anim): add vsync mode (#8087) --- src/misc/lv_anim.c | 56 ++++++++++++++++++++++++++++++-- src/misc/lv_anim_private.h | 7 ++++ tests/src/test_cases/test_anim.c | 43 ++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/src/misc/lv_anim.c b/src/misc/lv_anim.c index 7eab8fbfab..c1a1873a9d 100644 --- a/src/misc/lv_anim.c +++ b/src/misc/lv_anim.c @@ -40,6 +40,7 @@ * STATIC PROTOTYPES **********************/ static void anim_timer(lv_timer_t * param); +static void anim_vsync_event(lv_event_t * e); static void anim_mark_list_change(void); static void anim_completed_handler(lv_anim_t * a); static int32_t lv_anim_path_cubic_bezier(const lv_anim_t * a, int32_t x1, @@ -80,6 +81,30 @@ void lv_anim_core_deinit(void) lv_anim_delete_all(); } +void lv_anim_enable_vsync_mode(bool enable) +{ + if(enable) { + /* Remove animation timer, use vsync instead */ + if(state.timer) { + lv_timer_delete(state.timer); + state.timer = NULL; + } + } + else { + if(!state.timer) { + state.timer = lv_timer_create(anim_timer, LV_DEF_REFR_PERIOD, NULL); + LV_ASSERT_NULL(state.timer); + + if(state.anim_vsync_registered) { + lv_display_unregister_vsync_event(NULL, anim_vsync_event, NULL); + state.anim_vsync_registered = false; + } + } + } + + anim_mark_list_change(); +} + void lv_anim_init(lv_anim_t * a) { lv_memzero(a, sizeof(lv_anim_t)); @@ -682,13 +707,38 @@ static void anim_completed_handler(lv_anim_t * a) } } +static void anim_vsync_event(lv_event_t * e) +{ + LV_UNUSED(e); + anim_timer(NULL); +} + static void anim_mark_list_change(void) { state.anim_list_changed = true; - if(lv_ll_get_head(anim_ll_p) == NULL) - lv_timer_pause(state.timer); - else + if(lv_ll_get_head(anim_ll_p) == NULL) { + if(state.timer) { + lv_timer_pause(state.timer); + return; + } + + if(state.anim_vsync_registered) { + lv_display_unregister_vsync_event(NULL, anim_vsync_event, NULL); + state.anim_vsync_registered = false; + } + + return; + } + + if(state.timer) { lv_timer_resume(state.timer); + return; + } + + if(!state.anim_vsync_registered) { + lv_display_register_vsync_event(NULL, anim_vsync_event, NULL); + state.anim_vsync_registered = true; + } } static int32_t lv_anim_path_cubic_bezier(const lv_anim_t * a, int32_t x1, int32_t y1, int32_t x2, int32_t y2) diff --git a/src/misc/lv_anim_private.h b/src/misc/lv_anim_private.h index 5c25850170..83e4cd6bef 100644 --- a/src/misc/lv_anim_private.h +++ b/src/misc/lv_anim_private.h @@ -27,6 +27,7 @@ extern "C" { typedef struct { bool anim_list_changed; bool anim_run_round; + bool anim_vsync_registered; lv_timer_t * timer; lv_ll_t anim_ll; } lv_anim_state_t; @@ -45,6 +46,12 @@ void lv_anim_core_init(void); */ void lv_anim_core_deinit(void); +/* + * Set animation use vsync mode. + * @param enable true: use vsync mode, false: use timer mode. + */ +void lv_anim_enable_vsync_mode(bool enable); + /********************** * MACROS **********************/ diff --git a/tests/src/test_cases/test_anim.c b/tests/src/test_cases/test_anim.c index b3b0d07d6b..7e10cb7f02 100644 --- a/tests/src/test_cases/test_anim.c +++ b/tests/src/test_cases/test_anim.c @@ -15,6 +15,7 @@ void tearDown(void) /* Function run after every test */ lv_obj_clean(lv_screen_active()); lv_anim_delete_all(); + lv_anim_enable_vsync_mode(false); } static void exec_cb(void * var, int32_t v) @@ -193,4 +194,46 @@ void test_scroll_anim_delete(void) TEST_ASSERT_EQUAL(1, var); } +void test_anim_vsync_mode(void) +{ + lv_anim_enable_vsync_mode(true); + + /* anim timer should be NULL when vsync mode is enabled */ + TEST_ASSERT_NULL(lv_anim_get_timer()); + + int32_t var; + + /*Start an animation*/ + lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_var(&a, &var); + lv_anim_set_values(&a, 0, 1000); + lv_anim_set_exec_cb(&a, exec_cb); + lv_anim_set_duration(&a, 1000); + lv_anim_start(&a); + + /*Use vsync events to notify anim updates*/ + lv_tick_inc(10); + lv_display_send_vsync_event(NULL, NULL); + TEST_ASSERT_EQUAL(9, var); + + lv_tick_inc(10); + lv_display_send_vsync_event(NULL, NULL); + TEST_ASSERT_EQUAL(19, var); + + lv_anim_enable_vsync_mode(false); + TEST_ASSERT_NOT_NULL(lv_anim_get_timer()); + + /* Should not update the animation with vsync events when vsync mode is disabled */ + lv_tick_inc(20); + lv_display_send_vsync_event(NULL, NULL); + TEST_ASSERT_EQUAL(19, var); + + /* Test normal timer mode */ + lv_test_wait(20); + TEST_ASSERT_EQUAL(59, var); + + lv_anim_delete(&var, exec_cb); +} + #endif