docs(draw.rst): restructure and proofread from PR #7241 (#7976)
Arduino Lint / lint (push) Waiting to run
MicroPython CI / Build esp32 port (push) Waiting to run
MicroPython CI / Build rp2 port (push) Waiting to run
MicroPython CI / Build stm32 port (push) Waiting to run
MicroPython CI / Build unix port (push) Waiting to run
C/C++ CI / Build OPTIONS_16BIT - Ubuntu (push) Waiting to run
C/C++ CI / Build OPTIONS_24BIT - Ubuntu (push) Waiting to run
C/C++ CI / Build OPTIONS_FULL_32BIT - Ubuntu (push) Waiting to run
C/C++ CI / Build OPTIONS_NORMAL_8BIT - Ubuntu (push) Waiting to run
C/C++ CI / Build OPTIONS_SDL - Ubuntu (push) Waiting to run
C/C++ CI / Build OPTIONS_VG_LITE - Ubuntu (push) Waiting to run
C/C++ CI / Build OPTIONS_16BIT - cl - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_16BIT - gcc - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_24BIT - cl - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_24BIT - gcc - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_FULL_32BIT - cl - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_FULL_32BIT - gcc - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_VG_LITE - cl - Windows (push) Waiting to run
C/C++ CI / Build OPTIONS_VG_LITE - gcc - Windows (push) Waiting to run
C/C++ CI / Build ESP IDF ESP32S3 (push) Waiting to run
C/C++ CI / Run tests with 32bit build (push) Waiting to run
C/C++ CI / Run tests with 64bit build (push) Waiting to run
BOM Check / bom-check (push) Waiting to run
Verify that lv_conf_internal.h matches repository state / verify-conf-internal (push) Waiting to run
Verify the widget property name / verify-property-name (push) Waiting to run
Verify code formatting / verify-formatting (push) Waiting to run
Build docs / build-and-deploy (push) Waiting to run
Test API JSON generator / Test API JSON (push) Waiting to run
Check Makefile / Build using Makefile (push) Waiting to run
Check Makefile for UEFI / Build using Makefile for UEFI (push) Waiting to run
Port repo release update / run-release-branch-updater (push) Waiting to run
Verify Kconfig / verify-kconfig (push) Waiting to run

Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
Co-authored-by: Liam Howatt <30486941+liamHowatt@users.noreply.github.com>
This commit is contained in:
Victor Wheeler
2025-03-31 10:08:45 -06:00
committed by GitHub
parent b88fb674d3
commit 7fb89e47f7
8 changed files with 1034 additions and 87 deletions
@@ -409,7 +409,7 @@ Here is a shortened example of what the output looks like.
],
"structures":[
{
"name":"_lv_gradient_cache_t",
"name":"_lv_grad_cache_t",
"type":{
"name":"struct",
"json_type":"primitive_type"
@@ -0,0 +1,90 @@
.. _draw_api:
========
Draw API
========
Where to Use the Drawing API
****************************
In most cases you use LVGL's Drawing API through the API of Widgets: by creating
buttons, labels, etc., and setting the their styles, positions, and other properties.
In these cases rendering (drawing) is handled internally and you doen't see the
:ref:`Drawing Pipeline <draw_pipeline>` at all.
However there are three places where you can use LVGL's Drawing API directly.
1. **In the draw events of the Widgets**:
There are event codes which are sent when the Widget needs to render itself:
- :cpp:enumerator:`LV_EVENT_DRAW_MAIN_BEGIN`, :cpp:enumerator:`LV_EVENT_DRAW_MAIN`,
:cpp:enumerator:`LV_EVENT_DRAW_MAIN_END`:
Triggered before, during, and after a Widget is drawn, respectively. Widget
rendering typically occurs in :cpp:enumerator:`LV_EVENT_DRAW_MAIN`.
- :cpp:enumerator:`LV_EVENT_DRAW_POST_BEGIN`, :cpp:enumerator:`LV_EVENT_DRAW_POST`,
:cpp:enumerator:`LV_EVENT_DRAW_POST_END`:
Triggered before, during, and after all child Widgets are rendered, respectively.
This can be useful for overlay-like drawings, such as scrollbars which should be
rendered on top of any children.
These are relevant if a new Widget is implemented and it uses custom drawing.
2. **Modifying the created draw tasks**:
The when a draw task is created for a Widget :cpp:enumerator:`LV_EVENT_DRAW_TASK_ADDED`
is sent. In this event the created draw task can be modified or new draw tasks
can be added. Typical use cases for this are modifying each bar of a bar chart,
or cells of a table.
For performance reasons, this event is disabled by default. Enable it by setting
the :cpp:enumerator:`LV_OBJ_FLAG_SEND_DRAW_TASK_EVENTS` flag on the Widget(s) you
wish to emit this event.
3. **Draw to the Canvas Widget**:
The drawing functions can be used directly to draw to a Canvas Widget. Doing so
renders custom drawing to a buffer which can be used later as an image or a mask.
For more information see :ref:`lv_canvas`.
Drawing API
***********
The main components of LVGL's Drawing API are the :cpp:func:`lv_draw_rect`,
:cpp:func:`lv_draw_label`, :cpp:func:`lv_draw_image`, and similar functions.
When they are called :cpp:type:`lv_draw_task_t` objects are created internally.
These functions have the following parameters:
- **Layer**: This is the target of the drawing. See details at :ref:`draw_layers`.
- **Draw Descriptor**: This is a large ``struct`` containing all the information
about the drawing. See details of the draw descriptors at :ref:`draw_descriptors`.
- **Area** (in some cases): Specifies where to draw.
Coordinate System
*****************
Some functions and draw descriptors require area or point parameters. These are
always **absolute coordinates** on the display. For example, if the target layer is
on a 800x480 display and the layer's area is (100,100) (200,200), to render a 10x10
object in the middle, the coordinates (145,145) (154,154) should be used
(not (40,40) (49,49)).
Exception: for the Canvas Widget the layer is always assumed to be at the (0,0)
coordinate, regardless of the Canvas Widget's position.
API
***
.. API equals:
LV_EVENT_DRAW_MAIN_BEGIN
lv_draw_arc
lv_draw_image
lv_draw_label
lv_draw_line
lv_draw_mask_rect
lv_draw_triangle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,140 @@
.. _draw_layers:
===========
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:
1. **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 :cpp:expr:`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 :cpp:func:`lv_draw_layer`.
2. **Modifying the created Draw Tasks**:
In :cpp:enumerator:`LV_EVENT_DRAW_TASK_ADDED` the draw tasks created by
``lv_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 with
``lv_draw_rect/label/etc`` the current layer is also required.
The current layer can be read from the ``base`` draw descriptor. For example:
.. code-block:: c
/* 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;
3. **Draw to the Canvas Widget**:
The canvas itself doesn't store a layer, but one can be easily created and used
like this:
.. code-block:: c
/* 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 :cpp:func:`lv_draw_layer_create`:
.. code-block:: c
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 :ref:`Draw API <draw_api>` and :ref:`Draw descriptors <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:
.. code-block:: c
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 :ref:`Draw Units` when the first :ref:`Draw Task <draw
tasks>` is dispatched.
Layer buffers can be large, so ensure there is sufficient heap memory or increase
:c:macro:`LV_MEM_SIZE` in ``lv_conf.h``.
Layer Types
-----------
To save memory, LVGL can render certain types of layers in smaller chunks:
1. **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 using :c:macro:`LV_DRAW_LAYER_SIMPLE_BUF_SIZE` in ``lv_conf.h``.
2. **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
:c:macro:`LV_DRAW_LAYER_MAX_MEMORY` in ``lv_conf.h``. If set to ``0``, there is no
limit.
API
***
.. API equals:
lv_draw_layer_create
LV_EVENT_DRAW_TASK_ADDED
lv_event_get_layer
@@ -1,16 +1,26 @@
.. _draw:
.. _draw_pipeline:
================
Drawing Pipeline
================
=============
Draw Pipeline
=============
Overview
********
What is Drawing?
****************
Drawing is writing pixel colors into a buffer where they will be delivered to a
display panel as pixels. Sometimes it involves computing those colors before they
are written (e.g. combining them with other colors when an object has partial opacity).
Drawing (also known as :dfn:`rendering`) is writing pixel colors into a buffer where
they will be delivered to a display panel as pixels. Sometimes this is done by
copying colors from places like background- and foreground-color properties. Other
times it involves computing those colors before they are written (e.g. combining them
with other colors when an object higher on the Z axis has partial opacity).
The following sections cover the LVGL drawing logic and how to use it and optionally
tune it to fit your particular project (e.g. if you have a GPU or other resources
that you would like to get involved).
Draw-Pipeline Overview
**********************
On modern computing hardware meant to be used with larger display panels, there are
sometimes options for different ways drawing can be accomplished. For example, some
@@ -18,20 +28,24 @@ MCUs come with hardware that is very good (and fast) at certain types of drawing
tasks. Alternatively, you might have access to a drawing library that performs
certain types of drawing tasks with great efficiency. To make it possible to utilize
such facilities in the most efficient fashion, LVGL v9 and onwards implements a
"Drawing Pipeline", like an assembly line, where decisions are made as to which
:dfn:`Drawing Pipeline`, like an assembly line, where decisions are made as to which
drawing tasks (:ref:`Draw Tasks`) are given to which "logic entities"
(:ref:`Draw Units`) in order to be carried out.
This Pipeline is designed so that it is both flexible and extendable. As a
programmer, you can hook into it in order to provide LVGL with guidance as to what
Draw Units should receive what types of Draw Tasks, or replace LVGL's built-in
software rendering logic to any degree you choose.
This Pipeline is designed so that it is both flexible and extendable. You can use it
to perform custom rendering with a GPU, or replace the parts of the built-in software
rendering logic to any extent desired.
Using events, it's also possible to modify :ref:`draw tasks` or insert new ones as
LVGL renders Widgets.
The following sections describe the basic terminology and concepts of rendering.
.. _draw tasks:
Draw Tasks
----------
**********
A "Draw Task" (:cpp:type:`lv_draw_task_t`) is a package of information that is
created at the beginning of the Drawing Pipeline when a request to draw is made.
@@ -40,20 +54,20 @@ one or more Draw Tasks and pass them down the Drawing Pipeline. Each Draw Task
carries all the information required to:
- compute which :ref:`Draw Unit <draw units>` should receive this task, and
- give the Draw Unit all the details required to accomplish the drawing task.
- give the Draw Unit all the information required to accomplish the drawing task.
A Draw Task carries the following information:
:type: defines the drawing algorithm involved (e.g. line, fill, border, image,
label, arc, triangle, etc.)
:area: defines the rectangle involved where drawing will occur
:type: defines the drawing algorithm involved (e.g. line, fill,
border, image, label, arc, triangle, etc.)
:area: defines the rectangle in which drawing will occur
:transformation matrix: if :c:macro:`LV_DRAW_TRANSFORM_USE_MATRIX` is configured to '1'
:state: waiting, queued, in progress, completed
:drawing descriptor: carries details of the drawing to be performed
:preferred Draw Unit ID: the ID of the Draw Unit that should take this task
:preferred Draw Unit ID: identifier of the Draw Unit that should carry out this task
:preference score: value describing the speed of the specified Draw Unit relative
to software rendering (more on this below)
:next: a link to the next drawing task in the list.
:next: a link to the next Draw Task in the list.
Draw Tasks are collected in a list and periodically dispatched to Draw Units.
@@ -61,12 +75,15 @@ Draw Tasks are collected in a list and periodically dispatched to Draw Units.
.. _draw units:
Draw Units
----------
**********
A "Draw Unit" (based on :cpp:type:`lv_draw_unit_t`) is any "logic entity" that can
generate the output required by a :ref:`Draw Task <draw tasks>`. This can be a CPU
core, a GPU, a new rendering library for certain (or all) Draw Tasks, or anything
that can accomplish drawing.
core, a GPU, a custom rendering library for specific Draw Tasks, or any entity
capable of performing rendering.
For a reference implementation of a draw unit, see
`lv_draw_sw.c <https://github.com/lvgl/lvgl/blob/master/src/draw/sw/lv_draw_sw.c>`__.
During LVGL's initialization (:cpp:func:`lv_init`), a list of Draw Units is created.
If :c:macro:`LV_USE_DRAW_SW` is set to ``1`` in ``lv_conf.h`` (it is by default), the
@@ -76,8 +93,8 @@ they are added to this list during LVGL's initialization. If you are adding you
Draw Unit(s), you add each available drawing unit to that list by calling
:cpp:expr:`lv_draw_create_unit(sizeof(your_draw_unit_t))`. With each call to that
function, the newly-created draw unit is added to the head of that list, pushing
already-existing draw units further back in the list, making the earliest Draw Unit
created last in the list. The order of this list (and thus the order in which
already-existing draw units further back in the list, pushing the Draw Units created
earlier farther back in the list. The order of this list (and thus the order in which
:ref:`Draw Task Evaluation` is performed) is governed by the order in which each Draw
Unit is created.
@@ -96,23 +113,29 @@ For an example of how draw-unit cration and initialization is done, see
:cpp:func:`lv_draw_sw_init` in lv_draw_sw.c_ or the other draw units whose ``init``
functions are optionally called in :cpp:func:`lv_init`.
.. _lv_draw_sw.c: https://github.com/lvgl/lvgl/blob/master/src/draw/sw/lv_draw_sw.c
.. _draw task evaluation:
Draw Task Evaluation
--------------------
********************
When each :ref:`Draw Task <draw tasks>` is created, each existing Draw Unit is
"consulted" as to its "appropriateness" for the task. It does this through
an "evaluation callback" function pointer (a.k.a. ``evaluate_cb``), which each Draw
Unit sets (for itself) during its initialization. Normally, that evaluation
optionally examines the existing "preference score" for the task mentioned above,
and if it can accomplish that type of task (e.g. line drawing) faster than other
Draw Units that have already reported, it writes its own "preference score" and
"preferred Draw Unit ID" to the respective fields in the task. In this way, by the
time the evaluation sequence is complete, the task will contain the score and the ID
of the Drawing Unit that will be used to perform that task when it is
:ref:`dispatched <draw task dispatching>`.
Unit sets (for itself) during its initialization. Normally, that evaluation:
- optionally examines the existing "preference score" for the task mentioned above,
- if it can accomplish that type of task (e.g. line drawing) faster than other
Draw Units that have already reported, it writes its own "preference score" and
"preferred Draw Unit ID" to the respective fields in the task.
In this way, by the time the evaluation sequence is complete, the task will contain
the score and the ID of the Drawing Unit that will be used to perform that task when
it is :ref:`dispatched <draw task dispatching>`.
This logic, of course, can be overridden or redefined, depending on system design.
As a side effect, this also ensures that the same Draw Unit will be selected
consistently, depending on the type (and nature) of the drawing task, avoiding any
@@ -128,7 +151,7 @@ will handle it.
.. _draw task dispatching:
Dispatching
-----------
***********
While collecting Draw Tasks LVGL frequently dispatches the collected Draw Tasks to
their assigned Draw Units. This is handled via the ``dispatch_cb`` of the Draw Units.
@@ -145,54 +168,32 @@ ready to be carried out. The ramifications of having multiple drawing threads a
taken into account for this.
Layers
------
A layer is a buffer with a given area on which the pixel rendering occurrs. Each
display has a "main" layer, but during rendering additional layers might be created
internally to handle for example arbitrary Widget transformations.
Object Hierarchy
----------------
Run-Time Object Hierarchy
*************************
All of the above have this relationship at run time:
- LVGL
- LVGL (global)
- list of Draw Units
- list of Display(s)
- list of :ref:`Draw Units`
- list of :ref:`Display(s) <display_overview>`
- Layer(s): Each Display has its own list of Layers
- Layer(s): Each :ref:`Display object <display_overview>` has its own list of :ref:`draw_layers`
- Draw Tasks: Each Layer has its own list of Draw Tasks
.. _draw_events:
Events
******
- :cpp:enumerator:`LV_EVENT_DRAW_TASK_ADDED` when each :ref:`Draw Task <draw tasks>`
is created and before it is dispatched to the :ref:`Draw Unit <draw units>` that
will handle it.
.. admonition:: Further Reading
Learn more about :ref:`lv_obj_events` emitted by all Widgets.
Learn more about :ref:`events`.
lv_draw_sw.c_
.. _lv_draw_sw.c: https://github.com/lvgl/lvgl/blob/master/src/draw/sw/lv_draw_sw.c
- Draw Tasks: Each Layer has its own list of :ref:`Draw Tasks`
API
***
.. API equals:
lv_draw_create_unit
lv_draw_get_next_available_task
lv_draw_label
lv_draw_rect
lv_draw_sw_init
lv_draw_task_t
LV_DRAW_TRANSFORM_USE_MATRIX
lv_draw_unit_t
LV_USE_DRAW_OPENGLES
@@ -0,0 +1,13 @@
.. _draw:
=======
Drawing
=======
.. toctree::
:maxdepth: 2
draw_pipeline
draw_api
draw_layers
draw_descriptors
+1 -1
View File
@@ -15,4 +15,4 @@ Main Modules
timer
animation
fs
draw
draw/index
+8 -10
View File
@@ -1,25 +1,23 @@
Play with a simple horizontal gradient
--------------------------------------
Simple Horizontal Gradient
--------------------------
.. lv_example:: get_started/lv_example_grad_1
:language: c
Play with a linear (skew) gradient
----------------------------------
Linear (Skew) Gradient
----------------------
.. lv_example:: get_started/lv_example_grad_2
:language: c
Play with a radial gradient
---------------------------
Radial Gradient
---------------
.. lv_example:: get_started/lv_example_grad_3
:language: c
Play with a conical gradient
----------------------------
Conical Gradient
----------------
.. lv_example:: get_started/lv_example_grad_4
:language: c