Draw Layers
A layer is a buffer with a specified area where pixel rendering occurs. Each display has a "main" layer, but additional layers may be created internally during rendering to handle tasks such as Widget transformations.
Getting the Current Layer
The first parameter of the lv_draw_rect/label/etc
functions is a layer.
In most of the cases a layer is not created, but an existing layer is used to draw there.
The draw API can be used in these cases and the current layer can be used differently in each case:
In draw events: In
LV_EVENT_DRAW_MAIN/POST_BEGIN/...
events the Widget is being rendered to a layer of the display or another temporary layer created earlier during rendering. The current target layer can be retrieved using lv_event_get_layer(e).It also possible to create new layers in these events, but the previous layer is also required since it will be the parent layer in
lv_draw_layer()
.Modifying the created Draw Tasks: In
LV_EVENT_DRAW_TASK_ADDED
the draw tasks created bylv_draw_rect/label/etc
can be modified. It's not required to know the current layer to modify a draw task. However, if something new also needs to be drawn withlv_draw_rect/label/etc
the current layer is also required.The current layer can be read from the
base
draw descriptor. For example:/* In LV_EVENT_DRAW_TASK_ADDED */ lv_draw_task_t * t = lv_event_get_draw_task(e); lv_draw_base_dsc_t * draw_dsc = lv_draw_task_get_draw_dsc(t); lv_layer_t * current_layer = draw_dsc.layer;
Draw to the Canvas Widget: The canvas itself doesn't store a layer, but one can be easily created and used like this:
/* Initialize a layer */ lv_layer_t layer; lv_canvas_init_layer(canvas, &layer); /* Draw something here */ /* Wait until the rendering is ready */ lv_canvas_finish_layer(canvas, &layer);
Creating a New Layer
To create a new layer, use lv_draw_layer_create()
:
lv_area_t layer_area = {10, 10, 80, 50}; /* Area of the new layer */
lv_layer_t * new_layer = lv_draw_layer_create(parent_layer, LV_COLOR_FORMAT_RGB565, &layer_area);
Once the layer is created, draw tasks can be added to it
by using the Draw API and Draw descriptors.
In most cases this means calling the lv_draw_rect/label/etc
functions.
Finally, the layer must be rendered to its parent layer. Since a layer behaves similarly to an image, it can be rendered the same way as images:
lv_draw_image_dsc_t image_draw_dsc;
lv_draw_image_dsc_init(&image_draw_dsc);
image_draw_dsc.src = new_layer; /* Source image is the new layer. */
/* Draw new layer to parent layer. */
lv_draw_layer(parent_layer, &image_draw_dsc, &layer_area);
Memory Considerations
Layer Buffers
The buffer for a layer (where rendering occurs) is not allocated at creation. Instead, it is allocated by Draw Units when the first Draw Task is dispatched.
Layer buffers can be large, so ensure there is sufficient heap memory or increase
LV_MEM_SIZE
in lv_conf.h
.
Layer Types
To save memory, LVGL can render certain types of layers in smaller chunks:
Simple Layers: Simple layers can be rendered in chunks. For example, with
opa_layered = 140
, only 10 lines of the layer can be rendered at a time, then the next 10 lines, and so on. This avoids allocating a large buffer for the entire layer. The buffer size for a chunk is set usingLV_DRAW_LAYER_SIMPLE_BUF_SIZE
inlv_conf.h
.Transformed Layers: Transformed Widgets cannot be rendered in chunks because transformations often affect pixels outside the given area. For such layers, LVGL allocates a buffer large enough to render the entire transformed area without limits.
Memory Limit for Layers
The total memory available for layers at once is controlled by
LV_DRAW_LAYER_MAX_MEMORY
in lv_conf.h
. If set to 0
, there is no
limit.