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);
};