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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
*--------------------*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user