How to register a new GPU in LVGL v9.6?

Hello everyone,

I am currently working on integrating a custom GPU with LVGL v9.6 and am looking for guidance on the correct way to register it.

Could someone provide a high-level overview or point me toward the relevant header files or structure definitions I should implement to register my GPU callbacks? Any code snippets or examples of how to properly hook this into the display flush/render process would be greatly appreciated.

Thank you for your time and help!

What do you want to achieve?

To Register a new GPU in V9.6 and to offload [e.g., fill, blit, or blend] operations to my hardware GPU

What have you tried so far?

Interfaced LCD with CPU now Plan is to use GPU for Better Performance

Code to reproduce

/*You code here*/

Screenshot and/or video

Environment

  • MCU/MPU/Board: Renesas Rh850
  • LVGL version: 9.6

Hi @Shri

The two main integration points for a custom GPU in LVGL.

Display Flush Callback (Required)

The flush callback is the primary interface between LVGL’s render output and your display/GPU. After LVGL finishes rendering into a draw buffer, it calls this function to transfer the pixels to the screen.

void my_flush_cb(lv_display_t * display, const lv_area_t * area, uint8_t * px_map)
{
    // IMPORTANT: Signal LVGL that flushing is complete
    lv_display_flush_ready(display);
}

Register it with:

lv_display_set_flush_cb(display, my_flush_cb);

If LVGL renders in multiple chunks, use lv_display_flush_is_last(display) to detect the final chunk before committing to the display.


Flush-Wait Callback (Optional but Recommended for Async GPU)

If your GPU operates asynchronously (e.g., DMA transfers), you can provide a wait callback instead of blocking inside the flush callback. This allows LVGL to use semaphores, mutexes, or polling flags to wait efficiently.

void my_flush_wait_cb(lv_display_t * disp)
{
    your_gpu_wait_for_completion();
}

Register it with:

lv_display_set_flush_wait_cb(display, my_flush_wait_cb);

Custom Draw Unit (For GPU-Accelerated Rendering)

If you want your GPU to handle the actual rendering (not just pixel transfer), you need to implement a Draw Unit. This involves:

  • Calling lv_draw_create_unit(sizeof(your_draw_unit_t)) after lv_init()

  • Implementing evaluate_cb — decides if your GPU can handle a given draw task

  • Implementing dispatch_cb — submits the draw task to your GPU

  • Optionally implementing wait_for_finish_cb for async rendering

The relevant structure is lv_draw_unit_t:

struct _lv_draw_unit_t {
    lv_draw_unit_t * next;
    const char * name;
    int32_t idx;
    int32_t (*dispatch_cb)(lv_draw_unit_t * draw_unit, lv_layer_t * layer);
    int32_t (*evaluate_cb)(lv_draw_unit_t * draw_unit, lv_draw_task_t * task);
    int32_t (*wait_for_finish_cb)(lv_draw_unit_t * draw_unit);
    int32_t (*delete_cb)(lv_draw_unit_t * draw_unit);
    void    (*event_cb)(lv_event_t * event);
};

Thanks @halyssonJr