Skip to content

Commit

Permalink
Merge pull request #399 from espressif/bsp/lvgl_performance
Browse files Browse the repository at this point in the history
doc(LVGL port): Updated performance documentation for LVGL9
  • Loading branch information
espzav authored Oct 14, 2024
2 parents d823752 + 239f07c commit 61ab9cb
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 52 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ If you'd like to propose a change to the existing APIs or a large-scale refactor

## Third-party boards

ESP-BSP project is currently intended only to host BSPs for development boards manufactured by Espressif.
ESP-BSP project is currently intended only to host BSPs for development boards manufactured by Espressif and M5Stack.

If you want to create a BSP for a third-party board, we suggest creating a separate repository for it. You are welcome to use the ESP-BSP project as a template for your own board support package repository.

## Pre-commit hooks

ESP-BSP project uses [pre-commit hooks](https://pre-commit.com/) to perform code formatting and other checks when you run `git commit`.

To install pre-commit hooks, run `pip install pre-commit && pre-commit install`.
To install pre-commit hooks, run `pip install pre-commit && pre-commit install`.

If a pre-commit hook has modified any of the files when you run `git commit`, add these changes using `git add` and run `git commit` again.

Expand Down
5 changes: 5 additions & 0 deletions components/esp_lvgl_port/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 2.3.3

### Features
- Updated RGB screen flush handling in LVGL9.

## 2.3.2

### Fixes
Expand Down
73 changes: 41 additions & 32 deletions components/esp_lvgl_port/docs/performance.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# LCD & LVGL Performance

This document provides steps, how to set up your LCD and LVGL port for the best performance and comparison of different settings. All settings and measurements are valid for Espressif's chips.
This document provides steps, how to set up your LCD and LVGL port for the best performance and comparison of different settings. All settings and measurements are valid for Espressif's chips. Examples in [ESP-BSP](https://github.com/espressif/esp-bsp) are ready to use with the best performance.

## Performance metrics

Expand All @@ -26,7 +26,7 @@ On the other hand, the frame buffer(s) will consume significant portion of your

Main takeaways from the graph are:

* The size of **LVGL buffer** and **double buffering** feature has big impact on performance.
* The size of **LVGL buffer** and **double buffering** feature has big impact on performance.
* Frame buffer size >25% of the screen does not bring relevant performance boost
* Frame buffer size <10% will have severe negative effect on performance

Expand Down Expand Up @@ -67,18 +67,53 @@ The main LVGL task can be processed on the second core of the CPU. It can increa

### Using esp-idf `memcpy` and `memset` instead LVGL's configuration

Native esp-idf implementation are a little (~1-3 FPS) faster.
Native esp-idf implementation are a little (~1-3 FPS) faster (only for LVGL8).

* `CONFIG_LV_MEMCPY_MEMSET_STD=y`

### Default LVGL display refresh period

This setting can improve subjective performance during screen transitions (scrolling, etc.).

LVGL8
* `CONFIG_LV_DISP_DEF_REFR_PERIOD=10`

LVGL9
* `CONFIG_LV_DEF_REFR_PERIOD=10`

## Example FPS improvement vs graphical settings

The LVGL9 benchmark demo uses a different algorithm for measuring FPS. In this case, we used the same algorithm for measurement in LVGL8 for comparison.

### RGB LCD, PSRAM (octal) with GDMA - ESP32-S3-LCD-EV-BOARD

<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/esp32-s3-lcd-ev-board_800x480.png?raw=true" align="right" width="300px" />

Default settings:
* BSP example `display_lvgl_demos`
* LCD: 4.3" 800x480
* Interface: RGB
* LVGL buffer size: 800 x 480
* LVGL buffer mode: Direct (avoid-tearing)
* LVGL double buffer: NO
* Optimization: Debug
* CPU frequency: 160 MHz
* Flash frequency: 80 MHz
* PSRAM frequency: 80 MHz
* Flash mode: DIO
* LVGL display refresh period: 30 ms

| Average FPS (LVGL8) | Average FPS (LVGL 9.2) | Changed settings |
| :---: | :---: | ---------------- |
| 12 | 9 | Default |
| 13 | 9 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
| 14 | 11 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
| 14 | 11 | + Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
| 15 | 11 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
| 16 | 11 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10` / `CONFIG_LV_DEF_REFR_PERIOD=10`) |

### Parallel 8080 LCD (only for LVGL8)

<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/7inch-Capacitive-Touch-LCD-C_l.jpg?raw=true" align="right" width="300px" />

Default settings:
Expand All @@ -94,7 +129,7 @@ Default settings:
* Flash mode: DIO
* LVGL display refresh period: 30 ms

### Internal RAM with DMA
#### Internal RAM with DMA

| Average FPS | Weighted FPS | Changed settings |
| :---: | :---: | ---------------- |
Expand All @@ -105,7 +140,7 @@ Default settings:
| 28 | **60** | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
| 41 | 55 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) |

### PSRAM (QUAD) without DMA
#### PSRAM (QUAD) without DMA

Default changes:
* LCD IO clock: 2 MHz
Expand All @@ -124,36 +159,10 @@ Default changes:

[^1]: This is not working in default and sometimes in fast changes on screen is not working properly.

### RGB LCD (without `esp_lvgl_port`), PSRAM (octal) with GDMA - ESP32-S3-LCD-EV-BOARD

<img src="https://github.com/espressif/esp-bsp/blob/master/docu/pics/esp32-s3-lcd-ev-board_800x480.png?raw=true" align="right" width="300px" />

Default settings:
* BSP example `display_lvgl_demos`
* LCD: 4.3" 800x480
* Interface: RGB
* LVGL buffer size: 800 x 100
* LVGL double buffer: NO
* Optimization: Debug
* CPU frequency: 160 MHz
* Flash frequency: 80 MHz
* PSRAM frequency: 80 MHz
* Flash mode: DIO
* LVGL display refresh period: 30 ms

| Average FPS | Weighted FPS | Changed settings |
| :---: | :---: | ---------------- |
| 18 | 24 | Default |
| 18 | 26 | + Optimization: Performance (`CONFIG_COMPILER_OPTIMIZATION_PERF=y`) |
| 21 | 32 | + CPU frequency: 240 MHz (`CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y`) |
| 21 | 32 | + Flash mode: QIO (`CONFIG_ESPTOOLPY_FLASHMODE_QIO=y`) |
| 21 | 32 | + LVGL fast memory enabled (`CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM=y`) |
| 35 | 34 | + (`CONFIG_LV_DISP_DEF_REFR_PERIOD=10`) |

## Conclusion

The graphical performance depends on a lot of things and settings, many of which affect the whole system (Compiler, Flash, CPU, PSRAM configuration...). The user should primarily focus on trade-off between frame-buffer(s) size and RAM consumption of the buffer, before optimizing the design further.

Other configuration options not covered in this document are:
* Hardware interfaces, color depth, screen definition (size), clocks, LCD controller and more.
* Hardware interfaces, color depth, screen definition (size), clocks, LCD controller and more.
* Complexity of the graphical application (number of LVGL objects and their styles).
2 changes: 1 addition & 1 deletion components/esp_lvgl_port/idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "2.3.2"
version: "2.3.3"
description: ESP LVGL port
url: https://github.com/espressif/esp-bsp/tree/master/components/esp_lvgl_port
dependencies:
Expand Down
4 changes: 2 additions & 2 deletions components/esp_lvgl_port/src/lvgl8/esp_lvgl_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg)

BaseType_t res;
if (cfg->task_affinity < 0) {
res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task);
res = xTaskCreate(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task);
} else {
res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task, cfg->task_affinity);
res = xTaskCreatePinnedToCore(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task, cfg->task_affinity);
}
ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!");

Expand Down
4 changes: 2 additions & 2 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,9 @@ esp_err_t lvgl_port_init(const lvgl_port_cfg_t *cfg)

BaseType_t res;
if (cfg->task_affinity < 0) {
res = xTaskCreate(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task);
res = xTaskCreate(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task);
} else {
res = xTaskCreatePinnedToCore(lvgl_port_task, "LVGL task", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task, cfg->task_affinity);
res = xTaskCreatePinnedToCore(lvgl_port_task, "taskLVGL", cfg->task_stack, NULL, cfg->task_priority, &lvgl_port_ctx.lvgl_task, cfg->task_affinity);
}
ESP_GOTO_ON_FALSE(res == pdPASS, ESP_FAIL, err, TAG, "Create LVGL task fail!");

Expand Down
34 changes: 21 additions & 13 deletions components/esp_lvgl_port/src/lvgl9/esp_lvgl_port_disp.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static bool lvgl_port_flush_panel_ready_callback(esp_lcd_panel_handle_t panel_io
#endif
#endif
static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map);
static void lvgl_port_flush_wait_callback(lv_display_t *drv);
static void lvgl_port_disp_size_update_callback(lv_event_t *e);
static void lvgl_port_disp_rotation_update(lvgl_port_display_ctx_t *disp_ctx);
static void lvgl_port_display_invalidate_callback(lv_event_t *e);
Expand Down Expand Up @@ -170,6 +171,11 @@ lv_display_t *lvgl_port_add_disp_rgb(const lvgl_port_display_cfg_t *disp_cfg, co
ESP_RETURN_ON_FALSE(false, NULL, TAG, "RGB is supported only on ESP32S3 and from IDF 5.0!");
#endif

/* Set wait callback */
if (disp_ctx->flags.full_refresh || disp_ctx->flags.direct_mode) {
lv_display_set_flush_wait_cb(disp, lvgl_port_flush_wait_callback);
}

/* Apply rotation from initial display configuration */
lvgl_port_disp_rotation_update(disp_ctx);
}
Expand Down Expand Up @@ -466,6 +472,17 @@ void lvgl_port_rotate_area(lv_display_t *disp, lv_area_t *area)
}
}


static void lvgl_port_flush_wait_callback(lv_display_t *drv)
{
assert(drv != NULL);
if (lv_disp_flush_is_last(drv)) {
/* Waiting for the last frame buffer to complete transmission */
ulTaskNotifyValueClear(NULL, ULONG_MAX);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
}

static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, uint8_t *color_map)
{
assert(drv != NULL);
Expand Down Expand Up @@ -512,20 +529,11 @@ static void lvgl_port_flush_callback(lv_display_t *drv, const lv_area_t *area, u
_lvgl_port_transform_monochrome(drv, area, color_map);
}

/* RGB LCD */
if (disp_ctx->disp_type == LVGL_PORT_DISP_TYPE_RGB && (disp_ctx->flags.full_refresh || disp_ctx->flags.direct_mode)) {
if (lv_disp_flush_is_last(drv)) {
/* If the interface is I80 or SPI, this step cannot be used for drawing. */
esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
/* Waiting for the last frame buffer to complete transmission */
ulTaskNotifyValueClear(NULL, ULONG_MAX);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
} else {
esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);
}
/* Draw */
esp_lcd_panel_draw_bitmap(disp_ctx->panel_handle, offsetx1, offsety1, offsetx2 + 1, offsety2 + 1, color_map);

if (disp_ctx->disp_type == LVGL_PORT_DISP_TYPE_RGB) {
/* Call flush ready only in RGB screen when not full refresh or direct mode */
if (disp_ctx->disp_type == LVGL_PORT_DISP_TYPE_RGB && !disp_ctx->flags.full_refresh && !disp_ctx->flags.direct_mode) {
lv_disp_flush_ready(drv);
}
}
Expand Down

0 comments on commit 61ab9cb

Please sign in to comment.