Why does FPS become lower when the hardware double FB is turned on

Platform: ARM9
Software: Linux, support rgb565, hardware double FB
Display: 480x480
The initialization and refresh codes are as follows:

static void _lv_init(void)
{
   uint32_t width, height;
   uint32_t size;

  /*LittlevGL init*/
    lv_init();

    /*Linux frame buffer device init*/
    fbdev_init();
    fbdev_get_sizes(&width,&height);
    
    fr_kprintf("width:%d height:%d\n",width,height);
    
    size = width*height;

#ifdef LV_DOUBLE_FB_EN

    lv_color_t *p_buf1 =  (lv_color_t *)fr_malloc(size*sizeof(lv_color_t));
    lv_color_t *p_buf2 =  (lv_color_t *)fr_malloc(size*sizeof(lv_color_t));
 
    static lv_disp_draw_buf_t disp_buf;
    lv_disp_draw_buf_init(&disp_buf, p_buf1, p_buf2, size);
#else
    /*A small buffer for LittlevGL to draw the screen's content*/
    lv_color_t *p_buf =  (lv_color_t *)fr_malloc(size*sizeof(lv_color_t));
    /*Initialize a descriptor for the buffer*/
    static lv_disp_draw_buf_t disp_buf;
    lv_disp_draw_buf_init(&disp_buf, p_buf, NULL, size);

#endif
    /*Initialize and register a display driver*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.draw_buf   = &disp_buf;
    disp_drv.flush_cb   = fbdev_flush;
    disp_drv.hor_res    = width;
    disp_drv.ver_res    = height;
#ifdef LV_DOUBLE_FB_EN
    disp_drv.full_refresh = 1;
#endif
    lv_disp_drv_register(&disp_drv);


	/* Linux input device init */
    evdev_init();
    /* Initialize and register a display input driver */
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);      /*Basic initialization*/

    indev_drv.type      = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb   = evdev_read;   //lv_gesture_dir_t lv_indev_get_gesture_dir(const lv_indev_t * indev)
    lv_indev_drv_register(&indev_drv); 

}
void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p)
{
    if(fbp == NULL ||
            area->x2 < 0 ||
            area->y2 < 0 ||
            area->x1 > (int32_t)vinfo.xres - 1 ||
            area->y1 > (int32_t)vinfo.yres - 1) {
        lv_disp_flush_ready(drv);
        return;
    }

#ifdef LV_DOUBLE_FB_EN
        static int fb_double_toggle_flg = 0;
        vinfo.yoffset = vinfo.yres*fb_double_toggle_flg;	
        fb_double_toggle_flg=!fb_double_toggle_flg;
#endif

    /*Truncate the area to the screen*/
    int32_t act_x1 = area->x1 < 0 ? 0 : area->x1;
    int32_t act_y1 = area->y1 < 0 ? 0 : area->y1;
    int32_t act_x2 = area->x2 > (int32_t)vinfo.xres - 1 ? (int32_t)vinfo.xres - 1 : area->x2;
    int32_t act_y2 = area->y2 > (int32_t)vinfo.yres - 1 ? (int32_t)vinfo.yres - 1 : area->y2;


    lv_coord_t w = (act_x2 - act_x1 + 1);
    long int location = 0;
    long int byte_location = 0;
    unsigned char bit_location = 0;



   
    /*16 bit per pixel*/
     if(vinfo.bits_per_pixel == 16) {
        uint16_t * fbp16 = (uint16_t *)fbp;
        int32_t y;
        for(y = act_y1; y <= act_y2; y++) {
            location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 2;
            memcpy(&fbp16[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 2);
            color_p += w;
        }
     } else {
        /*Not supported bit per pixel*/
    }

    //May be some direct update command is required
    //ret = ioctl(state->fd, FBIO_UPDATE, (unsigned long)((uintptr_t)rect));

#ifdef LV_DOUBLE_FB_EN
    int zero = 0;
    if(ioctl(fbfd, FBIO_WAITFORVSYNC, &zero)<0){
        fprintf(stderr, "wait vsync fb swap failed\n");
    }
    if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
        fprintf(stderr, "active fb swap failed\n");
    }
     
    
#endif
    
    lv_disp_flush_ready(drv);

}

-When the hardware double is not turned on(LV_DOUBLE_FB_EN is not defined), FPS can reach 33, and the experience is better
-When the hardware double is enabled (LV_DOUBLE_FB_EN is defined), the FPS can only reach 14, and the experience is very bad
why?

My first guess is these lines:

#ifdef LV_DOUBLE_FB_EN
    disp_drv.full_refresh = 1;
#endif

It makes LVGL to always refresh the whole screen even if only 1 pixel has been changed. Without enabling this feature if you press a button only that button will be redrawn, which is much faster, and looks like higher FPS.

1.First of all, thank you for your reply. I try to put disp_ drv. full_ Refresh = 0, and then the display is abnormal: the contents of the two pages are displayed alternately. Later, after checking the online data, someone said that it needs to be set to 1. Sure enough, the display is normal after setting it to 1, but the FPS is only about 14;
2.I wonder if the code about frame synchronization and switching to the next FB in my refresh function is correct?

#ifdef LV_DOUBLE_FB_EN
    int zero = 0;
    if(ioctl(fbfd, FBIO_WAITFORVSYNC, &zero)<0){
        fprintf(stderr, "wait vsync fb swap failed\n");
    }
    if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
        fprintf(stderr, "active fb swap failed\n");
    }
     
    
#endif

3.Thank you again and have a nice work!

With full_refresh=0 LVGL will give you only the rendered (previously dirty) area. So you need to do something like this.

But if you can do ioctl to refresh on VSYNC there is other (better) option: the disp_drv->direct_mode flag. See here.

Basically all you need to do is set disp_drv->direct_mode and in flush_cb:

if(lv_disp_flush_is_last(drv)) {
    int zero = 0;
    if(ioctl(fbfd, FBIO_WAITFORVSYNC, &zero)<0) {
        fprintf(stderr, "wait vsync fb swap failed\n");
    }
    if (ioctl(fbfd, FBIOPAN_DISPLAY, &vinfo) < 0) {
        fprintf(stderr, "active fb swap failed\n");
    }
}
lv_disp_flush_ready(drv);