1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-14 06:42:58 +08:00

feat(display) add direct_mode drawing mode (#2460)

* feat(display) add direct_mode drawing mode

* update the docs
This commit is contained in:
Gabor Kiss-Vamosi 2021-11-05 15:35:36 +01:00 committed by GitHub
parent acd0f4fbc7
commit 607dfeceb6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 26 deletions

View File

@ -34,20 +34,42 @@ If only a small area changes (e.g. a button is pressed) then only that area will
A larger buffer results in better performance but above 1/10 screen sized buffer(s) there is no significant performance improvement.
Therefore it's recommended to choose the size of the draw buffer(s) to be at least 1/10 screen sized.
If only **one buffer** is used LVGL draws the content of the screen into that draw buffer and sends it to the display.
## Buffering modes
There are several settings to adjust the number draw buffers and buffering/refreshing modes.
You can measure the performance of different configurations using the [benchmark example](https://github.com/lvgl/lv_demos/tree/master/src/lv_demo_benchmark).
### One buffer
If only one buffer is used LVGL draws the content of the screen into that draw buffer and sends it to the display.
LVGL then needs to wait until the content of the buffer is sent to the display before drawing something new in it.
If **two buffers** are used LVGL can draw into one buffer while the content of the other buffer is sent to the display in the background.
### Two buffers
If two buffers are used LVGL can draw into one buffer while the content of the other buffer is sent to the display in the background.
DMA or other hardware should be used to transfer data to the display so the MCU can continue drawing.
This way, the rendering and refreshing of the display become parallel operations.
### Full refresh
In the display driver (`lv_disp_drv_t`) enabling the `full_refresh` bit will force LVGL to always redraw the whole screen. This works in both *one buffer* and *two buffers* modes.
If `full_refresh` is enabled and two screen sized draw buffers are provided, LVGL's display handling works like "traditional" double buffering.
This means the `flush_cb` callback only has to update the address of the framebuffer (`color_p` parameter).
This configuration should be used if the MCU has an LCD controller peripheral and not with an external display controller (e.g. ILI9341 or SSD1963) accessed via serial link. The latter will generally be too slow to maintain high frame rates with full screen redraws.
You can measure the performance of different draw buffer configurations using the [benchmark example](https://github.com/lvgl/lv_demos/tree/master/src/lv_demo_benchmark).
### Direct mode
If the `direct mode` flag is enabled in the display driver LVGL will draw directly into a **screen sized frame buffer**. That is the draw buffer(s) needs to be screen sized.
It this case `flush_cb` will be called only once when all dirty areas are redrawn.
With `direct_mode` the frame buffer always contains the current frame as it should be displayed on the screen.
If 2 frame buffers are provided as draw buffers LVGL will alter the buffers but always draw only the dirty areas.
Therefore the the 2 buffers needs to synchronized in `flush_cb` like this:
1. Display the frame buffer pointed by `color_p`
2. Copy the redrawn areas from `color_p` to the other buffer.
The get the redrawn areas to copy use the following functions
`_lv_refr_get_disp_refreshing()` returns the display being refreshed
`disp->inv_areas[LV_INV_BUF_SIZE]` contains the invalidated areas
`disp->inv_area_joined[LV_INV_BUF_SIZE]` if 1 that area was joined into an other one and should be ignored
`disp->inv_p` number of valid elements in `inv_areas`
```
## Display driver
@ -77,7 +99,11 @@ There are some optional display driver data fields:
- `anti_aliasing` use anti-aliasing (edge smoothing). Enabled by default if `LV_COLOR_DEPTH` is set to at least 16 in `lv_conf.h`.
- `rotated` and `sw_rotate` See the [Rotation](#rotation) section below.
- `screen_transp` if `1` the screen itself can have transparency as well. `LV_COLOR_SCREEN_TRANSP` must be enabled in `lv_conf.h` and `LV_COLOR_DEPTH` must be 32.
- `user_data` A custom `void` user data for the driver..
- `user_data` A custom `void` user data for the driver.
- `full_refresh` always redrawn the whole screen (see above)
- `direct_mode` drive directly into the frame buffer (see above)
- `user_data` A custom `void `user data for the driver..
Some other optional callbacks to make it easier and more optimal to work with monochrome, grayscale or other non-standard RGB displays:
- `rounder_cb` Round the coordinates of areas to redraw. E.g. a 2x2 px can be converted to 2x8.

View File

@ -457,31 +457,43 @@ static void lv_refr_area(const lv_area_t * area_p)
}
}
/*Always use the full row*/
lv_coord_t row;
lv_coord_t row_last = 0;
for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) {
/*Calc. the next y coordinates of draw_buf*/
draw_buf->area.x1 = area_p->x1;
draw_buf->area.x2 = area_p->x2;
draw_buf->area.y1 = row;
draw_buf->area.y2 = row + max_row - 1;
if(draw_buf->area.y2 > y2) draw_buf->area.y2 = y2;
row_last = draw_buf->area.y2;
if(y2 == row_last) disp_refr->driver->draw_buf->last_part = 1;
/*In direct mode draw directly on the absolute coordinates of the buffer*/
if(disp_refr->driver->direct_mode) {
draw_buf->area.x1 = 0;
draw_buf->area.x2 = lv_disp_get_hor_res(disp_refr) - 1;
draw_buf->area.y1 = 0;
draw_buf->area.y2 = lv_disp_get_ver_res(disp_refr) - 1;
disp_refr->driver->draw_buf->last_part = disp_refr->driver->draw_buf->last_area;
lv_refr_area_part(area_p);
}
/*Else assume the buffer starts at the given area*/
else {
/*Always use the full row*/
lv_coord_t row;
lv_coord_t row_last = 0;
for(row = area_p->y1; row + max_row - 1 <= y2; row += max_row) {
/*Calc. the next y coordinates of draw_buf*/
draw_buf->area.x1 = area_p->x1;
draw_buf->area.x2 = area_p->x2;
draw_buf->area.y1 = row;
draw_buf->area.y2 = row + max_row - 1;
if(draw_buf->area.y2 > y2) draw_buf->area.y2 = y2;
row_last = draw_buf->area.y2;
if(y2 == row_last) disp_refr->driver->draw_buf->last_part = 1;
lv_refr_area_part(area_p);
}
/*If the last y coordinates are not handled yet ...*/
if(y2 != row_last) {
/*Calc. the next y coordinates of draw_buf*/
draw_buf->area.x1 = area_p->x1;
draw_buf->area.x2 = area_p->x2;
draw_buf->area.y1 = row;
draw_buf->area.y2 = y2;
/*If the last y coordinates are not handled yet ...*/
if(y2 != row_last) {
/*Calc. the next y coordinates of draw_buf*/
draw_buf->area.x1 = area_p->x1;
draw_buf->area.x2 = area_p->x2;
draw_buf->area.y1 = row;
draw_buf->area.y2 = y2;
disp_refr->driver->draw_buf->last_part = 1;
lv_refr_area_part(area_p);
disp_refr->driver->draw_buf->last_part = 1;
lv_refr_area_part(area_p);
}
}
}

View File

@ -89,6 +89,7 @@ typedef struct _lv_disp_drv_t {
* LVGL will use this buffer(s) to draw the screens contents*/
lv_disp_draw_buf_t * draw_buf;
uint32_t direct_mode : 1; /**< 1: Use screen-sized buffers and draw to absolute coordinates*/
uint32_t full_refresh : 1; /**< 1: Always make the whole screen redrawn*/
uint32_t sw_rotate : 1; /**< 1: use software rotation (slower)*/
uint32_t antialiasing : 1; /**< 1: anti-aliasing is enabled on this display.*/