[lvgl 8.3.2] Corrupted display when disp_drv.direct_mode = 1

I wrote a hardware overlay driver for my laptop (a 10-year old one) and am trying the demo widget with it.

The issue is: if I do not put disp_drv.direct_mode = 1;, the window of the demo widget is fast but is corrupted when I click “Analytics”. If setting it, all graphics are correct but the FPS is like 10fps at most.

My expectation: showing the graphics correct and fast, with both settings.

Thanks for any helps!

My config is:

static uint32_t vinfo_xres = 800;
static uint32_t vinfo_yres = 600;
static uint32_t vinfo_xoffset = 0;
static uint32_t vinfo_yoffset = 0;
static uint32_t vinfo_bits_per_pixel = 32;
static uint32_t finfo_line_length = vinfo_xres * 4; // bytes for each line, aka "stride"

My code is:

static void libgui_flush_cb(struct _lv_disp_drv_t *disp_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(disp_drv);
        return;
    }

    // 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;

    // 32 or 24 bit per pixel
    if(vinfo_bits_per_pixel == 32 || vinfo_bits_per_pixel == 24) {
        uint32_t * fbp32 = (uint32_t *)fbp;
        int32_t y;

        {
            location = (act_x1 + vinfo_xoffset) + (act_y1 + vinfo_yoffset) * finfo_line_length / 4;
            printf("[Superymk] <libgui_flush_cb> act_x1:%d, act_x2:%d, act_y1:%d, act_y2:%d, location_start:%ld\n", 
                act_x1, act_x2, act_y1, act_y2, location);
        }

        for(y = act_y1; y <= act_y2; y++) {
            location = (act_x1 + vinfo_xoffset) + (y + vinfo_yoffset) * finfo_line_length / 4;
            memcpy(&fbp32[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1) * 4);
            color_p += w;
        }
    }
    // 16 bit per pixel
    else 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;
        }
    }
    // 8 bit per pixel
    else if(vinfo_bits_per_pixel == 8) {
        uint8_t * fbp8 = (uint8_t *)fbp;
        int32_t y;
        for(y = act_y1; y <= act_y2; y++) {
            location = (act_x1 + vinfo_xoffset) + (y + vinfo_yoffset) * finfo_line_length;
            memcpy(&fbp8[location], (uint32_t *)color_p, (act_x2 - act_x1 + 1));
            color_p += w;
        }
    }
    // 1 bit per pixel
    else if(vinfo_bits_per_pixel == 1) {
        uint8_t * fbp8 = (uint8_t *)fbp;
        int32_t x;
        int32_t y;
        for(y = act_y1; y <= act_y2; y++) {
            for(x = act_x1; x <= act_x2; x++) {
                location = (x + vinfo_xoffset) + (y + vinfo_yoffset) * vinfo_xres;
                byte_location = location / 8; /* find the byte we need to change */
                bit_location = location % 8; /* inside the byte found, find the bit we need to change */
                fbp8[byte_location] &= ~(((uint8_t)(1)) << bit_location);
                fbp8[byte_location] |= ((uint8_t)(color_p->full)) << bit_location;
                color_p++;
            }

            color_p += area->x2 - act_x2;
        }
    } 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));

    lv_disp_flush_ready(disp_drv);

And init function is:

SAP_STATUS status = SUCCESS;

    // Check: <cfg> must be valid
    if (!cfg)
        return EINVAL;

    if(cfg->fb_vaddr == INVALID_VADDR)
        return EINVAL;

    // Check: No double init
    if (disp)
        return EINVAL;

    // Initialize window canvas
    // LittlevGL init
    lv_init();

    // Initialize a descriptor for the buffer
    static lv_disp_draw_buf_t disp_buf;
    lv_disp_draw_buf_init(&disp_buf, (void *)cfg->fb_vaddr, NULL, cfg->fb_width * cfg->fb_height);
    fbp = (void *)cfg->fb_vaddr;

    // Initialize and register a display driver
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);





    disp_drv.direct_mode = 1;







    disp_drv.draw_buf = &disp_buf;
    disp_drv.flush_cb = libgui_flush_cb;
    disp_drv.hor_res = cfg->fb_width;
    disp_drv.ver_res = cfg->fb_height;
    disp = lv_disp_drv_register(&disp_drv);
    if (!disp)
    {
        GUI_ERR("Init Lib-GUI error: Failed to init display!\n");
        status = EINTERNAL;
        goto init_disp_err;
    }

    //// Display configs
    vinfo_xres = 800;
    vinfo_yres = 600;
    vinfo_xoffset = 0;
    vinfo_yoffset = 0;
    vinfo_bits_per_pixel = 32;
    finfo_line_length = vinfo_xres * 4; // bytes for each line, aka "stride"

    // Register keyboard
    static lv_indev_drv_t kbd_drv;
    lv_indev_drv_init(&kbd_drv); /*Basic initialization*/
    kbd_drv.type = LV_INDEV_TYPE_KEYPAD;
    kbd_drv.read_cb = libgui_keyboard_read;
    kbd_indev = lv_indev_drv_register(&kbd_drv);
    if (!kbd_indev)
    {
        GUI_ERR("Init Lib-GUI error: Failed to init keyboard!\n");
        status = EINTERNAL;
        goto init_kbd_err;
    }

    // Register mouse
    static lv_indev_drv_t mouse_drv;
    lv_indev_drv_init(&mouse_drv); /*Basic initialization*/
    mouse_drv.type = LV_INDEV_TYPE_POINTER;

    // This function will be called periodically (by the library) to get the mouse position and state
    mouse_drv.read_cb = libgui_mouse_read;
    mouse_indev = lv_indev_drv_register(&mouse_drv);
    if (!mouse_indev)
    {
        GUI_ERR("Init Lib-GUI error: Failed to init mouse!\n");
        status = EINTERNAL;
        goto init_mouse_err;
    }

    //// Configure mouse
    lines_per_wheel = cfg->lines_per_wheel;

    // Set a cursor for the mouse
    LV_IMG_DECLARE(mouse_cursor_icon)
    cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
    if (!cursor_obj)
    {
        GUI_ERR("Init Lib-GUI error: Failed to init cursor!\n");
        status = EINTERNAL;
        goto init_cursor_err;
    }
    lv_img_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
    lv_indev_set_cursor(mouse_indev, cursor_obj);   /*Connect the image  object to the driver*/

    /*Create a Demo*/
    lv_demo_widgets();

    GUI_INFO("Initialize Lib-GUI Success\n");
    return SUCCESS;

init_cursor_err:
init_mouse_err:
init_kbd_err:
init_disp_err:
    return status;

Screenshot (setting disp_drv.direct_mode = 1;):

Screenshot (no disp_drv.direct_mode = 1;):

Hi, @Superymk , do you resolve this question?

No, I tried lvgl 8.3.3 and the issue is still there. My previous description is inconsistent with the figures. Here is the correction:

If disp_drv.direct_mode = 0, then the corruption happens
If disp_drv.direct_mode = 1, then the display is good but slow.

Some other backgrounds: (1) I do not use interrupts, so I use while loop to read mouse and update screen, and I do not put any sleep in the while loop. (2) I do not use double buffers, and fbp directly points to the correct VRAM. Why it is correct? Otherwise, disp_drv.direct_mode = 1 should highly likely output corrupted images.

Thanks!

I implement according to this code, direct mode can show correct, maybe you can try it:

Thanks a lot! I’ll try it once I get time and let you know if I have any further issues!

Best regards,
Superymk