V8 display driver (double buffer) low FPS & high CPU

Hi @pete-pjb and @xennex,

To be sure we are on the same page I’d like to clarify the difference between v7 and v8 in this regard.

v7
If you set 2 screens sized buffers, v7 worked in a special “true double buffered mode”. It worked like this:

  1. Render invalid areas to the inactive buffer
  2. Swap the buffers
  3. Copy the redrawn areas to new inactive buffer to have them the same content.

I considered it wasteful especially with screen sized animations because here the whole screen was copied and then overwritten it a new content.

v8
There are 2 modes that can be set explicitly:

  • full_refresh: LVGL always redraws the whole screen. So no copying is required.
  • direct mode: LVGL redraws only the dirty areas in a screen sized buffer. So NO full-screen refresh, but the buffers are not synchronized. It’s useful, if you can send full frames to a GPU to display.

IMO performance issue is the largest if you set full_refresh but only a small area changes. In v7 it was fast (small rendering + small copy) but in v8 it’s slower (large rendering).

I was thinking about adding a v7-like mode to v8, but in v8 we started to think more abstractly. I.e. the draw buffer can be anything like an lv_color_t array, SDL Texture in GPU, specially packed bitmap, or any internal non accessible buffer. So we can’t simply memcpy it.

However, in the flush_cb you can mimic v7’s behavior like this:

  1. Set 2 full screen buffer with full_refr = 0, direct_mode = 1
  2. In flush_cb check if lv_disp_flush_is_last(drv) == true
  3. If so, copy the areas:
my_set_active_buffers(color_p);
lv_disp_t* disp = _lv_refr_get_disp_refreshing();
for(i = 0; i < disp->inv_p; i++) {
   ​if(disp->inv_joined[i]) continue;
 ​
 ​  my_copy_area(disp->inv_areas[i]);
}

I haven’t tested it but I’d be happy to help with it further if you can help with testing on embedded HW.