feat(disp): add double buffered direct-mode efficient sync algorithm (#4443)

Signed-off-by: YanXiaowei <yanxiaowei@xiaomi.com>
Co-authored-by: bjsylvia <bjsylvia@163.com>
Co-authored-by: YanXiaowei <yanxiaowei@xiaomi.com>
Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
Co-authored-by: Fabian Blatz <fabianblatz@gmail.com>
Co-authored-by: Mike Fikes <mike@fikesfarm.com>
Co-authored-by: Zoltan Janosy <janosy.zoltan@gmail.com>
Co-authored-by: Zoltan Janosy <zjanosy@fishman.com>
This commit is contained in:
Brandon Holland
2023-10-10 12:44:32 -07:00
committed by GitHub
parent 80149e7f98
commit 8c63327f66
14 changed files with 198 additions and 41 deletions

View File

@@ -6,8 +6,8 @@ LV_IMAGE_DECLARE(animimg003)
static const lv_image_dsc_t * anim_imgs[3] = {
&animimg001,
&animimg002,
&animimg003,
& animimg002,
& animimg003,
};
void lv_example_animimg_1(void)

View File

@@ -35,6 +35,7 @@
**********************/
static void lv_refr_join_area(void);
static void refr_invalid_areas(void);
static void refr_sync_areas(void);
static void refr_area(const lv_area_t * area_p);
static void refr_area_part(lv_layer_t * layer);
static lv_obj_t * lv_refr_get_top_obj(const lv_area_t * area_p, lv_obj_t * obj);
@@ -367,7 +368,7 @@ void _lv_display_refr_timer(lv_timer_t * tmr)
}
lv_refr_join_area();
refr_sync_areas();
refr_invalid_areas();
if(disp_refr->inv_p == 0) goto refr_finish;
@@ -383,23 +384,13 @@ void _lv_display_refr_timer(lv_timer_t * tmr)
/*We need to wait for ready here to not mess up the active screen*/
while(disp_refr->flushing);
/*The buffers are already swapped.
*So the active buffer is the off screen buffer where LVGL will render*/
void * buf_off_screen = disp_refr->buf_act;
void * buf_on_screen = disp_refr->buf_act == disp_refr->buf_1
? disp_refr->buf_2
: disp_refr->buf_1;
lv_coord_t stride = lv_draw_buf_width_to_stride(lv_display_get_horizontal_resolution(disp_refr),
lv_display_get_color_format(disp_refr));
uint32_t i;
for(i = 0; i < disp_refr->inv_p; i++) {
if(disp_refr->inv_area_joined[i]) continue;
lv_draw_buf_copy(
buf_off_screen, stride, &disp_refr->inv_areas[i],
buf_on_screen, stride, &disp_refr->inv_areas[i],
disp_refr->color_format
);
if(disp_refr->inv_area_joined[i])
continue;
lv_area_t * sync_area = _lv_ll_ins_tail(&disp_refr->sync_areas);
*sync_area = disp_refr->inv_areas[i];
}
refr_clean_up:
@@ -461,6 +452,85 @@ static void lv_refr_join_area(void)
}
}
/**
* Refresh the sync areas
*/
static void refr_sync_areas(void)
{
/*Do not sync if not direct or double buffered*/
if(disp_refr->render_mode != LV_DISPLAY_RENDER_MODE_DIRECT) return;
/*Do not sync if not double buffered*/
if(!lv_display_is_double_buffered(disp_refr)) return;
/*Do not sync if no sync areas*/
if(_lv_ll_is_empty(&disp_refr->sync_areas)) return;
/*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) {}
/*The buffers are already swapped.
*So the active buffer is the off screen buffer where LVGL will render*/
void * buf_off_screen = disp_refr->buf_act;
void * buf_on_screen = disp_refr->buf_act == disp_refr->buf_1
? disp_refr->buf_2
: disp_refr->buf_1;
/*Get stride for buffer copy*/
lv_coord_t stride = lv_draw_buf_width_to_stride(
lv_display_get_horizontal_resolution(disp_refr),
lv_display_get_color_format(disp_refr));
/*Iterate through invalidated areas to see if sync area should be copied*/
uint16_t i;
int8_t j;
lv_area_t res[4] = {0};
int8_t res_c;
lv_area_t * sync_area, * new_area, * next_area;
for(i = 0; i < disp_refr->inv_p; i++) {
/*Skip joined areas*/
if(disp_refr->inv_area_joined[i]) continue;
/*Iterate over sync areas*/
sync_area = _lv_ll_get_head(&disp_refr->sync_areas);
while(sync_area != NULL) {
/*Get next sync area*/
next_area = _lv_ll_get_next(&disp_refr->sync_areas, sync_area);
/*Remove intersect of redraw area from sync area and get remaining areas*/
res_c = _lv_area_diff(res, sync_area, &disp_refr->inv_areas[i]);
/*New sub areas created after removing intersect*/
if(res_c != -1) {
/*Replace old sync area with new areas*/
for(j = 0; j < res_c; j++) {
new_area = _lv_ll_ins_prev(&disp_refr->sync_areas, sync_area);
*new_area = res[j];
}
_lv_ll_remove(&disp_refr->sync_areas, sync_area);
lv_free(sync_area);
}
/*Move on to next sync area*/
sync_area = next_area;
}
}
/*Copy sync areas (if any remaining)*/
for(sync_area = _lv_ll_get_head(&disp_refr->sync_areas); sync_area != NULL;
sync_area = _lv_ll_get_next(&disp_refr->sync_areas, sync_area)) {
lv_draw_buf_copy(
buf_off_screen, stride, sync_area,
buf_on_screen, stride, sync_area,
lv_display_get_color_format(disp_refr)
);
}
/*Clear sync areas*/
_lv_ll_clear(&disp_refr->sync_areas);
}
/**
* Refresh the joined areas
*/

View File

@@ -83,6 +83,8 @@ lv_display_t * lv_display_create(lv_coord_t hor_res, lv_coord_t ver_res)
disp->inv_en_cnt = 1;
_lv_ll_init(&disp->sync_areas, sizeof(lv_area_t));
lv_display_t * disp_def_tmp = disp_def;
disp_def = disp; /*Temporarily change the default screen to create the default screens on the
new display*/
@@ -168,6 +170,7 @@ void lv_display_remove(lv_display_t * disp)
lv_obj_del(disp->screens[0]);
}
_lv_ll_clear(&disp->sync_areas);
_lv_ll_remove(disp_ll_p, disp);
if(disp->refr_timer) lv_timer_del(disp->refr_timer);
lv_free(disp);

View File

@@ -92,6 +92,9 @@ struct _lv_display_t {
uint32_t inv_p;
int32_t inv_en_cnt;
/** Double buffer sync areas (redrawn during last refresh) */
lv_ll_t sync_areas;
/*---------------------
* Layer
*--------------------*/

View File

@@ -303,7 +303,7 @@ LV_ATTRIBUTE_FAST_MEM static void draw_line_skew(lv_draw_unit_t * draw_unit, con
lv_draw_sw_mask_line_param_t mask_top_param;
lv_draw_sw_mask_line_param_t mask_bottom_param;
void * masks[5] = {&mask_left_param, &mask_right_param, NULL, NULL, NULL};
void * masks[5] = {&mask_left_param, & mask_right_param, NULL, NULL, NULL};
if(flat) {

View File

@@ -497,7 +497,7 @@ static void
render_frame_rect(gd_GIF * gif, uint8_t * buffer)
{
int i, j, k;
uint8_t index, *color;
uint8_t index, * color;
i = gif->fy * gif->width + gif->fx;
for(j = 0; j < gif->fh; j++) {
for(k = 0; k < gif->fw; k++) {

View File

@@ -42,7 +42,7 @@ typedef struct _gd_GIF {
void (*application)(struct _gd_GIF * gif, char id[8], char auth[3]);
uint16_t fx, fy, fw, fh;
uint8_t bgindex;
uint8_t * canvas, *frame;
uint8_t * canvas, * frame;
} gd_GIF;
gd_GIF * gd_open_gif_file(const char * fname);

View File

@@ -1703,7 +1703,7 @@ static unsigned encodeLZ77(uivector * out, Hash * hash,
unsigned hashval;
unsigned current_offset, current_length;
unsigned prev_offset;
const unsigned char * lastptr, *foreptr, *backptr;
const unsigned char * lastptr, * foreptr, * backptr;
unsigned hashpos;
if(windowsize == 0 || windowsize > 32768) return 60; /*error: windowsize smaller/larger than allowed*/
@@ -2717,7 +2717,7 @@ unsigned lodepng_chunk_append(unsigned char ** out, size_t * outsize, const unsi
{
unsigned i;
size_t total_chunk_length, new_length;
unsigned char * chunk_start, *new_buffer;
unsigned char * chunk_start, * new_buffer;
if(lodepng_addofl(lodepng_chunk_length(chunk), 12, &total_chunk_length)) return 77;
if(lodepng_addofl(*outsize, total_chunk_length, &new_length)) return 77;
@@ -4761,7 +4761,7 @@ static unsigned readChunk_bKGD(LodePNGInfo * info, const unsigned char * data, s
static unsigned readChunk_tEXt(LodePNGInfo * info, const unsigned char * data, size_t chunkLength)
{
unsigned error = 0;
char * key = 0, *str = 0;
char * key = 0, * str = 0;
while(!error) { /*not really a while loop, only used to break on error*/
unsigned length, string2_begin;
@@ -4857,7 +4857,7 @@ static unsigned readChunk_iTXt(LodePNGInfo * info, const LodePNGDecoderSettings
LodePNGDecompressSettings zlibsettings = decoder->zlibsettings;
unsigned length, begin, compressed;
char * key = 0, *langtag = 0, *transkey = 0;
char * key = 0, * langtag = 0, * transkey = 0;
while(!error) { /*not really a while loop, only used to break on error*/
/*Quick check if the chunk length isn't too small. Even without check
@@ -5484,7 +5484,7 @@ static unsigned writeSignature(ucvector * out)
static unsigned addChunk_IHDR(ucvector * out, unsigned w, unsigned h,
LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method)
{
unsigned char * chunk, *data;
unsigned char * chunk, * data;
CERROR_TRY_RETURN(lodepng_chunk_init(&chunk, out, 13, "IHDR"));
data = chunk + 8;

View File

@@ -350,7 +350,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context * c, int wid
{
int best_waste = (1 << 30), best_x, best_y = (1 << 30);
stbrp__findresult fr;
stbrp_node ** prev, *node, *tail, **best = NULL;
stbrp_node ** prev, * node, * tail, ** best = NULL;
// align to multiple of c->align
width = (width + c->align - 1);
@@ -453,7 +453,7 @@ static stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context * context,
{
// find best position according to heuristic
stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);
stbrp_node * node, *cur;
stbrp_node * node, * cur;
// bail if:
// 1. it failed

View File

@@ -199,8 +199,8 @@ static JRESULT create_huffman_tbl( /* 0:OK, !0:Failed */
{
unsigned int i, j, b, cls, num;
size_t np;
uint8_t d, *pb, *pd;
uint16_t hc, *ph;
uint8_t d, * pb, * pd;
uint16_t hc, * ph;
while(ndata) { /* Process all tables in the segment */
@@ -343,7 +343,7 @@ static int huffext( /* >=0: decoded data, <0: error code */
} while(bl);
#else
const uint8_t * hb, *hd;
const uint8_t * hb, * hd;
const uint16_t * hc;
unsigned int nc, bl, wbit = jd->dbit % 32;
uint32_t w = jd->wreg & ((1UL << wbit) - 1);
@@ -833,7 +833,7 @@ JRESULT jd_mcu_output(
const int CVACC = (sizeof(int) > 2) ? 1024 : 128; /* Adaptive accuracy for both 16-/32-bit systems */
unsigned int ix, iy, mx, my, rx, ry;
int yy, cb, cr;
jd_yuv_t * py, *pc;
jd_yuv_t * py, * pc;
uint8_t * pix;
JRECT rect;
@@ -892,7 +892,7 @@ JRESULT jd_mcu_output(
/* Squeeze up pixel table if a part of MCU is to be truncated */
mx >>= jd->scale;
if(rx < mx) { /* Is the MCU spans rigit edge? */
uint8_t * s, *d;
uint8_t * s, * d;
unsigned int xi, yi;
s = d = (uint8_t *)jd->workbuf;
@@ -911,7 +911,7 @@ JRESULT jd_mcu_output(
/* Convert RGB888 to RGB565 if needed */
if(JD_FORMAT == 1) {
uint8_t * s = (uint8_t *)jd->workbuf;
uint16_t w, *d = (uint16_t *)s;
uint16_t w, * d = (uint16_t *)s;
unsigned int n = rx * ry;
do {

View File

@@ -145,6 +145,78 @@ bool _lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area
return union_ok;
}
/**
* Get resulting sub areas after removing the common parts of two areas from the first area
* @param res_p pointer to an array of areas with a count of 4, the resulting areas will be stored here
* @param a1_p pointer to the first area
* @param a2_p pointer to the second area
* @return number of results or -1 if no intersect
*/
int8_t _lv_area_diff(lv_area_t res_p[], const lv_area_t * a1_p, const lv_area_t * a2_p)
{
/*Areas have no common parts*/
if(!_lv_area_is_on(a1_p, a2_p)) return -1;
/*No remaining areas after removing common parts*/
if(_lv_area_is_in(a1_p, a2_p, 0)) return 0;
/*Result counter*/
int8_t res_c = 0;
/*Get required information*/
lv_area_t n;
lv_coord_t a1_w = lv_area_get_width(a1_p) - 1;
lv_coord_t a1_h = lv_area_get_height(a1_p) - 1;
/*Compute top rectangle*/
lv_coord_t th = a2_p->y1 - a1_p->y1;
if(th > 0) {
n.x1 = a1_p->x1;
n.y1 = a1_p->y1;
n.x2 = a1_p->x2;
n.y2 = a1_p->y1 + th;
res_p[res_c++] = n;
}
/*Compute the bottom rectangle*/
lv_coord_t bh = a1_h - (a2_p->y2 - a1_p->y1);
if(bh > 0 && a2_p->y2 < a1_p->y2) {
n.x1 = a1_p->x1;
n.y1 = a2_p->y2;
n.x2 = a1_p->x2;
n.y2 = a2_p->y2 + bh;
res_p[res_c++] = n;
}
/*Compute side height*/
lv_coord_t y1 = a2_p->y1 > a1_p->y1 ? a2_p->y1 : a1_p->y1;
lv_coord_t y2 = a2_p->y2 < a1_p->y2 ? a2_p->y2 : a1_p->y2;
lv_coord_t sh = y2 - y1;
/*Compute the left rectangle*/
lv_coord_t lw = a2_p->x1 - a1_p->x1;
if(lw > 0 && sh > 0) {
n.x1 = a1_p->x1;
n.y1 = y1;
n.x2 = a1_p->x1 + lw;
n.y2 = y1 + sh;
res_p[res_c++] = n;
}
/*Compute the right rectangle*/
lv_coord_t rw = a1_w - (a2_p->x2 - a1_p->x1);
if(rw > 0) {
n.x1 = a2_p->x2;
n.y1 = y1;
n.x2 = a2_p->x2 + rw;
n.y2 = y1 + sh;
res_p[res_c++] = n;
}
//Return number of results
return res_c;
}
/**
* Join two areas into a third which involves the other two
* @param res_p pointer to an area, the result will be stored here

View File

@@ -194,6 +194,15 @@ void lv_area_move(lv_area_t * area, lv_coord_t x_ofs, lv_coord_t y_ofs);
*/
bool _lv_area_intersect(lv_area_t * res_p, const lv_area_t * a1_p, const lv_area_t * a2_p);
/**
* Get resulting sub areas after removing the common parts of two areas from the first area
* @param res_p pointer to an array of areas with a count of 4, the resulting areas will be stored here
* @param a1_p pointer to the first area
* @param a2_p pointer to the second area
* @return number of results (max 4) or -1 if no intersect
*/
int8_t _lv_area_diff(lv_area_t res_p[], const lv_area_t * a1_p, const lv_area_t * a2_p);
/**
* Join two areas into a third which involves the other two
* @param a_res_p pointer to an area, the result will be stored here

View File

@@ -106,7 +106,7 @@ void lv_lru_del(lv_lru_t * cache)
LV_ASSERT_NULL(cache);
// free each of the cached items, and the hash table
lv_lru_item_t * item = NULL, *next = NULL;
lv_lru_item_t * item = NULL, * next = NULL;
uint32_t i = 0;
if(cache->items) {
for(; i < cache->hash_table_size; i++) {
@@ -147,7 +147,7 @@ lv_lru_res_t lv_lru_set(lv_lru_t * cache, const void * key, size_t key_length, v
// see if the key already exists
uint32_t hash_index = lv_lru_hash(cache, key, key_length);
int required = 0;
lv_lru_item_t * item = NULL, *prev = NULL;
lv_lru_item_t * item = NULL, * prev = NULL;
item = cache->items[hash_index];
while(item && lv_lru_cmp_keys(item, key, key_length)) {
@@ -219,7 +219,7 @@ lv_lru_res_t lv_lru_remove(lv_lru_t * cache, const void * key, size_t key_size)
test_for_missing_key();
// loop until we find the item, or hit the end of a chain
lv_lru_item_t * item = NULL, *prev = NULL;
lv_lru_item_t * item = NULL, * prev = NULL;
uint32_t hash_index = lv_lru_hash(cache, key, key_size);
item = cache->items[hash_index];
@@ -237,8 +237,8 @@ lv_lru_res_t lv_lru_remove(lv_lru_t * cache, const void * key, size_t key_size)
void lv_lru_remove_lru_item(lv_lru_t * cache)
{
lv_lru_item_t * min_item = NULL, *min_prev = NULL;
lv_lru_item_t * item = NULL, *prev = NULL;
lv_lru_item_t * min_item = NULL, * min_prev = NULL;
lv_lru_item_t * item = NULL, * prev = NULL;
uint32_t i = 0, min_index = -1;
uint64_t min_access_count = -1;

View File

@@ -10,8 +10,8 @@ LV_IMAGE_DECLARE(test_animimg003)
static const lv_image_dsc_t * anim_imgs[3] = {
&test_animimg001,
&test_animimg002,
&test_animimg003,
& test_animimg002,
& test_animimg003,
};
static lv_obj_t * active_screen = NULL;