站点图标

LVGL 01 Enable Transparent Plane

  In this article, we'll trying to overlay a UI layer onto a video layer, which like OSD. Here is my platform information.

  1. System: kernel 4.19
  2. LVGL Version: 8.3
  3. Display Driver: DRM
  4. CPU: RV1126, which have two layers.

§1 Check Plane Info

  If your CPU's VOP support multiple layer, then you could draw UI and video on difference layer. In this article, I use RV1126 to implement this function. If you use framebuffer as display interface, then you can directly draw image or UI on different fb device. Such as, draw video on fb1, UI on fb0. If you use DRM, using modetest to check whether planes support overlay.

[root@DCIR:/]# modetest
Encoders:
id  crtc    type    possible crtcs  possible clones 
58  56  DSI 0x00000001  0x00000000

Connectors:
id  encoder status      name        size (mm)   modes   encoders
59  58  connected   DSI-1           68x121      1   58
  modes:
    name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot)
  800x1280 57 800 818 836 882 1280 1310 1314 1328 67000 flags: nhsync, nvsync; type: preferred, driver
  props:
    1 EDID:
        flags: immutable blob
        blobs:

        value:
    2 DPMS:
        flags: enum
        enums: On=0 Standby=1 Suspend=2 Off=3
        value: 0
    5 link-status:
        flags: enum
        enums: Good=0 Bad=1
        value: 0
    6 non-desktop:
        flags: immutable range
        values: 0 1
        value: 0
    46 brightness:
        flags: range
        values: 0 100
        value: 50
    47 contrast:
        flags: range
        values: 0 100
        value: 50
    50 saturation:
        flags: range
        values: 0 100
        value: 50
    51 hue:
        flags: range
        values: 0 100
        value: 50

CRTCs:
id  fb  pos size
56  60  (0,0)   (800x1280)
  800x1280 57 800 818 836 882 1280 1310 1314 1328 67000 flags: nhsync, nvsync; type: preferred, driver
  props:
    41 left margin:
        flags: range
        values: 0 100
        value: 100
    42 right margin:
        flags: range
        values: 0 100
        value: 100
    43 top margin:
        flags: range
        values: 0 100
        value: 100
    44 bottom margin:
        flags: range
        values: 0 100
        value: 100
    54 FEATURE:
        flags: immutable bitmask
        values: afbdc=0x1
        value: 0
    26 GAMMA_LUT:
        flags: blob
        blobs:

        value:
    27 GAMMA_LUT_SIZE:
        flags: immutable range
        values: 0 4294967295
        value: 256

Planes:
id  crtc    fb  CRTC x,y    x,y gamma size  possible crtcs
55  56  60  0,0     0,0 0           0x00000001
  formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16
  props:
    8 type:
        flags: immutable enum
        enums: Overlay=0 Primary=1 Cursor=2
        value: 1
    53 FEATURE:
        flags: immutable bitmask
        values: scale=0x1 alpha=0x2 hdr2sdr=0x4 sdr2hdr=0x8 afbdc=0x10
        value: 2
57  0   0   0,0     0,0 0           0x00000001
  formats: XR24 AR24 XB24 AB24 RG24 BG24 RG16 BG16 NV12 NV16 NV24
  props:
    8 type:
        flags: immutable enum
        enums: Overlay=0 Primary=1 Cursor=2
        value: 0
    53 FEATURE:
        flags: immutable bitmask
        values: scale=0x1 alpha=0x2 hdr2sdr=0x4 sdr2hdr=0x8 afbdc=0x10
        value: 3

Frame buffers:
id  size    pitch

1.1 Connectors

  Connected output port via CPU, here we only have one MIPI-DSI output which id equals 59.

1.2 CRTCs

  Video Output Processor, for RV1126, we only have one VOP which id equals 56.

1.3 Planes

  i.e. layer, for RV1126, we have two layers. plane-55's props specify it's a primary layer, and plane-57 is a overlay layer. so, we should draw video on primary player, and draw UI on overlay layer.

§2 LVGL config

  Here are several steps to enable transparent background:

2.1 LV_COLOR_DEPTH & LV_COLOR_SCREEN_TRANSP

  1. In lv_conf.h, make sure color depth is 32, eg. #define LV_COLOR_DEPTH 32, which allows alpha channel.
  2. In lv_conf.h, enable LV_COLOR_SCREEN_TRANSP, eg. #define LV_COLOR_SCREEN_TRANSP 1.

2.2 Specify planes

  Here I manually specify LVGL's plane id as 57. In lv_drivers/display/drm.c, for function drm_setup, we modify:

// ret = find_plane(fourcc, &drm_dev.plane_id, drm_dev.crtc_id, drm_dev.crtc_idx);
// if (ret) {
//  err("Cannot find plane");
//  goto err;
// }
drm_dev.plane_id = 57;

2.3 Set background opa

  In main function, we add:

lv_style_t style_scr_act;
lv_style_init(&style_scr_act);
lv_style_set_bg_opa(&style_scr_act, LV_OPA_TRANSP);
lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);
// lv_disp_set_bg_opa(lv_scr_act(), LV_OPA_TRANSP);

The complete main:

int main(void)
{

    DRM_Init();

    // capture and draw video
    pthread_t pth_capt;

    pthread_create(&pth_capt, NULL, (void*)V4L2_SP_Streaming, NULL);

#if 1
/* ================ */
/* ===== LVGL ===== */
/* ================ */

    /*LittlevGL init*/
    lv_init();

    /*Linux frame buffer device init*/
    drm_init();

    /*A small buffer for LittlevGL to draw the screen's content*/
    static lv_color_t buf[DISP_BUF_SIZE], buf1[DISP_BUF_SIZE];

    /*Initialize a descriptor for the buffer*/
    static lv_disp_draw_buf_t disp_buf;
    // lv_disp_draw_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE);
    lv_disp_draw_buf_init(&disp_buf, buf, buf1, DISP_BUF_SIZE);

    /*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   = drm_flush;
    disp_drv.hor_res    = 800;
    disp_drv.ver_res    = 1280;
    disp_drv.screen_transp = 1;
    lv_disp_drv_register(&disp_drv);

#if 1
    evdev_init();
    static lv_indev_drv_t indev_drv_1;
    lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
    indev_drv_1.type = LV_INDEV_TYPE_POINTER;

    /*This function will be called periodically (by the library) to get the mouse position and state*/
    indev_drv_1.read_cb = evdev_read;
    lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);
#endif

#if 1
    /*Set a cursor for the mouse*/
    LV_IMG_DECLARE(mouse_cursor_icon)
    lv_obj_t * cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
    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*/
#endif

#if 1
    lv_style_t style_scr_act;
    lv_style_init(&style_scr_act);
    lv_style_set_bg_opa(&style_scr_act, LV_OPA_TRANSP);
    lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);
    // lv_disp_set_bg_opa(lv_scr_act(), LV_OPA_TRANSP);
#endif

    mybtn();

    /*Handle LitlevGL tasks (tickless mode)*/
    while(1) {
        lv_timer_handler();
        usleep(5000);
    }
#endif

    pthread_exit(NULL);

    return 0;
}
退出移动版