diff --git a/src/core/lv_refr.c b/src/core/lv_refr.c index f6abf960a..c07953790 100644 --- a/src/core/lv_refr.c +++ b/src/core/lv_refr.c @@ -44,6 +44,7 @@ static void refr_obj(lv_layer_t * layer, lv_obj_t * obj); static uint32_t get_max_row(lv_display_t * disp, lv_coord_t area_w, lv_coord_t area_h); static void draw_buf_flush(lv_display_t * disp); static void call_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map); +static void wait_for_flushing(lv_display_t * disp); /********************** * STATIC VARIABLES @@ -384,7 +385,7 @@ void _lv_display_refr_timer(lv_timer_t * tmr) /*With double buffered direct mode synchronize the rendered areas to the other buffer*/ /*We need to wait for ready here to not mess up the active screen*/ - while(disp_refr->flushing); + wait_for_flushing(disp_refr); uint32_t i; for(i = 0; i < disp_refr->inv_p; i++) { @@ -470,7 +471,7 @@ static void refr_sync_areas(void) /*With double buffered direct mode synchronize the rendered areas to the other buffer*/ /*We need to wait for ready here to not mess up the active screen*/ - while(disp_refr->flushing) {} + wait_for_flushing(disp_refr); /*The buffers are already swapped. *So the active buffer is the off screen buffer where LVGL will render*/ @@ -653,7 +654,7 @@ static void refr_area_part(lv_layer_t * layer) /* In single buffered mode wait here until the buffer is freed. * Else we would draw into the buffer while it's still being transferred to the display*/ if(!lv_display_is_double_buffered(disp_refr)) { - while(disp_refr->flushing); + wait_for_flushing(disp_refr); } /*If the screen is transparent initialize it when the flushing is ready*/ if(lv_color_format_has_alpha(disp_refr->color_format)) { @@ -984,7 +985,7 @@ static void draw_buf_flush(lv_display_t * disp) * If we need to wait here it means that the content of one buffer is being sent to display * and other buffer already contains the new rendered image. */ if(lv_display_is_double_buffered(disp)) { - while(disp->flushing); + wait_for_flushing(disp_refr); } disp->flushing = 1; @@ -1036,3 +1037,20 @@ static void call_flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * LV_PROFILER_END; } + + +static void wait_for_flushing(lv_display_t * disp) +{ + LV_PROFILER_BEGIN; + LV_LOG_TRACE("begin"); + + if(disp->flush_wait_cb) { + disp->flush_wait_cb(disp); + } + else { + while(disp->flushing); + } + + LV_LOG_TRACE("end"); + LV_PROFILER_END; +} diff --git a/src/display/lv_display.c b/src/display/lv_display.c index 60a0e6f95..e102bcbcd 100644 --- a/src/display/lv_display.c +++ b/src/display/lv_display.c @@ -398,6 +398,15 @@ void lv_display_set_flush_cb(lv_display_t * disp, lv_display_flush_cb_t flush_cb disp->flush_cb = flush_cb; } + +void lv_display_set_flush_wait_cb(lv_display_t * disp, lv_display_flush_wait_cb_t wait_cb) +{ + if(disp == NULL) disp = lv_display_get_default(); + if(disp == NULL) return; + + disp->flush_wait_cb = wait_cb; +} + void lv_display_set_color_format(lv_display_t * disp, lv_color_format_t color_format) { if(disp == NULL) disp = lv_display_get_default(); diff --git a/src/display/lv_display.h b/src/display/lv_display.h index fd7a8e4ef..eaf9dbdce 100644 --- a/src/display/lv_display.h +++ b/src/display/lv_display.h @@ -85,6 +85,7 @@ typedef enum { typedef void (*lv_display_flush_cb_t)(struct _lv_display_t * disp, const lv_area_t * area, uint8_t * px_map); +typedef void (*lv_display_flush_wait_cb_t)(struct _lv_display_t * disp); /********************** * GLOBAL PROTOTYPES @@ -249,6 +250,18 @@ void lv_display_set_draw_buffers(lv_display_t * disp, void * buf1, void * buf2, * @param flush_cb the flush callback (`px_map` contains the rendered image as raw pixel map and it should be copied to `area` on the display) */ void lv_display_set_flush_cb(lv_display_t * disp, lv_display_flush_cb_t flush_cb); + +/** + * Set a callback to be used while LVGL is waiting flushing to be finished. + * It can do any complex logic to wait, including semaphores, mutexes, polling flags, etc. + * If not set the `disp->flushing` flag is used which can be cleared with `lv_display_flush_ready()` + * @param disp pointer to a display + * @param wait_cb a callback to call while LVGL is waiting for flush ready. + * If NULL `lv_display_flush_ready()` can be used to signal that flushing is ready. + */ +void lv_display_set_flush_wait_cb(lv_display_t * disp, lv_display_flush_wait_cb_t wait_cb); + + /** * Set the color format of the display. * If set to other than `LV_COLOR_FORMAT_NATIVE` the layer's `buffer_convert` function will be used diff --git a/src/display/lv_display_private.h b/src/display/lv_display_private.h index 48821b910..1628b045e 100644 --- a/src/display/lv_display_private.h +++ b/src/display/lv_display_private.h @@ -70,6 +70,12 @@ struct _lv_display_t { * called when finished*/ lv_display_flush_cb_t flush_cb; + /** + * Used to wait while flushing is ready. + * It can do any complex logic to wait, including semaphores, mutexes, polling flags, etc. + * If not set `flushing` flag is used which can be cleared with `lv_display_flush_ready()`*/ + lv_display_flush_wait_cb_t flush_wait_cb; + /*1: flushing is in progress. (It can't be a bit field because when it's cleared from IRQ Read-Modify-Write issue might occur)*/ volatile int flushing;