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


Having converted a project from V7 (working normally) to V8 the performance monitor is showing ~3 FPS at ~80% CPU. I have confirmed that this actually is the case (GUI task is busy) with an independent analysis tool (event analyser). Drive is configured for 2, full size, buffers.


NXP RT1064 under IAR Workbench. Display is 1024x768.

What do you want to achieve?

Similar operation as with V7

What have you tried so far?

Setting disp_drv.full_refresh = 0 results in the screen switching between the previous & current one every ~300ms and from what I can tell is not the correct setting when using 2 full size buffers.

Any guidance or suggestions are welcome.

Code to reproduce

Here is my flush function which has not changed from V7

static void FlushDisplay( lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p )
    ELCDIF_SetNextBufferAddr( LCDIF, (uint32_t)color_p );

    /* IMPORTANT!!!
     * Inform the graphics library that you are ready with the flushing*/
    lv_disp_flush_ready( disp_drv );

And here is the driver initialisation.

static lv_disp_draw_buf_t disp_buf;  // Drawing buffer.
static lv_disp_drv_t disp_drv;       // Descriptor of a display driver

void lv_port_disp_init( void )
    lv_disp_draw_buf_init( &disp_buf, LCDIF_Buffer[ 0 ], LCDIF_Buffer[ 1 ], LCDIF_PANEL_HEIGHT * LCDIF_PANEL_WIDTH );


    /* Register the display in LVGL */
    lv_disp_drv_init( &disp_drv ); /*Basic initialization*/

    /*Set the resolution of the display*/
    disp_drv.hor_res = LCD_WIDTH;
    disp_drv.ver_res = LCD_HEIGHT;

    /*Used to copy the buffer's content to the display*/
    disp_drv.flush_cb = FlushDisplay;
    disp_drv.full_refresh = 1;  // Need for double buffered mode to prevent repeated partial refreshes.

    /*Set a display buffer*/
    disp_drv.draw_buf = &disp_buf;

    /*Finally register the driver and configure the theme.*/
    lv_disp_t* display = lv_disp_drv_register( &disp_drv );
    if( display )
#include "GUI/alc_theme.h"
        display->theme = alc_theme_init( display, ALC_LIGHT_MODE );

@kisvegabor Since the RT1064 is part of the ratified hardware for LVGL it would be helpful to publish which version of LVGL the hardware was tested with. I can only assume this board was tested with V7 since V8 would surely have exhibited the problems that I describe above.

Publishing a benchmark along with LVGL certified hardware would be helpful (as suggested in this post) to many who are reviewing the library and still in the process of choosing hardware.
It also substantiates the operation of LVGL on the target platform and may well assist in debugging across different versions of LVGL (as I have encountered). Still no resolution to this BTW so I am having to stick with V7.


Have you used exactly the same disp_buf configuration in v7 and v8? There shouldn’t be so large difference, in fact v8 should be faster.

Some ideas:

  • Be sure O3 optimization is enabled. It should double the FPS.
  • Using 2 buffers in external RAM is typically very slow. Instead I suggest using only 1 frame buffer in external RAM and a smaller (e.g. 1/5 screen sized) disp_buf in internal RAM for LVGL and in flush_cb use lv_memcpy or normal memcpy (which one is faster) to copy the rendered area to the frame buffer. In this case disp_drv.full_refresh is not required.

I wanted to avoid it as SDKs get outdated very quickly, but it’d be really helpful to examine at least how the driver is set up. I can send the project on Monday.

Thanks. I look forward to reviewing the project used for testing.

Item #1: I don’t feel relying on compiler optimisation to have the code execute performantly is the solution. This code worked fine under V7.
Item #2: Two external buffers were used previously in V7 and worked perfectly so there is clearly some significant change in V8 wrt updating/refreshing regions.

BTW If you are not already aware the example projects included with NXP’s SDK are based on V7 and configured to use full size double buffers for all LVGL certified boards from NXP.

It just cam to mind there is one difference that might be important in your case. In v7 if you used 2 buffers LVGL did the following:

  • Update each invalidated area in the frame buffer
  • Call the flush_cb
  • Copy the redrawn areas to the other buffer (now inactive) to keep the 2 buffers synchronized.

I dropped this method because it wasn’t standard and the extra copy operation also caused a huge slow down if the whole screen was updated (the whole screen was copied)

In v8 full_refresh always refreshed the whole screen. So even if you just drag a slider the whole screen will the redrawn.

Could it be related to your problem?

This must be it. As mentioned, I use full sized double buffers (with PXP hardware accel) and simply swap the pointer in the flush callback which all was fine in V7. It sounds like V8 and full size double buffers don’t play well together.
It would be most helpful if you could provide the code used for testing the RT1064 certified hardware which uses V8 with a single buffer so I can see how it’s done. I have tried implementing but must have something wrong since I get visual “noise” in the refresh region.

@kisvegabor Still waiting for you to send me the project.

The dev board has only a 480x272 display, so I could place both frame buffer into internal RAM.

For your large screen for example this config should be used:

  • 1 framebuffer in external RAM
  • 1 LVGL draw buffer (1/10 screen sized) that is copied to the frame buffer in the flush_cb

Can you please provide the actual code that you used?
I’m not sure why you don’t just publish the test project used for board certification.
If you had I would probably not be pestering you with questions :wink:

Attached :slight_smile:

Here is also a new littlevgl_support.c (10.1 KB) file with a different driver implementation. It should be easy to use on your 1024x768 display too.

Thanks. I’ll take a look an let you know how it goes.

As previously mentioned the full, double buffered approach is unusable due to low FPS and high CPU usage. The alternate, single buffer approach, does work (i.e. low CPU @ 33FPS) BUT falls down when refreshing the whole screen which takes nearly 1 second! and is very obvious visually.

I have based the single buffer approach along the lines used in your attached file, lvgl_support.c.
I would really like to get this resolved as it is preventing me from upgrading to V8.