mirror of
https://github.com/lvgl/lvgl.git
synced 2024-11-27 03:33:48 +08:00
LV_VDB_DOUBLE: Add double virtual display buffer. Needs test on real hardware
This commit is contained in:
parent
d1837d2684
commit
d9147ae21b
@ -17,18 +17,19 @@
|
||||
#define LV_HOR_RES (320 * LV_DOWNSCALE)
|
||||
#define LV_VER_RES (240 * LV_DOWNSCALE)
|
||||
#define LV_DPI (80 * LV_DOWNSCALE)
|
||||
/* Enable anti-aliasing
|
||||
* If enabled everything will half-sized
|
||||
* Use LV_DOWNSCALE to compensate he down scaling effect of anti-aliasing*/
|
||||
#define LV_ANTIALIAS 1
|
||||
#define LV_DOWNSCALE (1 << LV_ANTIALIAS) /*Set the downscaling value*/
|
||||
|
||||
/* Buffered rendering: >= LV_DOWNSCALE * LV_HOR_RES or 0 to disable buffering*/
|
||||
#define LV_VDB_SIZE (LV_HOR_RES * 30)
|
||||
|
||||
/* Enable antialaiassing
|
||||
* If enabled everything will half-sized
|
||||
* Use LV_DOWNSCALE to compensate
|
||||
* the down scaling effect of antialiassing*/
|
||||
#define LV_ANTIALIAS 1
|
||||
|
||||
/*Set the downscaling value*/
|
||||
#define LV_DOWNSCALE (1 << LV_ANTIALIAS)
|
||||
#define LV_VDB_SIZE (LV_HOR_RES * LV_VER_RES / 20)
|
||||
#if LV_VDB_SIZE
|
||||
/* Double virtual buffering
|
||||
* One for rendering another to transfer former rendered image to frame buffer in the background*/
|
||||
#define LV_VDB_DOUBLE 1
|
||||
#endif
|
||||
|
||||
#define LV_REFR_PERIOD 40 /*Screen refresh period in milliseconds*/
|
||||
#define LV_INV_FIFO_SIZE 32 /*The average number of objects on a screen */
|
||||
|
@ -70,7 +70,6 @@ void lv_refr_init(void)
|
||||
ptask_t* task;
|
||||
task = ptask_create(lv_refr_task, LV_REFR_PERIOD, PTASK_PRIO_MID, NULL);
|
||||
dm_assert(task);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,7 +129,7 @@ void lv_inv_area(const area_t * area_p)
|
||||
* @param cb pointer to a callback function (void my_refr_cb(uint32_t time_ms, uint32_t px_num))
|
||||
* time_ms: refresh time in [ms]
|
||||
* px_num: not the drawn pixels but the number of affected pixels of the screen
|
||||
* (more pixels are drawn with opacity areas)
|
||||
* (more pixels are drawn because of overlapping objects)
|
||||
*/
|
||||
void lv_refr_set_monitor_cb(void (*cb)(uint32_t, uint32_t))
|
||||
{
|
||||
@ -257,15 +256,8 @@ static void lv_refr_area_no_vdb(const area_t * area_p)
|
||||
*/
|
||||
static void lv_refr_area_with_vdb(const area_t * area_p)
|
||||
{
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
|
||||
/*Always use the full row*/
|
||||
vdb_p->area.x1 = area_p->x1;
|
||||
vdb_p->area.y1 = area_p->y1;
|
||||
vdb_p->area.x2 = area_p->x2;
|
||||
|
||||
/*Calculate the max row num*/
|
||||
uint32_t max_row = (uint32_t) LV_VDB_SIZE / (vdb_p->area.x2 - vdb_p->area.x1 + 1);
|
||||
uint32_t max_row = (uint32_t) LV_VDB_SIZE / (area_get_width(area_p));
|
||||
if(max_row > area_get_height(area_p)) max_row = area_get_height(area_p);
|
||||
|
||||
/*Round the row number with downscale*/
|
||||
@ -273,20 +265,28 @@ static void lv_refr_area_with_vdb(const area_t * area_p)
|
||||
max_row &= (~0x1);
|
||||
#endif
|
||||
|
||||
/*Refresh all rows*/
|
||||
cord_t row = area_p->y1;
|
||||
|
||||
/*Always use the full row*/
|
||||
cord_t row;
|
||||
cord_t row_last = 0;
|
||||
for(row = area_p->y1; row + max_row - 1 <= area_p->y2; row += max_row) {
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
|
||||
/*Calc. the next y coordinates of VDB*/
|
||||
vdb_p->area.x1 = area_p->x1;
|
||||
vdb_p->area.x2 = area_p->x2;
|
||||
vdb_p->area.y1 = row;
|
||||
vdb_p->area.y2 = row + max_row - 1;
|
||||
|
||||
row_last = row + max_row - 1;
|
||||
lv_refr_area_part_vdb(area_p);
|
||||
}
|
||||
|
||||
/*If the last y coordinates are not handled yet ...*/
|
||||
if(area_p->y2 != vdb_p->area.y2) {
|
||||
if(area_p->y2 != row_last) {
|
||||
lv_vdb_t * vdb_p = lv_vdb_get();
|
||||
|
||||
/*Calc. the next y coordinates of VDB*/
|
||||
vdb_p->area.x1 = area_p->x1;
|
||||
vdb_p->area.x2 = area_p->x2;
|
||||
vdb_p->area.y1 = row;
|
||||
vdb_p->area.y2 = area_p->y2;
|
||||
|
||||
|
@ -20,7 +20,13 @@
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
#if LV_VDB_DOUBLE != 0
|
||||
typedef enum {
|
||||
LV_VDB_STATE_FREE = 0,
|
||||
LV_VDB_STATE_ACTIVE,
|
||||
LV_VDB_STATE_FLUSH,
|
||||
} lv_vdb_state_t;
|
||||
#endif
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
@ -28,7 +34,12 @@
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
#if LV_VDB_DOUBLE == 0
|
||||
static lv_vdb_t vdb;
|
||||
#else
|
||||
static lv_vdb_t vdb[2];
|
||||
static volatile lv_vdb_state_t vdb_state[2] = {LV_VDB_STATE_FREE, LV_VDB_STATE_FREE};
|
||||
#endif
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
@ -39,21 +50,53 @@ static lv_vdb_t vdb;
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get the vdb variable
|
||||
* @return pointer to the vdb variable
|
||||
* Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode
|
||||
* @return pointer to the 'vdb' variable
|
||||
*/
|
||||
lv_vdb_t * lv_vdb_get(void)
|
||||
{
|
||||
#if LV_VDB_DOUBLE == 0
|
||||
return &vdb;
|
||||
#else
|
||||
/*If already there is an active do nothing*/
|
||||
if(vdb_state[0] == LV_VDB_STATE_ACTIVE) return &vdb[0];
|
||||
if(vdb_state[1] == LV_VDB_STATE_ACTIVE) return &vdb[1];
|
||||
|
||||
/*Try to allocate a free VDB*/
|
||||
if(vdb_state[0] == LV_VDB_STATE_FREE) {
|
||||
vdb_state[0] = LV_VDB_STATE_ACTIVE;
|
||||
return &vdb[0];
|
||||
}
|
||||
|
||||
if(vdb_state[1] == LV_VDB_STATE_FREE) {
|
||||
vdb_state[1] = LV_VDB_STATE_ACTIVE;
|
||||
return &vdb[1];
|
||||
}
|
||||
|
||||
return NULL; /*There wasn't free VDB (never happen)*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush the content of the vdb
|
||||
* Flush the content of the VDB
|
||||
*/
|
||||
void lv_vdb_flush(void)
|
||||
{
|
||||
lv_vdb_t * vdb_act = lv_vdb_get();
|
||||
if(vdb_act == NULL) return;
|
||||
|
||||
#if LV_VDB_DOUBLE != 0
|
||||
/* Wait the pending flush before starting this one
|
||||
* (Don't forget: 'lv_vdb_flush_ready' has to be called when flushing is ready)*/
|
||||
while(vdb_state[0] == LV_VDB_STATE_FLUSH || vdb_state[1] == LV_VDB_STATE_FLUSH);
|
||||
|
||||
/*Turn the active VDB to flushing*/
|
||||
if(vdb_state[0] == LV_VDB_STATE_ACTIVE) vdb_state[0] = LV_VDB_STATE_FLUSH;
|
||||
if(vdb_state[1] == LV_VDB_STATE_ACTIVE) vdb_state[1] = LV_VDB_STATE_FLUSH;
|
||||
#endif
|
||||
|
||||
#if LV_ANTIALIAS == 0
|
||||
disp_map(vdb.area.x1, vdb.area.y1, vdb.area.x2, vdb.area.y2, vdb.buf);
|
||||
disp_map(vdb_act->area.x1, vdb_act->area.y1, vdb_act->area.x2, vdb_act->area.y2, vdb_act->buf);
|
||||
#else
|
||||
/* Get the average of 2x2 pixels and put the result back to the VDB
|
||||
* The reading goes much faster then the write back
|
||||
@ -68,12 +111,12 @@ void lv_vdb_flush(void)
|
||||
* */
|
||||
cord_t x;
|
||||
cord_t y;
|
||||
cord_t w = area_get_width(&vdb.area);
|
||||
color_t * in1_buf = vdb.buf; /*Pointer to the first row*/
|
||||
color_t * in2_buf = vdb.buf + w; /*Pointer to the second row*/
|
||||
color_t * out_buf = vdb.buf; /*Store the result here*/
|
||||
for(y = vdb.area.y1; y < vdb.area.y2; y += 2) {
|
||||
for(x = vdb.area.x1; x < vdb.area.x2; x += 2) {
|
||||
cord_t w = area_get_width(&vdb_act->area);
|
||||
color_t * in1_buf = vdb_act->buf; /*Pointer to the first row*/
|
||||
color_t * in2_buf = vdb_act->buf + w; /*Pointer to the second row*/
|
||||
color_t * out_buf = vdb_act->buf; /*Store the result here*/
|
||||
for(y = vdb_act->area.y1; y < vdb_act->area.y2; y += 2) {
|
||||
for(x = vdb_act->area.x1; x < vdb_act->area.x2; x += 2) {
|
||||
|
||||
/*If the pixels are the same do not calculate the average */
|
||||
if(in1_buf->full == (in1_buf + 1)->full &&
|
||||
@ -103,7 +146,19 @@ void lv_vdb_flush(void)
|
||||
|
||||
/* Now the full the VDB is filtered and the result is stored in the first quarter of it
|
||||
* Write out the filtered map to the display*/
|
||||
disp_map(vdb.area.x1 >> 1, vdb.area.y1 >> 1, vdb.area.x2 >> 1, vdb.area.y2 >> 1, vdb.buf);
|
||||
disp_map(vdb_act->area.x1 >> 1, vdb_act->area.y1 >> 1, vdb_act->area.x2 >> 1, vdb_act->area.y2 >> 1, vdb_act->buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* In 'LV_VDB_DOUBLE' mode has to be called when the 'disp_map'
|
||||
* is ready with copying the map to a frame buffer.
|
||||
*/
|
||||
void lv_vdb_flush_ready(void)
|
||||
{
|
||||
#if LV_VDB_DOUBLE != 0
|
||||
if(vdb_state[0] == LV_VDB_STATE_FLUSH) vdb_state[0] = LV_VDB_STATE_FREE;
|
||||
if(vdb_state[1] == LV_VDB_STATE_FLUSH) vdb_state[1] = LV_VDB_STATE_FREE;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -34,15 +34,13 @@ typedef struct
|
||||
color_t buf[LV_VDB_SIZE];
|
||||
}lv_vdb_t;
|
||||
|
||||
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Get the vdb variable
|
||||
* @return pointer to the vdb variable
|
||||
* Get the 'vdb' variable or allocate one in LV_VDB_DOUBLE mode
|
||||
* @return pointer to the 'vdb' variable
|
||||
*/
|
||||
lv_vdb_t * lv_vdb_get(void);
|
||||
|
||||
@ -51,6 +49,13 @@ lv_vdb_t * lv_vdb_get(void);
|
||||
*/
|
||||
void lv_vdb_flush(void);
|
||||
|
||||
|
||||
/**
|
||||
* In 'LV_VDB_DOUBLE' mode has to be called when 'disp_map()'
|
||||
* is ready with copying the map to a frame buffer.
|
||||
*/
|
||||
void lv_vdb_flush_ready(void);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
Loading…
Reference in New Issue
Block a user