From ee8de1e1a0d7da36cbfd840c299abfe3ac027719 Mon Sep 17 00:00:00 2001 From: nicusorcitu <97085059+nicusorcitu@users.noreply.github.com> Date: Fri, 12 Jan 2024 12:54:42 +0200 Subject: [PATCH] feat(nxp): release NXP PXP and VG-Lite for LVGL v9.0 (#5288) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nicușor Cîțu Signed-off-by: Ana Grad Co-authored-by: Ana Grad --- docs/integration/chip/nxp.rst | 530 +++++++++++------- lv_conf_template.h | 52 +- src/draw/nxp/pxp/lv_draw_buf_pxp.c | 81 +-- src/draw/nxp/pxp/lv_draw_pxp.c | 262 +++++++-- src/draw/nxp/pxp/lv_draw_pxp.h | 18 +- src/draw/nxp/pxp/lv_draw_pxp_bg_img.c | 93 --- src/draw/nxp/pxp/lv_draw_pxp_fill.c | 12 +- src/draw/nxp/pxp/lv_draw_pxp_img.c | 51 +- src/draw/nxp/pxp/lv_draw_pxp_layer.c | 110 +++- src/draw/nxp/pxp/lv_pxp_cfg.c | 4 - src/draw/nxp/pxp/lv_pxp_osa.c | 8 +- src/draw/nxp/pxp/lv_pxp_osa.h | 2 +- src/draw/nxp/pxp/lv_pxp_utils.c | 45 +- src/draw/nxp/pxp/lv_pxp_utils.h | 12 +- src/draw/nxp/vglite/lv_draw_buf_vglite.c | 126 ++--- src/draw/nxp/vglite/lv_draw_vglite.c | 262 ++++++--- src/draw/nxp/vglite/lv_draw_vglite.h | 31 +- src/draw/nxp/vglite/lv_draw_vglite_arc.c | 39 +- src/draw/nxp/vglite/lv_draw_vglite_bg_img.c | 113 ---- src/draw/nxp/vglite/lv_draw_vglite_border.c | 67 +-- src/draw/nxp/vglite/lv_draw_vglite_fill.c | 99 ++-- src/draw/nxp/vglite/lv_draw_vglite_img.c | 156 +++--- src/draw/nxp/vglite/lv_draw_vglite_label.c | 84 ++- src/draw/nxp/vglite/lv_draw_vglite_layer.c | 113 +++- src/draw/nxp/vglite/lv_draw_vglite_line.c | 56 +- src/draw/nxp/vglite/lv_draw_vglite_triangle.c | 179 ++++++ src/draw/nxp/vglite/lv_vglite_buf.c | 10 +- src/draw/nxp/vglite/lv_vglite_buf.h | 15 +- src/draw/nxp/vglite/lv_vglite_matrix.c | 7 +- src/draw/nxp/vglite/lv_vglite_utils.c | 188 +++---- src/draw/nxp/vglite/lv_vglite_utils.h | 59 +- src/lv_conf_internal.h | 104 +++- src/stdlib/builtin/lv_mem_core_builtin.c | 8 +- .../src/test_cases/draw/test_draw_sw_rotate.c | 2 +- tests/src/test_cases/test_anim.c | 2 +- tests/src/test_cases/test_bindings.c | 2 +- tests/src/test_cases/widgets/test_bar.c | 2 +- tests/src/test_cases/widgets/test_msgbox.c | 2 +- 38 files changed, 1735 insertions(+), 1271 deletions(-) delete mode 100644 src/draw/nxp/pxp/lv_draw_pxp_bg_img.c delete mode 100644 src/draw/nxp/vglite/lv_draw_vglite_bg_img.c create mode 100644 src/draw/nxp/vglite/lv_draw_vglite_triangle.c diff --git a/docs/integration/chip/nxp.rst b/docs/integration/chip/nxp.rst index 0936c57b9..3ca4bae39 100644 --- a/docs/integration/chip/nxp.rst +++ b/docs/integration/chip/nxp.rst @@ -2,158 +2,191 @@ NXP === -NXP has integrated LVGL into the MCUXpresso SDK packages for general -purpose and crossover microcontrollers, allowing easy evaluation and -migration into your product design. -`Download an SDK for a supported board `__ -today and get started with your next GUI application. +NXP has integrated LVGL into the MCUXpresso SDK packages for several of our +microcontrollers as an optional software component, allowing easy evaluation and +migration into your product design. LVGL is a free and open-source embedded +graphic library with features that enable you need to create embedded GUIs with +intuitive graphical elements, beautiful visual effects and a low memory +footprint. The complete graphic framework includes a variety of widgets for you +to use in the creation of your GUI, and supports more advanced functions such as +animations and anti-aliasing. +LVGL enables graphics in our free GUI Guider UI tool. It's available for use +with NXP’s general purpose and crossover microcontrollers, providing developers +with a tool for creating complete, high quality GUI applications with LVGL. Creating new project with LVGL ------------------------------ -Downloading the MCU SDK example project is recommended as a starting -point. It comes fully configured with LVGL (and with PXP/VGLite support -if the modules are present), no additional integration work is required. - +`Download an SDK for a supported board `__ +today and get started with your next GUI application. It comes fully configured +with LVGL (and with PXP/VGLite support if the modules are present), no +additional integration work is required. HW acceleration for NXP iMX RT platforms ---------------------------------------- -Depending on the RT platform used, the acceleration can be done by NXP -PXP (PiXel Pipeline) and/or the Verisilicon GPU through an API named -VGLite. Each accelerator has its own context that allows them to be used -individually as well simultaneously (in LVGL multithreading mode). - +Depending on the RT platform used, the acceleration can be done by NXP PXP +(PiXel Pipeline) and/or the Verisilicon GPU through an API named VGLite. Each +accelerator has its own context that allows them to be used individually as well +simultaneously (in LVGL multithreading mode). PXP accelerator ~~~~~~~~~~~~~~~ - -Several drawing features in LVGL can be offloaded to the PXP engine. The -CPU is available for other operations while the PXP is running. RTOS is -required to block the LVGL drawing thread and switch to another task or -suspend the CPU for power savings. - -Supported draw callbacks are available in "src/draw/nxp/pxp/lv_draw_pxp.c": - -.. code:: c - - pxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_pxp_img_decoded; - pxp_draw_ctx->blend = lv_draw_pxp_blend; - pxp_draw_ctx->base_draw.wait_for_finish = lv_draw_pxp_wait_for_finish; - - -Features supported: -^^^^^^^^^^^^^^^^^^^ - -All operations can be used in conjunction with optional transparency. - -- RGB565 and ARGB8888 color formats -- Area fill with color -- BLIT (BLock Image Transfer) -- Screen Rotation (90, 180, 270 degree) -- Color keying -- Recoloring (color tint) -- Image Rotation (90, 180, 270 degree) -- RTOS integration layer -- Default FreeRTOS and bare metal code provided -- Combination of recolor and/or rotation + color key/alpha - blend/transparency is supported. That is achieved by PXP in two - steps: - - - First step is to recolor/rotate the image to a temporary buffer (statically allocated) - - Second step is required to handle color keying, alpha channel or to apply transparency - - -Known limitations: -^^^^^^^^^^^^^^^^^^ - -- Rotation is not supported for images unaligned to blocks of 16x16 - pixels. PXP is set to process 16x16 blocks to optimize the system for - memory bandwidth and image processing time. The output engine - essentially truncates any output pixels after the desired number of - pixels has been written. When rotating a source image and the output - is not divisible by the block size, the incorrect pixels could be - truncated and the final output image can look shifted. - - Basic configuration: ^^^^^^^^^^^^^^^^^^^^ -- Select NXP PXP engine in lv_conf.h: Set :c:macro:`LV_USE_GPU_NXP_PXP` to ``1`` -- Enable default implementation for interrupt handling, PXP start - function and automatic initialization: Set - :c:macro:`LV_USE_GPU_NXP_PXP_AUTO_INIT` to ``1`` +- Select NXP PXP engine in "lv_conf.h": Set :c:macro:`LV_USE_DRAW_PXP` to `1`. +- Enable PXP asserts in "lv_conf.h": Set :c:macro: `LV_USE_PXP_ASSERT` to `1`. + There are few PXP assertions that can stop the program execution in case the + c:macro: `LV_ASSERT_HANDLER` is set to `while(1);` (Halt by default). Else, + there will be logged just an error message via `LV_LOG_ERROR`. - If :c:macro:`SDK_OS_FREE_RTOS` symbol is defined, FreeRTOS implementation - will be used, otherwise bare metal code will be included - + will be used, otherwise bare metal code will be included. Basic initialization: ^^^^^^^^^^^^^^^^^^^^^ -- If :c:macro:`LV_USE_GPU_NXP_PXP_AUTO_INIT` is enabled, no user code is - required; PXP is initialized automatically in :cpp:func:`lv_init` -- For manual PXP initialization, default configuration structure for - callbacks can be used. Initialize PXP before calling :cpp:func:`lv_init` +PXP draw initialization is done automatically in :cpp:func:`lv_init()` once the +PXP is enabled, no user code is required: .. code:: c - #if LV_USE_GPU_NXP_PXP - #include "src/draw/nxp/pxp/lv_gpu_nxp_pxp.h" - #endif - ... - #if LV_USE_GPU_NXP_PXP - PXP_COND_STOP(!lv_gpu_nxp_pxp_init(), "PXP init failed."); - #endif + #if LV_USE_DRAW_PXP + lv_draw_pxp_init(); + #endif +During PXP initialization, a new draw unit `lv_draw_pxp_unit_t` will be created +with the additional callbacks: + +.. code:: c + + lv_draw_pxp_unit_t * draw_pxp_unit = lv_draw_create_unit(sizeof(lv_draw_pxp_unit_t)); + draw_pxp_unit->base_unit.evaluate_cb = _pxp_evaluate; + draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch; + draw_pxp_unit->base_unit.delete_cb = _pxp_delete; + +and an addition thread `_pxp_render_thread_cb()` will be spawned in order to +handle the supported draw tasks. + +.. code:: c + + #if LV_USE_OS + lv_thread_init(&draw_pxp_unit->thread, LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 2 * 1024, draw_pxp_unit); + #endif + +If `LV_USE_OS` is not defined, then no additional draw thread will be created +and the PXP drawing task will get executed on the same LVGL main thread. + +`_pxp_evaluate()` will get called after each task is being created and will +analyze if the task is supported by PXP or not. If it is supported, then an +preferred score and the draw unit id will be set to the task. An `score` equal +to `100` is the default CPU score. Smaller score means that PXP is capable of +drawing it faster. + +`_pxp_dispatch()` is the PXP dispatcher callback, it will take a ready to draw +task (having the `DRAW_UNIT_ID_PXP` set) and will pass the task to the PXP draw +unit for processing. + +`_pxp_delete()` will cleanup the PXP draw unit. + +Features supported: +^^^^^^^^^^^^^^^^^^^ + +Several drawing features in LVGL can be offloaded to the PXP engine. The CPU is +available for other operations while the PXP is running. RTOS is required to +block the LVGL drawing thread and switch to another task or suspend the CPU for +power savings. + +Supported draw tasks are available in "src/draw/nxp/pxp/lv_draw_pxp.c": + +.. code:: c + + switch(t->type) { + case LV_DRAW_TASK_TYPE_FILL: + lv_draw_pxp_fill(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_IMAGE: + lv_draw_pxp_img(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_LAYER: + lv_draw_pxp_layer(draw_unit, t->draw_dsc, &t->area); + break; + default: + break; + } + +Additional, the screen rotation can be handled by the PXP: + +.. code::c + + void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height, + int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation, + lv_color_format_t cf); + +- Fill area with color (w/o radius, w/o gradient) + optional opacity. +- Blit source image RGB565/ARGB888/XRGB8888 over destination. + RGB565/RGB888/ARGB888/XRGB8888 + optional opacity. +- Recolor source image RGB565. +- Scale and rotate (90, 180, 270 degree) source image RGB565. +- Blending layers (w/ same supported formats as blitting). +- Rotate screen (90, 180, 270 degree). + +Known limitations: +^^^^^^^^^^^^^^^^^^ + +- PXP can only rotate at 90x angles. +- Rotation is not supported for images unaligned to blocks of 16x16 pixels. PXP + is set to process 16x16 blocks to optimize the system for memory bandwidth and + image processing time. The output engine essentially truncates any output + pixels after the desired number of pixels has been written. When rotating a + source image and the output is not divisible by the block size, the incorrect + pixels could be truncated and the final output image can look shifted. +- Recolor or transformation for images w/ opacity or alpha channel can't be + obtained in a single PXP pipeline configuration. Two or multiple steps would + be required. +- Buffer address must be aligned to 64 bytes: set :c:macro:`LV_DRAW_BUF_ALIGN` + to `64` in "lv_conf.h". + No stride alignment is required: set :c:macro:`LV_DRAW_BUF_STRIDE_ALIGN` to + `1` in "lv_conf.h". Project setup: ^^^^^^^^^^^^^^ -- Add PXP related files to project: +- Add PXP related source files (and corresponding headers if available) to + project: - - src/draw/nxp/pxp/lv_draw_pxp.c[.h]: draw context callbacks - - src/draw/nxp/pxp/lv_draw_pxp_blend.c[.h]: fill and blit (with optional transformation) - - src/draw/nxp/pxp/lv_gpu_nxp_pxp.c[.h]: init, uninit, run/wait PXP device - - src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c[.h]: OS abstraction (FreeRTOS or bare metal) + - "src/draw/nxp/pxp/lv_draw_buf_pxp.c": draw buffer callbacks + - "src/draw/nxp/pxp/lv_draw_pxp_fill.c": fill area + - "src/draw/nxp/pxp/lv_draw_pxp_img.c": blit image (w/ optional recolor or + transformation) + - "src/draw/nxp/pxp/lv_draw_pxp_layer.c": layer blending + - "src/draw/nxp/pxp/lv_draw_pxp.c": draw unit initialization + - "src/draw/nxp/pxp/lv_pxp_cfg.c": init, deinit, run/wait PXP device + - "src/draw/nxp/pxp/lv_pxp_osa.c": OS abstraction (FreeRTOS or bare metal) + - "src/draw/nxp/pxp/lv_pxp_utils.c": function helpers - - optional, required only if :c:macro:`LV_USE_GPU_NXP_PXP_AUTO_INIT` is set to ``1`` +- PXP related code depends on two drivers provided by MCU SDK. These drivers + need to be added to project: -- PXP related code depends on two drivers provided by MCU SDK. These - drivers need to be added to project: + - fsl_pxp.c: PXP driver + - fsl_cache.c: CPU cache handling functions - - fsl_pxp.c[.h]: PXP driver - - fsl_cache.c[.h]: CPU cache handling functions - - -Logging: -^^^^^^^^ - -- By default, :c:macro:`LV_GPU_NXP_PXP_LOG_ERRORS` is enabled so that any PXP error will be seen on SDK debug console -- By default, :c:macro:`LV_GPU_NXP_PXP_LOG_TRACES` is disabled. Enable it for tracing logs (like PXP limitations) - - -Advanced configuration: -^^^^^^^^^^^^^^^^^^^^^^^ +PXP default configuration: +^^^^^^^^^^^^^^^^^^^^^^^^^^ - Implementation depends on multiple OS-specific functions. The struct - :cpp:struct:`lv_nxp_pxp_cfg_t` with callback pointers is used as a parameter - for the :cpp:func:`lv_gpu_nxp_pxp_init` function. Default implementation - for FreeRTOS and bare metal is provided in lv_gpu_nxp_pxp_osa.c - - - :cpp:func:`pxp_interrupt_init`: Initialize PXP interrupt (HW setup, OS setup) - - :cpp:func:`pxp_interrupt_deinit`: Deinitialize PXP interrupt (HW setup, OS setup) - - :cpp:func:`pxp_run`: Start PXP job. Use OS-specific mechanism to block drawing thread. - PXP must finish drawing before leaving this function. - -- Area threshold (size limit) is configurable and used to decide - whether the area will be processed by PXP or not. Areas smaller than - the defined value will be processed by CPU and those bigger than the - threshold will be processed by PXP. The threshold is defined as a - macro in lv_draw_pxp.c - - - :c:macro:`LV_GPU_NXP_PXP_SIZE_LIMIT`: size threshold for fill/blit (with optional transformation) + :cpp:struct:`pxp_cfg_t` with callback pointers is used as a parameter for the + :cpp:func:`lv_pxp_init()` function. Default implementation for FreeRTOS and + bare metal is provided in lv_pxp_osa.c. + - :cpp:func:`pxp_interrupt_init()`: Initialize PXP interrupt (HW setup, + OS setup) + - :cpp:func:`pxp_interrupt_deinit()`: Deinitialize PXP interrupt (HW setup, + OS setup) + - :cpp:func:`pxp_run()`: Start PXP job. Use OS-specific mechanism to block + drawing thread. + - :cpp:func:`pxp_wait()`: Wait for PXP completion. VGLite accelerator ~~~~~~~~~~~~~~~~~~ @@ -163,116 +196,203 @@ CPU is available for other operations while the VGLite is running. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for power savings. -Supported draw callbacks are available in "src/draw/nxp/vglite/lv_draw_vglite.c": - -.. code:: c - - vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf; - vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line; - vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc; - vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect; - vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded; - vglite_draw_ctx->blend = lv_draw_vglite_blend; - vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish; - -.. _features-supported-1: - - -Features supported: -^^^^^^^^^^^^^^^^^^^ - -All operations can be used in conjunction with optional transparency. - -- RGB565 and ARGB8888 color formats -- Area fill with color -- BLIT (BLock Image Transfer) -- Image Rotation (any degree with decimal) -- Image Scale -- Draw rectangle background with optional radius or gradient -- Blit rectangle background image -- Draw rectangle border/outline with optional rounded corners -- Draw arc with optional rounded ending -- Draw line or dashed line with optional rounded ending - -.. _known-limitations-1: - - -Known limitations: -^^^^^^^^^^^^^^^^^^ - -- Source image alignment: The byte alignment requirement for a pixel - depends on the specific pixel format. Both buffer address and buffer - stride must be aligned. As general rule, the alignment is set to 16 - pixels. This makes the buffer address alignment to be 32 bytes for - RGB565 and 64 bytes for ARGB8888. -- For pixel engine (PE) destination, the alignment should be 64 bytes - for all tiled (4x4) buffer layouts. The pixel engine has no - additional alignment requirement for linear buffer layouts - (:c:macro:`VG_LITE_LINEAR`). - -.. _basic-configuration-1: - - Basic configuration: ^^^^^^^^^^^^^^^^^^^^ -- Select NXP VGLite engine in lv_conf.h: Set :c:macro:`LV_USE_GPU_NXP_VG_LITE` to 1 -- :c:macro:`SDK_OS_FREE_RTOS` symbol needs to be defined so that the FreeRTOS implementation will be used - -.. _basic-initialization-1: +- Select NXP VGLite engine in "lv_conf.h": Set :c:macro:`LV_USE_DRAW_VGLITE` to + `1`. :c:macro:`SDK_OS_FREE_RTOS` symbol needs to be defined so that FreeRTOS + driver osal implementation will be enabled. +- Enable VGLite asserts in "lv_conf.h": Set :c:macro: `LV_USE_VGLITE_ASSERT` to + `1`. + VGLite assertions will verify the driver API status code and in any error, it + can stop the program execution in case the c:macro: `LV_ASSERT_HANDLER` is set + to `while(1);` (Halt by default). Else, there will be logged just an error + message via `LV_LOG_ERROR`. Basic initialization: ^^^^^^^^^^^^^^^^^^^^^ -- Initialize VGLite before calling :cpp:func:`lv_init` by specifying the - width/height of tessellation window. Value should be a multiple of - 16; minimum value is 16 pixels, maximum cannot be greater than the - frame width. If less than or equal to 0, then no tessellation buffer - is created, in which case VGLite is initialized only for blitting. +Initialize VGLite GPU before calling :cpp:func:`lv_init()` by specifying the +width/height of tessellation window. The default values for tesselation width +and height, and command buffer size are in the SDK file "vglite_support.h". .. code:: c - #if LV_USE_GPU_NXP_VG_LITE + #if LV_USE_GPU_NXP_VG_LITE #include "vg_lite.h" - #endif + #include "vglite_support.h" + #endif ... - #if LV_USE_GPU_NXP_VG_LITE - VG_LITE_COND_STOP(vg_lite_init(64, 64) != VG_LITE_SUCCESS, "VGLite init failed."); - #endif + #if LV_USE_DRAW_VGLITE + if(vg_lite_init(DEFAULT_VG_LITE_TW_WIDTH, DEFAULT_VG_LITE_TW_HEIGHT) != VG_LITE_SUCCESS) + { + PRINTF("VGLite init error. STOP."); + vg_lite_close(); + while (1) + ; + } -.. _project-setup-1: + if (vg_lite_set_command_buffer_size(VG_LITE_COMMAND_BUFFER_SIZE) != VG_LITE_SUCCESS) + { + PRINTF("VGLite set command buffer. STOP."); + vg_lite_close(); + while (1) + ; + } + #endif -Project setup: -^^^^^^^^^^^^^^ +VGLite draw initialization is done automatically in :cpp:func:`lv_init()` once +the VGLite is enabled, no user code is required: -- Add VGLite related files to project: +.. code:: c - - src/draw/nxp/vglite/lv_draw_vglite.c[.h]: draw context callbacks - - src/draw/nxp/vglite/lv_draw_vglite_blend.c[.h]: fill and blit (with optional transformation) - - src/draw/nxp/vglite/lv_draw_vglite_rect.c[.h]: draw rectangle - - src/draw/nxp/vglite/lv_draw_vglite_arc.c[.h]: draw arc - - src/draw/nxp/vglite/lv_draw_vglite_line.c[.h]: draw line - - src/draw/nxp/vglite/lv_vglite_buf.c[.h]: init/get vglite buffer - - src/draw/nxp/vglite/lv_vglite_utils.c[.h]: function helpers + #if LV_USE_DRAW_VGLITE + lv_draw_vglite_init(); + #endif -.. _logging-1: +During VGLite initialization, a new draw unit `lv_draw_vglite_unit_t` will be +created with the additional callbacks: -Logging: -^^^^^^^^ +.. code:: c -- By default, :c:macro:`LV_GPU_NXP_VG_LITE_LOG_ERRORS` is enabled so that any VGLite error will be seen on SDK debug console -- By default, :c:macro:`LV_GPU_NXP_VG_LITE_LOG_TRACES` is disabled. Enable it - for tracing logs (like blit split workaround or VGLite fallback to CPU due to any error on the driver) + lv_draw_vglite_unit_t * draw_vglite_unit = lv_draw_create_unit(sizeof(lv_draw_vglite_unit_t)); + draw_vglite_unit->base_unit.evaluate_cb = _vglite_evaluate; + draw_vglite_unit->base_unit.dispatch_cb = _vglite_dispatch; + draw_vglite_unit->base_unit.delete_cb = _vglite_delete; -.. _advanced-configuration-1: +and an addition thread `_vglite_render_thread_cb()` will be spawned in order to +handle the supported draw tasks. + +.. code:: c + + #if LV_USE_OS + lv_thread_init(&draw_vglite_unit->thread, LV_THREAD_PRIO_HIGH, _vglite_render_thread_cb, 2 * 1024, draw_vglite_unit); + #endif + +If `LV_USE_OS` is not defined, then no additional draw thread will be created +and the VGLite drawing task will get executed on the same LVGL main thread. + +`_vglite_evaluate()` will get called after each task is being created and will +analyze if the task is supported by VGLite or not. If it is supported, then an +preferred score and the draw unit id will be set to the task. An `score` equal +to `100` is the default CPU score. Smaller score means that VGLite is capable of +drawing it faster. + +`_vglite_dispatch()` is the VGLite dispatcher callback, it will take a ready to +draw task (having the `DRAW_UNIT_ID_VGLITE` set) and will pass the task to the +VGLite draw unit for processing. + +`_vglite_delete()` will cleanup the VGLite draw unit. Advanced configuration: ^^^^^^^^^^^^^^^^^^^^^^^ -- Area threshold (size limit) is configurable and used to decide - whether the area will be processed by VGLite or not. Areas smaller - than the defined value will be processed by CPU and those bigger than - the threshold will be processed by VGLite. The threshold is defined - as a macro in lv_draw_vglite.c +- Enable VGLite blit split in "lv_conf.h": + Set :c:macro: `LV_USE_VGLITE_BLIT_SPLIT` to `1`. + Enabling the blit split workaround will mitigate any quality degradation issue + on screen's dimension > 352 pixels. - - :c:macro:`LV_GPU_NXP_VG_LITE_SIZE_LIMIT`: size threshold for fill/blit (with optional transformation) +.. code:: c + + #define VGLITE_BLIT_SPLIT_THR 352 + +- By default, the blit split threshold is set to 352. Blits with width or height + higher than this value will be done in multiple steps. Value must be multiple + of stride alignment in px. For most color formats, the alignment is 16px + (except the index formats). Transformation will not be supported once with + the blit split. + +- Enable VGLite draw task synchronously in "lv_conf.h": + Set :c:macro: `LV_USE_VGLITE_DRAW_ASYNC` to `1`. + Multiple draw tasks can be queued and flushed them once to the GPU based on + the GPU idle status. If GPU is busy, the task will be queued, and the VGLite + dispatcher will ask for a new available task. If GPU is idle, the queue with + any pending tasks will be flushed to the GPU. The completion status of draw + task will be sent to the main LVGL thread asynchronously. + +Features supported: +^^^^^^^^^^^^^^^^^^^ + +Several drawing features in LVGL can be offloaded to the VGLite engine. The CPU +is available for other operations while the GPU is running. RTOS is required to +block the LVGL drawing thread and switch to another task or suspend the CPU for +power savings. + +Supported draw tasks are available in "src/draw/nxp/pxp/lv_draw_vglite.c": + +.. code:: c + + switch(t->type) { + case LV_DRAW_TASK_TYPE_LABEL: + lv_draw_vglite_label(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_FILL: + lv_draw_vglite_fill(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_BORDER: + lv_draw_vglite_border(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_IMAGE: + lv_draw_vglite_img(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_ARC: + lv_draw_vglite_arc(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_LINE: + lv_draw_vglite_line(draw_unit, t->draw_dsc); + break; + case LV_DRAW_TASK_TYPE_LAYER: + lv_draw_vglite_layer(draw_unit, t->draw_dsc, &t->area); + break; + case LV_DRAW_TASK_TYPE_TRIANGLE: + lv_draw_vglite_triangle(draw_unit, t->draw_dsc); + break; + default: + break; + } + +All the below opration can be done in addition with optional opacity. +- Fill area with color (w/ radius or gradient). +- Blit source image (any format from `_vglite_src_cf_supported()`) over + destination (any format from `_vglite_dest_cf_supported()`). +- Recolor source image. +- Scale and rotate (any decimal degree) source image. +- Blending layers (w/ same supported formats as blitting). +- Draw letters (blit bitmap letters - raster font). +- Draw full borders (LV_BORDER_SIDE_FULL). +- Draw arcs (w/ rounded edges). +- Draw lines (w/ dash or rounded edges). +- Draw triangles with color (w/ gradient). + +Known limitations: +^^^^^^^^^^^^^^^^^^ + +- Source image alignment: The byte alignment requirement for a pixel depends on + the specific pixel format. Both buffer address and buffer stride must be + aligned. As general rule, the alignment is set to 16 pixels. This makes the + buffer address alignment to be 32 bytes for RGB565 and 64 bytes for ARGB8888. +- For pixel engine (PE) destination, the alignment should be 64 bytes for all + tiled (4x4) buffer layouts. The pixel engine has no additional alignment + requirement for linear buffer layouts (:c:macro:`VG_LITE_LINEAR`). + +Project setup: +^^^^^^^^^^^^^^ + +- Add VGLite related source files (and corresponding headers if available) to + project: + + - "src/draw/nxp/vglite/lv_draw_buf_vglite.c": draw buffer callbacks + - "src/draw/nxp/vglite/lv_draw_vglite_arc.c": draw arc + - "src/draw/nxp/vglite/lv_draw_vglite_border.c": draw border + - "src/draw/nxp/vglite/lv_draw_vglite_fill.c": fill area + - "src/draw/nxp/vglite/lv_draw_vglite_img.c": blit image (w/ optional + recolor or transformation) + - "src/draw/nxp/vglite/lv_draw_vglite_label.c": draw label + - "src/draw/nxp/vglite/lv_draw_vglite_layer.c": layer blending + - "src/draw/nxp/vglite/lv_draw_vglite_line.c": draw line + - "src/draw/nxp/vglite/lv_draw_vglite_triangle.c": draw triangle + - "src/draw/nxp/vglite/lv_draw_vglite.c": draw unit initialization + - "src/draw/nxp/vglite/lv_vglite_buf.c": init/get vglite buffer + - "src/draw/nxp/vglite/lv_vglite_matrix.c": set vglite matrix + - "src/draw/nxp/vglite/lv_vglite_path.c": create vglite path data + - "src/draw/nxp/vglite/lv_vglite_utils.c": function helpers diff --git a/lv_conf_template.h b/lv_conf_template.h index f0c835123..31ddf24d0 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -67,6 +67,23 @@ *(Not so important, you can adjust it to modify default sizes and spaces)*/ #define LV_DPI_DEF 130 /*[px/inch]*/ +/*================= + * OPERATING SYSTEM + *=================*/ +/*Select an operating system to use. Possible options: + * - LV_OS_NONE + * - LV_OS_PTHREAD + * - LV_OS_FREERTOS + * - LV_OS_CMSIS_RTOS2 + * - LV_OS_RTTHREAD + * - LV_OS_WINDOWS + * - LV_OS_CUSTOM */ +#define LV_USE_OS LV_OS_NONE + +#if LV_USE_OS == LV_OS_CUSTOM + #define LV_OS_CUSTOM_INCLUDE +#endif + /*======================== * RENDERING CONFIGURATION *========================*/ @@ -122,9 +139,27 @@ /* Use NXP's VG-Lite GPU on iMX RTxxx platforms. */ #define LV_USE_DRAW_VGLITE 0 +#if LV_USE_DRAW_VGLITE + /* Enable blit quality degradation workaround recommended for screen's dimension > 352 pixels. */ + #define LV_USE_VGLITE_BLIT_SPLIT 0 + + #if LV_USE_OS + /* Enable VGLite draw async. Queue multiple tasks and flash them once to the GPU. */ + #define LV_USE_VGLITE_DRAW_ASYNC 1 + #endif + + /* Enable VGLite asserts. */ + #define LV_USE_VGLITE_ASSERT 0 +#endif + /* Use NXP's PXP on iMX RTxxx platforms. */ #define LV_USE_DRAW_PXP 0 +#if LV_USE_DRAW_PXP + /* Enable PXP asserts. */ + #define LV_USE_PXP_ASSERT 0 +#endif + /* Use Renesas Dave2D on RA platforms. */ #define LV_USE_DRAW_DAVE2D 0 @@ -143,23 +178,6 @@ #endif -/*================= - * OPERATING SYSTEM - *=================*/ -/*Select an operating system to use. Possible options: - * - LV_OS_NONE - * - LV_OS_PTHREAD - * - LV_OS_FREERTOS - * - LV_OS_CMSIS_RTOS2 - * - LV_OS_RTTHREAD - * - LV_OS_WINDOWS - * - LV_OS_CUSTOM */ -#define LV_USE_OS LV_OS_NONE - -#if LV_USE_OS == LV_OS_CUSTOM - #define LV_OS_CUSTOM_INCLUDE -#endif - /*======================= * FEATURE CONFIGURATION *=======================*/ diff --git a/src/draw/nxp/pxp/lv_draw_buf_pxp.c b/src/draw/nxp/pxp/lv_draw_buf_pxp.c index 199afa45f..7ba894e12 100644 --- a/src/draw/nxp/pxp/lv_draw_buf_pxp.c +++ b/src/draw/nxp/pxp/lv_draw_buf_pxp.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -33,7 +33,7 @@ * STATIC PROTOTYPES **********************/ -static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area); +static void _invalidate_cache(void * buf, uint32_t stride, lv_color_format_t cf, const lv_area_t * area); /********************** * STATIC VARIABLES @@ -58,44 +58,49 @@ void lv_draw_buf_pxp_init_handlers(void) * STATIC FUNCTIONS **********************/ -static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area) +static void _invalidate_cache(void * buf, uint32_t stride, lv_color_format_t cf, const lv_area_t * area) { - LV_UNUSED(draw_buf); - LV_UNUSED(area); + if(area->y1 == 0) { + uint16_t size = stride * lv_area_get_height(area); - DEMO_CleanInvalidateCache(); + /* Invalidate full buffer. */ + DEMO_CleanInvalidateCacheByAddr((void *)buf, size); + return; + } + + const uint8_t * buf_u8 = buf; + /* ARM require a 32 byte aligned address. */ + uint8_t align_bytes = 32; + uint8_t bits_per_pixel = lv_color_format_get_bpp(cf); + + uint16_t align_pixels = align_bytes * 8 / bits_per_pixel; + uint16_t offset_x = 0; + + if(area->x1 >= (int32_t)(area->x1 % align_pixels)) { + uint16_t shift_x = area->x1 - (area->x1 % align_pixels); + + offset_x = area->x1 - shift_x; + buf_u8 += (shift_x * bits_per_pixel) / 8; + } + + if(area->y1) { + uint16_t shift_y = area->y1; + + buf_u8 += shift_y * stride; + } + + /* Area to clear can start from a different offset in buffer. + * Invalidate the area line by line. + */ + uint16_t line_pixels = offset_x + lv_area_get_width(area); + uint16_t line_size = (line_pixels * bits_per_pixel) / 8; + uint16_t area_height = lv_area_get_height(area); + + for(uint16_t y = 0; y < area_height; y++) { + const void * line_addr = buf_u8 + y * stride; + + DEMO_CleanInvalidateCacheByAddr((void *)line_addr, line_size); + } } -#if 0 -/** - * @todo - * LVGL needs to use hardware acceleration for buf_copy and do not affect GPU rendering. - */ - -void _pxp_buf_copy(void * dest_buf, uint32_t dest_stride, const lv_area_t * dest_area, - void * src_buf, uint32_t src_stride, const lv_area_t * src_area, - lv_color_format_t cf) -{ - lv_pxp_reset(); - - const pxp_pic_copy_config_t picCopyConfig = { - .srcPicBaseAddr = (uint32_t)src_buf, - .srcPitchBytes = src_stride, - .srcOffsetX = src_area->x1, - .srcOffsetY = src_area->y1, - .destPicBaseAddr = (uint32_t)dest_buf, - .destPitchBytes = dest_stride, - .destOffsetX = dest_area->x1, - .destOffsetY = dest_area->y1, - .width = lv_area_get_width(src_area), - .height = lv_area_get_height(src_area), - .pixelFormat = pxp_get_as_px_format(cf) - }; - - PXP_StartPictureCopy(PXP_ID, &picCopyConfig); - - lv_pxp_run(); -} -#endif - #endif /*LV_USE_DRAW_PXP*/ diff --git a/src/draw/nxp/pxp/lv_draw_pxp.c b/src/draw/nxp/pxp/lv_draw_pxp.c index 6a6eb1f0d..55df3dc84 100644 --- a/src/draw/nxp/pxp/lv_draw_pxp.c +++ b/src/draw/nxp/pxp/lv_draw_pxp.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2022, 2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -17,7 +17,11 @@ #if LV_USE_DRAW_PXP #include "lv_pxp_cfg.h" -#include "../../../display/lv_display_private.h" +#include "lv_pxp_utils.h" + +#if LV_USE_PARALLEL_DRAW_DEBUG + #include "../../../core/lv_global.h" +#endif /********************* * DEFINES @@ -33,6 +37,12 @@ * STATIC PROTOTYPES **********************/ +/* + * Evaluate a task and set the score and preferred PXP unit. + * Return 1 if task is preferred, 0 otherwise (task is not supported). + */ +static int32_t _pxp_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task); + /* * Dispatch a task to the PXP unit. * Return 1 if task was dispatched, 0 otherwise (task not supported). @@ -40,10 +50,9 @@ static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer); /* - * Evaluate a task and set the score and preferred PXP unit. - * Return 1 if task is preferred, 0 otherwise (task is not supported). + * Delete the PXP draw unit. */ -static int32_t _pxp_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task); +static int32_t _pxp_delete(lv_draw_unit_t * draw_unit); #if LV_USE_OS static void _pxp_render_thread_cb(void * ptr); @@ -59,6 +68,10 @@ static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u); * STATIC VARIABLES **********************/ +#if LV_USE_PARALLEL_DRAW_DEBUG + #define _draw_info LV_GLOBAL_DEFAULT()->draw_info +#endif + /********************** * MACROS **********************/ @@ -72,13 +85,14 @@ void lv_draw_pxp_init(void) lv_draw_buf_pxp_init_handlers(); lv_draw_pxp_unit_t * draw_pxp_unit = lv_draw_create_unit(sizeof(lv_draw_pxp_unit_t)); - draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch; draw_pxp_unit->base_unit.evaluate_cb = _pxp_evaluate; + draw_pxp_unit->base_unit.dispatch_cb = _pxp_dispatch; + draw_pxp_unit->base_unit.delete_cb = _pxp_delete; lv_pxp_init(); #if LV_USE_OS - lv_thread_init(&draw_pxp_unit->thread, LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 8 * 1024, draw_pxp_unit); + lv_thread_init(&draw_pxp_unit->thread, LV_THREAD_PRIO_HIGH, _pxp_render_thread_cb, 2 * 1024, draw_pxp_unit); #endif } @@ -87,14 +101,96 @@ void lv_draw_pxp_deinit(void) lv_pxp_deinit(); } +void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height, + int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation, + lv_color_format_t cf) +{ + lv_pxp_reset(); + + /* convert rotation angle */ + pxp_rotate_degree_t pxp_rotation; + switch(rotation) { + case LV_DISPLAY_ROTATION_0: + pxp_rotation = kPXP_Rotate0; + break; + case LV_DISPLAY_ROTATION_90: + pxp_rotation = kPXP_Rotate90; + break; + case LV_DISPLAY_ROTATION_180: + pxp_rotation = kPXP_Rotate180; + break; + case LV_DISPLAY_ROTATION_270: + pxp_rotation = kPXP_Rotate270; + break; + default: + pxp_rotation = kPXP_Rotate0; + break; + } + PXP_SetRotateConfig(PXP_ID, kPXP_RotateOutputBuffer, pxp_rotation, kPXP_FlipDisable); + + /*Simple blit, no effect - Disable PS buffer*/ + PXP_SetProcessSurfacePosition(PXP_ID, 0xFFFFU, 0xFFFFU, 0U, 0U); + + /*AS buffer - source image*/ + pxp_as_buffer_config_t asBufferConfig = { + .pixelFormat = pxp_get_as_px_format(cf), + .bufferAddr = (uint32_t)src_buf, + .pitchBytes = src_stride + }; + PXP_SetAlphaSurfaceBufferConfig(PXP_ID, &asBufferConfig); + PXP_SetAlphaSurfacePosition(PXP_ID, 0U, 0U, src_width - 1U, src_height - 1U); + PXP_EnableAlphaSurfaceOverlayColorKey(PXP_ID, false); + + /*Output buffer.*/ + pxp_output_buffer_config_t outputBufferConfig = { + .pixelFormat = pxp_get_out_px_format(cf), + .interlacedMode = kPXP_OutputProgressive, + .buffer0Addr = (uint32_t)dest_buf, + .buffer1Addr = (uint32_t)0U, + .pitchBytes = dest_stride, + .width = src_width, + .height = src_height + }; + PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig); + + lv_pxp_run(); +} + /********************** * STATIC FUNCTIONS **********************/ -static inline bool _pxp_cf_supported(lv_color_format_t cf) +static inline bool _pxp_src_cf_supported(lv_color_format_t cf) { - bool is_cf_supported = (cf == LV_COLOR_FORMAT_RGB565 || cf == LV_COLOR_FORMAT_RGB888 || - cf == LV_COLOR_FORMAT_ARGB8888 || cf == LV_COLOR_FORMAT_XRGB8888); + bool is_cf_supported = false; + + switch(cf) { + case LV_COLOR_FORMAT_RGB565: + case LV_COLOR_FORMAT_ARGB8888: + case LV_COLOR_FORMAT_XRGB8888: + is_cf_supported = true; + break; + default: + break; + } + + return is_cf_supported; +} + +static inline bool _pxp_dest_cf_supported(lv_color_format_t cf) +{ + bool is_cf_supported = false; + + switch(cf) { + case LV_COLOR_FORMAT_RGB565: + case LV_COLOR_FORMAT_RGB888: + case LV_COLOR_FORMAT_ARGB8888: + case LV_COLOR_FORMAT_XRGB8888: + is_cf_supported = true; + break; + default: + break; + } return is_cf_supported; } @@ -103,8 +199,9 @@ static bool _pxp_draw_img_supported(const lv_draw_image_dsc_t * draw_dsc) { const lv_image_dsc_t * img_dsc = draw_dsc->src; - bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP); - bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->zoom != LV_SCALE_NONE); + bool has_recolor = (draw_dsc->recolor_opa > LV_OPA_MIN); + bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE || + draw_dsc->scale_y != LV_SCALE_NONE); /* Recolor and transformation are not supported at the same time. */ if(has_recolor && has_transform) @@ -146,6 +243,11 @@ static int32_t _pxp_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) { LV_UNUSED(u); + const lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc; + + if(!_pxp_dest_cf_supported(draw_dsc_base->layer->color_format)) + return 0; + switch(t->type) { case LV_DRAW_TASK_TYPE_FILL: { const lv_draw_fill_dsc_t * draw_dsc = (lv_draw_fill_dsc_t *) t->draw_dsc; @@ -161,29 +263,11 @@ static int32_t _pxp_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) return 1; } - case LV_DRAW_TASK_TYPE_BG_IMG: { - const lv_draw_bg_image_dsc_t * draw_dsc = (lv_draw_bg_image_dsc_t *) t->draw_dsc; - lv_image_src_t src_type = lv_image_src_get_type(draw_dsc->src); - - if(src_type == LV_IMAGE_SRC_SYMBOL) - return 0; - - if(!_pxp_cf_supported(draw_dsc->img_header.cf)) - return 0; - - if(t->preference_score > 70) { - t->preference_score = 70; - t->preferred_draw_unit_id = DRAW_UNIT_ID_PXP; - } - return 1; - } - case LV_DRAW_TASK_TYPE_LAYER: { const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc; lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src; - lv_draw_buf_t * draw_buf = &layer_to_draw->draw_buf; - if(!_pxp_cf_supported(draw_buf->color_format)) + if(!_pxp_src_cf_supported(layer_to_draw->color_format)) return 0; if(!_pxp_draw_img_supported(draw_dsc)) @@ -200,7 +284,8 @@ static int32_t _pxp_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc; const lv_image_dsc_t * img_dsc = draw_dsc->src; - if(!_pxp_cf_supported(img_dsc->header.cf)) + if((!_pxp_src_cf_supported(img_dsc->header.cf)) || + (!pxp_buf_aligned(img_dsc->data, img_dsc->header.stride))) return 0; if(!_pxp_draw_img_supported(draw_dsc)) @@ -227,16 +312,11 @@ static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) if(draw_pxp_unit->task_act) return 0; - /* Return if target buffer format is not supported. */ - if(!_pxp_cf_supported(layer->draw_buf.color_format)) - return 0; - /* Try to get an ready to draw. */ lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_PXP); - /* Return 0 is no selection, some tasks can be supported only by other units. */ if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_PXP) - return 0; + return -1; void * buf = lv_draw_layer_alloc_buf(layer); if(buf == NULL) @@ -249,7 +329,8 @@ static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) #if LV_USE_OS /* Let the render thread work. */ - lv_thread_sync_signal(&draw_pxp_unit->sync); + if(draw_pxp_unit->inited) + lv_thread_sync_signal(&draw_pxp_unit->sync); #else _pxp_execute_drawing(draw_pxp_unit); @@ -263,22 +344,46 @@ static int32_t _pxp_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) return 1; } +static int32_t _pxp_delete(lv_draw_unit_t * draw_unit) +{ +#if LV_USE_OS + lv_draw_pxp_unit_t * draw_pxp_unit = (lv_draw_pxp_unit_t *) draw_unit; + + LV_LOG_INFO("Cancel PXP draw thread."); + draw_pxp_unit->exit_status = true; + + if(draw_pxp_unit->inited) + lv_thread_sync_signal(&draw_pxp_unit->sync); + + lv_result_t res = lv_thread_delete(&draw_pxp_unit->thread); + + return res; +#else + LV_UNUSED(draw_unit); + + return 0; +#endif +} + static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u) { lv_draw_task_t * t = u->task_act; lv_draw_unit_t * draw_unit = (lv_draw_unit_t *)u; - - /* Invalidate cache */ lv_layer_t * layer = draw_unit->target_layer; - lv_draw_buf_invalidate_cache(&layer->draw_buf, (const char *)&t->area); + + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, &t->area, draw_unit->clip_area)) + return; /*Fully clipped, nothing to do*/ + + /* Make area relative to the buffer */ + lv_area_move(&draw_area, -layer->buf_area.x1, -layer->buf_area.y1); + /* Invalidate only the drawing area */ + lv_draw_buf_invalidate_cache(layer->buf, layer->buf_stride, layer->color_format, &draw_area); switch(t->type) { case LV_DRAW_TASK_TYPE_FILL: lv_draw_pxp_fill(draw_unit, t->draw_dsc, &t->area); break; - case LV_DRAW_TASK_TYPE_BG_IMG: - lv_draw_pxp_bg_img(draw_unit, t->draw_dsc, &t->area); - break; case LV_DRAW_TASK_TYPE_IMAGE: lv_draw_pxp_img(draw_unit, t->draw_dsc, &t->area); break; @@ -288,6 +393,51 @@ static void _pxp_execute_drawing(lv_draw_pxp_unit_t * u) default: break; } + +#if LV_USE_PARALLEL_DRAW_DEBUG + /*Layers manage it for themselves*/ + if(t->type != LV_DRAW_TASK_TYPE_LAYER) { + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, &t->area, u->base_unit.clip_area)) + return; + + int32_t idx = 0; + lv_draw_unit_t * draw_unit_tmp = _draw_info.unit_head; + while(draw_unit_tmp != (lv_draw_unit_t *)u) { + draw_unit_tmp = draw_unit_tmp->next; + idx++; + } + lv_draw_rect_dsc_t rect_dsc; + lv_draw_rect_dsc_init(&rect_dsc); + rect_dsc.bg_color = lv_palette_main(idx % _LV_PALETTE_LAST); + rect_dsc.border_color = rect_dsc.bg_color; + rect_dsc.bg_opa = LV_OPA_10; + rect_dsc.border_opa = LV_OPA_80; + rect_dsc.border_width = 1; + lv_draw_sw_fill((lv_draw_unit_t *)u, &rect_dsc, &draw_area); + + lv_point_t txt_size; + lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); + + lv_area_t txt_area; + txt_area.x1 = draw_area.x1; + txt_area.y1 = draw_area.y1; + txt_area.x2 = draw_area.x1 + txt_size.x - 1; + txt_area.y2 = draw_area.y1 + txt_size.y - 1; + + lv_draw_rect_dsc_init(&rect_dsc); + rect_dsc.bg_color = lv_color_white(); + lv_draw_sw_fill((lv_draw_unit_t *)u, &rect_dsc, &txt_area); + + char buf[8]; + lv_snprintf(buf, sizeof(buf), "%d", idx); + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + label_dsc.color = lv_color_black(); + label_dsc.text = buf; + lv_draw_sw_label((lv_draw_unit_t *)u, &label_dsc, &txt_area); + } +#endif } #if LV_USE_OS @@ -296,25 +446,37 @@ static void _pxp_render_thread_cb(void * ptr) lv_draw_pxp_unit_t * u = ptr; lv_thread_sync_init(&u->sync); + u->inited = true; while(1) { - /* - * Wait for sync if no task received or _draw_task_buf is empty. - * The thread will have to run as much as there are pending tasks. - */ + /* Wait for sync if there is no task set. */ while(u->task_act == NULL) { + if(u->exit_status) + break; + lv_thread_sync_wait(&u->sync); } + if(u->exit_status) { + LV_LOG_INFO("Ready to exit PXP draw thread."); + break; + } + _pxp_execute_drawing(u); - /* Cleanup. */ + /* Signal the ready state to dispatcher. */ u->task_act->state = LV_DRAW_TASK_STATE_READY; + + /* Cleanup. */ u->task_act = NULL; /* The draw unit is free now. Request a new dispatching as it can get a new task. */ lv_draw_dispatch_request(); } + + u->inited = false; + lv_thread_sync_delete(&u->sync); + LV_LOG_INFO("Exit PXP draw thread."); } #endif diff --git a/src/draw/nxp/pxp/lv_draw_pxp.h b/src/draw/nxp/pxp/lv_draw_pxp.h index 2741fa2a1..d5e98d791 100644 --- a/src/draw/nxp/pxp/lv_draw_pxp.h +++ b/src/draw/nxp/pxp/lv_draw_pxp.h @@ -4,7 +4,7 @@ */ /** - * Copyright 2022, 2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -33,16 +33,7 @@ extern "C" { * TYPEDEFS **********************/ -typedef lv_layer_t lv_pxp_layer_t; - -typedef struct { - lv_draw_unit_t base_unit; - lv_draw_task_t * task_act; -#if LV_USE_OS - lv_thread_sync_t sync; - lv_thread_t thread; -#endif -} lv_draw_pxp_unit_t; +typedef lv_draw_sw_unit_t lv_draw_pxp_unit_t; /********************** * GLOBAL PROTOTYPES @@ -54,8 +45,9 @@ void lv_draw_pxp_init(void); void lv_draw_pxp_deinit(void); -void lv_draw_pxp_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc, - const lv_area_t * coords); +void lv_draw_pxp_rotate(const void * src_buf, void * dest_buf, int32_t src_width, int32_t src_height, + int32_t src_stride, int32_t dest_stride, lv_display_rotation_t rotation, + lv_color_format_t cf); void lv_draw_pxp_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc, const lv_area_t * coords); diff --git a/src/draw/nxp/pxp/lv_draw_pxp_bg_img.c b/src/draw/nxp/pxp/lv_draw_pxp_bg_img.c deleted file mode 100644 index 9dada1ef2..000000000 --- a/src/draw/nxp/pxp/lv_draw_pxp_bg_img.c +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file lv_draw_pxp_bg_img.c - * - */ - -/** - * Copyright 2023 NXP - * - * SPDX-License-Identifier: MIT - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_draw_pxp.h" - -#if LV_USE_DRAW_PXP - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_draw_pxp_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc, - const lv_area_t * coords) -{ - if(dsc->src == NULL) return; - if(dsc->opa <= LV_OPA_MIN) return; - - lv_area_t clip_area; - if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) { - return; - } - - const lv_area_t * clip_area_ori = draw_unit->clip_area; - draw_unit->clip_area = &clip_area; - - lv_draw_image_dsc_t img_dsc; - lv_draw_image_dsc_init(&img_dsc); - img_dsc.recolor = dsc->recolor; - img_dsc.recolor_opa = dsc->recolor_opa; - img_dsc.opa = dsc->opa; - img_dsc.src = dsc->src; - - /*Center align*/ - if(dsc->tiled == false) { - lv_area_t area; - area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - dsc->img_header.w / 2; - area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - dsc->img_header.h / 2; - area.x2 = area.x1 + dsc->img_header.w - 1; - area.y2 = area.y1 + dsc->img_header.h - 1; - - lv_draw_pxp_img(draw_unit, &img_dsc, &area); - } - else { - lv_area_t area; - area.y1 = coords->y1; - area.y2 = area.y1 + dsc->img_header.h - 1; - - for(; area.y1 <= coords->y2; area.y1 += dsc->img_header.h, area.y2 += dsc->img_header.h) { - - area.x1 = coords->x1; - area.x2 = area.x1 + dsc->img_header.w - 1; - for(; area.x1 <= coords->x2; area.x1 += dsc->img_header.w, area.x2 += dsc->img_header.w) { - lv_draw_pxp_img(draw_unit, &img_dsc, &area); - } - } - } - - draw_unit->clip_area = clip_area_ori; -} - -#endif /*LV_USE_DRAW_PXP*/ diff --git a/src/draw/nxp/pxp/lv_draw_pxp_fill.c b/src/draw/nxp/pxp/lv_draw_pxp_fill.c index 44fc1601a..9d61c4005 100644 --- a/src/draw/nxp/pxp/lv_draw_pxp_fill.c +++ b/src/draw/nxp/pxp/lv_draw_pxp_fill.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2020-2023 NXP + * Copyright 2020-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -56,21 +56,17 @@ void lv_draw_pxp_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * dsc lv_area_t rel_coords; lv_area_copy(&rel_coords, coords); - lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t rel_clip_area; lv_area_copy(&rel_clip_area, draw_unit->clip_area); - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t blend_area; if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area)) return; /*Fully clipped, nothing to do*/ - uint8_t * dest_buf = layer->draw_buf.buf; - int32_t dest_stride = lv_draw_buf_get_stride(&layer->draw_buf); - lv_color_format_t dest_cf = layer->draw_buf.color_format; - - _pxp_fill(dest_buf, &blend_area, dest_stride, dest_cf, dsc); + _pxp_fill(layer->buf, &blend_area, layer->buf_stride, layer->color_format, dsc); } /********************** diff --git a/src/draw/nxp/pxp/lv_draw_pxp_img.c b/src/draw/nxp/pxp/lv_draw_pxp_img.c index 451aa0ad5..962fdd684 100644 --- a/src/draw/nxp/pxp/lv_draw_pxp_img.c +++ b/src/draw/nxp/pxp/lv_draw_pxp_img.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2020-2023 NXP + * Copyright 2020-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -71,14 +71,14 @@ void lv_draw_pxp_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc lv_area_t rel_coords; lv_area_copy(&rel_coords, coords); - lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_move(&rel_coords, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t rel_clip_area; lv_area_copy(&rel_clip_area, draw_unit->clip_area); - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_move(&rel_clip_area, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t blend_area; - bool has_transform = dsc->rotation != 0 || dsc->zoom != LV_SCALE_NONE; + bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE); if(has_transform) lv_area_copy(&blend_area, &rel_coords); else if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area)) @@ -87,17 +87,17 @@ void lv_draw_pxp_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * dsc const uint8_t * src_buf = img_dsc->data; lv_area_t src_area; - src_area.x1 = blend_area.x1 - (coords->x1 - layer->draw_buf_ofs.x); - src_area.y1 = blend_area.y1 - (coords->y1 - layer->draw_buf_ofs.y); + src_area.x1 = blend_area.x1 - (coords->x1 - layer->buf_area.x1); + src_area.y1 = blend_area.y1 - (coords->y1 - layer->buf_area.y1); src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1; src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1; int32_t src_stride = img_dsc->header.stride; lv_color_format_t src_cf = img_dsc->header.cf; - uint8_t * dest_buf = layer->draw_buf.buf; - int32_t dest_stride = lv_draw_buf_get_stride(&layer->draw_buf); - lv_color_format_t dest_cf = layer->draw_buf.color_format; - bool has_recolor = (dsc->recolor_opa != LV_OPA_TRANSP); + uint8_t * dest_buf = layer->buf; + int32_t dest_stride = layer->buf_stride; + lv_color_format_t dest_cf = layer->color_format; + bool has_recolor = (dsc->recolor_opa > LV_OPA_MIN); if(has_recolor && !has_transform) _pxp_blit_recolor(dest_buf, &blend_area, dest_stride, dest_cf, @@ -194,10 +194,11 @@ static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, int32_t piv_offset_x = 0; int32_t piv_offset_y = 0; - int32_t trim_size = 0; + int32_t trim_x = 0; + int32_t trim_y = 0; bool has_rotation = (dsc->rotation != 0); - bool has_scale = (dsc->zoom != LV_SCALE_NONE); + bool has_scale = (dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE); uint8_t src_px_size = lv_color_format_get_size(src_cf); uint8_t dest_px_size = lv_color_format_get_size(dest_cf); @@ -237,21 +238,21 @@ static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, } if(has_scale) { - float scale_factor_fp = (float)dsc->zoom / LV_SCALE_NONE; - int32_t scale_factor_int = (int32_t)scale_factor_fp; + float fp_scale_x = (float)dsc->scale_x / LV_SCALE_NONE; + float fp_scale_y = (float)dsc->scale_y / LV_SCALE_NONE; + int32_t int_scale_x = (int32_t)fp_scale_x; + int32_t int_scale_y = (int32_t)fp_scale_y; /*Any scale_factor in (k, k + 1] will result in a trim equal to k*/ - if(scale_factor_fp == scale_factor_int) - trim_size = scale_factor_int - 1; - else - trim_size = scale_factor_int; + trim_x = (fp_scale_x == int_scale_x) ? int_scale_x - 1 : int_scale_x; + trim_y = (fp_scale_y == int_scale_y) ? int_scale_y - 1 : int_scale_y; - dest_w = src_w * scale_factor_fp + trim_size; - dest_h = src_h * scale_factor_fp + trim_size; + dest_w = src_w * fp_scale_x + trim_x; + dest_h = src_h * fp_scale_y + trim_y; /*Final pivot offset = scale_factor * rotation_pivot_offset + scaling_pivot_offset*/ - piv_offset_x = floor(scale_factor_fp * piv_offset_x) - floor((scale_factor_fp - 1) * pivot.x); - piv_offset_y = floor(scale_factor_fp * piv_offset_y) - floor((scale_factor_fp - 1) * pivot.y); + piv_offset_x = floor(fp_scale_x * piv_offset_x) - floor((fp_scale_x - 1) * pivot.x); + piv_offset_y = floor(fp_scale_y * piv_offset_y) - floor((fp_scale_y - 1) * pivot.y); } /*PS buffer - source image*/ @@ -264,7 +265,7 @@ static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, .pitchBytes = src_stride }; PXP_SetProcessSurfaceBufferConfig(PXP_ID, &psBufferConfig); - PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, dest_w - trim_size - 1U, dest_h - trim_size - 1U); + PXP_SetProcessSurfacePosition(PXP_ID, 0U, 0U, dest_w - trim_x - 1U, dest_h - trim_y - 1U); if(has_scale) PXP_SetProcessSurfaceScaler(PXP_ID, src_w, src_h, dest_w, dest_h); @@ -279,8 +280,8 @@ static void _pxp_blit_transform(uint8_t * dest_buf, const lv_area_t * dest_area, .buffer0Addr = (uint32_t)(dest_buf + dest_stride * (dest_area->y1 + piv_offset_y) + dest_px_size * (dest_area->x1 + piv_offset_x)), .buffer1Addr = (uint32_t)0U, .pitchBytes = dest_stride, - .width = dest_w - trim_size, - .height = dest_h - trim_size + .width = dest_w - trim_x, + .height = dest_h - trim_y }; PXP_SetOutputBufferConfig(PXP_ID, &outputBufferConfig); diff --git a/src/draw/nxp/pxp/lv_draw_pxp_layer.c b/src/draw/nxp/pxp/lv_draw_pxp_layer.c index f3e6d80d0..385e97c46 100644 --- a/src/draw/nxp/pxp/lv_draw_pxp_layer.c +++ b/src/draw/nxp/pxp/lv_draw_pxp_layer.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -18,6 +18,9 @@ #if LV_USE_DRAW_PXP #include "../../../stdlib/lv_string.h" +#if LV_USE_PARALLEL_DRAW_DEBUG + #include "../../../core/lv_global.h" +#endif /********************* * DEFINES @@ -35,6 +38,10 @@ * STATIC VARIABLES **********************/ +#if LV_USE_PARALLEL_DRAW_DEBUG + #define _draw_info LV_GLOBAL_DEFAULT()->draw_info +#endif + /********************** * MACROS **********************/ @@ -50,20 +57,109 @@ void lv_draw_pxp_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * d /*It can happen that nothing was draw on a layer and therefore its buffer is not allocated. *In this case just return. */ - if(layer_to_draw->draw_buf.buf == NULL) + if(layer_to_draw->buf == NULL) return; - lv_image_dsc_t img_dsc = { 0 }; - img_dsc.header.w = layer_to_draw->draw_buf.width; - img_dsc.header.h = layer_to_draw->draw_buf.height; - img_dsc.header.cf = layer_to_draw->draw_buf.color_format; - img_dsc.data = lv_draw_buf_get_buf(&layer_to_draw->draw_buf); + uint32_t width = lv_area_get_width(&layer_to_draw->buf_area); + uint32_t height = lv_area_get_height(&layer_to_draw->buf_area); + const lv_area_t area = { + .x1 = 0, + .y1 = 0, + .x2 = width - 1, + .y2 = height - 1 + }; + lv_draw_buf_invalidate_cache(layer_to_draw->buf, layer_to_draw->buf_stride, layer_to_draw->color_format, &area); + + lv_image_dsc_t img_dsc = {0}; + img_dsc.header.w = width; + img_dsc.header.h = height; + img_dsc.header.cf = layer_to_draw->color_format; + img_dsc.header.stride = layer_to_draw->buf_stride; + img_dsc.data = layer_to_draw->buf; lv_draw_image_dsc_t new_draw_dsc; lv_memcpy(&new_draw_dsc, draw_dsc, sizeof(lv_draw_image_dsc_t)); new_draw_dsc.src = &img_dsc; lv_draw_pxp_img(draw_unit, &new_draw_dsc, coords); + +#if LV_USE_LAYER_DEBUG || LV_USE_PARALLEL_DRAW_DEBUG + lv_area_t area_rot; + lv_area_copy(&area_rot, coords); + if(draw_dsc->rotation || draw_dsc->scale_x != LV_SCALE_NONE || draw_dsc->scale_y != LV_SCALE_NONE) { + int32_t w = lv_area_get_width(coords); + int32_t h = lv_area_get_height(coords); + + _lv_image_buf_get_transformed_area(&area_rot, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y, + &draw_dsc->pivot); + + area_rot.x1 += coords->x1; + area_rot.y1 += coords->y1; + area_rot.x2 += coords->x1; + area_rot.y2 += coords->y1; + } + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, &area_rot, draw_unit->clip_area)) return; +#endif + +#if LV_USE_LAYER_DEBUG + lv_draw_fill_dsc_t fill_dsc; + lv_draw_fill_dsc_init(&fill_dsc); + fill_dsc.color = lv_color_hex(layer_to_draw->color_format == LV_COLOR_FORMAT_ARGB8888 ? 0xff0000 : 0x00ff00); + fill_dsc.opa = LV_OPA_20; + lv_draw_sw_fill(draw_unit, &fill_dsc, &area_rot); + + lv_draw_border_dsc_t border_dsc; + lv_draw_border_dsc_init(&border_dsc); + border_dsc.color = fill_dsc.color; + border_dsc.opa = LV_OPA_60; + border_dsc.width = 2; + lv_draw_sw_border(draw_unit, &border_dsc, &area_rot); + +#endif + +#if LV_USE_PARALLEL_DRAW_DEBUG + uint32_t idx = 0; + lv_draw_unit_t * draw_unit_tmp = _draw_info.unit_head; + while(draw_unit_tmp != draw_unit) { + draw_unit_tmp = draw_unit_tmp->next; + idx++; + } + + lv_draw_fill_dsc_t fill_dsc; + lv_draw_rect_dsc_init(&fill_dsc); + fill_dsc.color = lv_palette_main(idx % _LV_PALETTE_LAST); + fill_dsc.opa = LV_OPA_10; + lv_draw_sw_fill(draw_unit, &fill_dsc, &area_rot); + + lv_draw_border_dsc_t border_dsc; + lv_draw_border_dsc_init(&border_dsc); + border_dsc.color = lv_palette_main(idx % _LV_PALETTE_LAST); + border_dsc.opa = LV_OPA_100; + border_dsc.width = 2; + lv_draw_sw_border(draw_unit, &border_dsc, &area_rot); + + lv_point_t txt_size; + lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); + + lv_area_t txt_area; + txt_area.x1 = draw_area.x1; + txt_area.x2 = draw_area.x1 + txt_size.x - 1; + txt_area.y2 = draw_area.y2; + txt_area.y1 = draw_area.y2 - txt_size.y + 1; + + lv_draw_fill_dsc_init(&fill_dsc); + fill_dsc.color = lv_color_black(); + lv_draw_sw_fill(draw_unit, &fill_dsc, &txt_area); + + char buf[8]; + lv_snprintf(buf, sizeof(buf), "%d", idx); + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + label_dsc.color = lv_color_white(); + label_dsc.text = buf; + lv_draw_sw_label(draw_unit, &label_dsc, &txt_area); +#endif } #endif /*LV_USE_DRAW_PXP*/ diff --git a/src/draw/nxp/pxp/lv_pxp_cfg.c b/src/draw/nxp/pxp/lv_pxp_cfg.c index 34dc71443..f1d796293 100644 --- a/src/draw/nxp/pxp/lv_pxp_cfg.c +++ b/src/draw/nxp/pxp/lv_pxp_cfg.c @@ -48,10 +48,6 @@ void lv_pxp_init(void) { _pxp_cfg = pxp_get_default_cfg(); - if(!_pxp_cfg || !_pxp_cfg->pxp_interrupt_deinit || !_pxp_cfg->pxp_interrupt_init || - !_pxp_cfg->pxp_run || !_pxp_cfg->pxp_wait) - LV_LOG_ERROR("PXP configuration error."); - PXP_Init(PXP_ID); PXP_EnableCsc1(PXP_ID, false); /*Disable CSC1, it is enabled by default.*/ diff --git a/src/draw/nxp/pxp/lv_pxp_osa.c b/src/draw/nxp/pxp/lv_pxp_osa.c index 770e99c1f..539cefe50 100644 --- a/src/draw/nxp/pxp/lv_pxp_osa.c +++ b/src/draw/nxp/pxp/lv_pxp_osa.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2020, 2022, 2023 NXP + * Copyright 2020, 2022-2023 NXP * * SPDX-License-Identifier: MIT */ @@ -16,6 +16,7 @@ #include "lv_pxp_osa.h" #if LV_USE_DRAW_PXP +#include "lv_pxp_utils.h" #include "../../../misc/lv_log.h" #include "fsl_pxp.h" @@ -115,10 +116,7 @@ static void _pxp_interrupt_init(void) { #if defined(SDK_OS_FREE_RTOS) xPXPIdleSemaphore = xSemaphoreCreateBinary(); - if(xPXPIdleSemaphore == NULL) { - LV_LOG_ERROR("xSemaphoreCreateBinary failed!"); - return; - } + PXP_ASSERT_MSG(xPXPIdleSemaphore, "xSemaphoreCreateBinary failed!"); NVIC_SetPriority(PXP_IRQ_ID, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1); #endif diff --git a/src/draw/nxp/pxp/lv_pxp_osa.h b/src/draw/nxp/pxp/lv_pxp_osa.h index 03a8fdc59..371429049 100644 --- a/src/draw/nxp/pxp/lv_pxp_osa.h +++ b/src/draw/nxp/pxp/lv_pxp_osa.h @@ -4,7 +4,7 @@ */ /** - * Copyright 2020, 2022, 2023 NXP + * Copyright 2020, 2022-2023 NXP * * SPDX-License-Identifier: MIT */ diff --git a/src/draw/nxp/pxp/lv_pxp_utils.c b/src/draw/nxp/pxp/lv_pxp_utils.c index 164ca6f0e..3940a68b5 100644 --- a/src/draw/nxp/pxp/lv_pxp_utils.c +++ b/src/draw/nxp/pxp/lv_pxp_utils.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -42,15 +42,9 @@ pxp_output_pixel_format_t pxp_get_out_px_format(lv_color_format_t cf) pxp_output_pixel_format_t out_px_format = kPXP_OutputPixelFormatRGB565; switch(cf) { - /*2 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB565: out_px_format = kPXP_OutputPixelFormatRGB565; break; - case LV_COLOR_FORMAT_RGB565A8: - LV_ASSERT_MSG(false, "Unsupported color format."); - break; - - /*3 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB888: out_px_format = kPXP_OutputPixelFormatRGB888P; break; @@ -62,7 +56,7 @@ pxp_output_pixel_format_t pxp_get_out_px_format(lv_color_format_t cf) break; default: - LV_ASSERT_MSG(false, "Unsupported color format."); + PXP_ASSERT_MSG(false, "Unsupported color format."); break; } @@ -74,17 +68,11 @@ pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf) pxp_as_pixel_format_t as_px_format = kPXP_AsPixelFormatRGB565; switch(cf) { - /*2 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB565: as_px_format = kPXP_AsPixelFormatRGB565; break; - case LV_COLOR_FORMAT_RGB565A8: - LV_ASSERT_MSG(false, "Unsupported color format."); - break; - - /*3 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB888: - LV_ASSERT_MSG(false, "Unsupported color format."); + PXP_ASSERT_MSG(false, "Unsupported color format."); break; case LV_COLOR_FORMAT_ARGB8888: as_px_format = kPXP_AsPixelFormatARGB8888; @@ -94,7 +82,7 @@ pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf) break; default: - LV_ASSERT_MSG(false, "Unsupported color format."); + PXP_ASSERT_MSG(false, "Unsupported color format."); break; } @@ -106,24 +94,18 @@ pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf) pxp_ps_pixel_format_t ps_px_format = kPXP_PsPixelFormatRGB565; switch(cf) { - /*2 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB565: ps_px_format = kPXP_PsPixelFormatRGB565; break; - case LV_COLOR_FORMAT_RGB565A8: - LV_ASSERT_MSG(false, "Unsupported color format."); - break; - - /*3 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB888: - LV_ASSERT_MSG(false, "Unsupported color format."); + PXP_ASSERT_MSG(false, "Unsupported color format."); break; case LV_COLOR_FORMAT_ARGB8888: #if (!(defined(FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT) && FSL_FEATURE_PXP_HAS_NO_EXTEND_PIXEL_FORMAT)) && \ (!(defined(FSL_FEATURE_PXP_V3) && FSL_FEATURE_PXP_V3)) ps_px_format = kPXP_PsPixelFormatARGB8888; #else - LV_ASSERT_MSG(false, "Unsupported color format."); + PXP_ASSERT_MSG(false, "Unsupported color format."); #endif break; case LV_COLOR_FORMAT_XRGB8888: @@ -136,13 +118,26 @@ pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf) break; default: - LV_ASSERT_MSG(false, "Unsupported color format."); + PXP_ASSERT_MSG(false, "Unsupported color format."); break; } return ps_px_format; } +bool pxp_buf_aligned(const void * buf, uint32_t stride) +{ + /* Test for pointer alignment */ + if((uintptr_t)buf % 64) + return false; + + /* Test for invalid stride (no stride alignment required) */ + if(stride == 0) + return false; + + return true; +} + /********************** * STATIC FUNCTIONS **********************/ diff --git a/src/draw/nxp/pxp/lv_pxp_utils.h b/src/draw/nxp/pxp/lv_pxp_utils.h index 0a7c670e9..928517c55 100644 --- a/src/draw/nxp/pxp/lv_pxp_utils.h +++ b/src/draw/nxp/pxp/lv_pxp_utils.h @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -29,6 +29,14 @@ extern "C" { * DEFINES *********************/ +#if LV_USE_PXP_ASSERT +#define PXP_ASSERT(expr) LV_ASSERT(expr) +#define PXP_ASSERT_MSG(expr, msg) LV_ASSERT_MSG(expr, msg) +#else +#define PXP_ASSERT(expr) +#define PXP_ASSERT_MSG(expr, msg) LV_LOG_ERROR(msg) +#endif + /********************** * TYPEDEFS **********************/ @@ -47,6 +55,8 @@ pxp_as_pixel_format_t pxp_get_as_px_format(lv_color_format_t cf); pxp_ps_pixel_format_t pxp_get_ps_px_format(lv_color_format_t cf); +bool pxp_buf_aligned(const void * buf, uint32_t stride); + /********************** * MACROS **********************/ diff --git a/src/draw/nxp/vglite/lv_draw_buf_vglite.c b/src/draw/nxp/vglite/lv_draw_buf_vglite.c index 108cd8be8..393c9a6b2 100644 --- a/src/draw/nxp/vglite/lv_draw_buf_vglite.c +++ b/src/draw/nxp/vglite/lv_draw_buf_vglite.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -17,7 +17,6 @@ #if LV_USE_DRAW_VGLITE #include "lv_vglite_buf.h" -#include "lv_vglite_matrix.h" #include "lv_vglite_utils.h" #include "lvgl_support.h" @@ -36,14 +35,12 @@ static void * _buf_malloc(size_t size_bytes, lv_color_format_t cf); -static void * _align_buf(void * buf, lv_color_format_t cf); +static void * _buf_align(void * buf, lv_color_format_t cf); -static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area); +static void _invalidate_cache(void * buf, uint32_t stride, lv_color_format_t cf, const lv_area_t * area); static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf); -static void * _go_to_xy(lv_draw_buf_t * draw_buf, int32_t x, int32_t y); - /********************** * STATIC VARIABLES **********************/ @@ -61,7 +58,7 @@ void lv_draw_buf_vglite_init_handlers(void) lv_draw_buf_handlers_t * handlers = lv_draw_buf_get_handlers(); handlers->buf_malloc_cb = _buf_malloc; - handlers->align_pointer_cb = _align_buf; + handlers->align_pointer_cb = _buf_align; handlers->invalidate_cache_cb = _invalidate_cache; handlers->width_to_stride_cb = _width_to_stride; } @@ -80,7 +77,7 @@ static void * _buf_malloc(size_t size_bytes, lv_color_format_t cf) return lv_malloc(size_bytes); } -static void * _align_buf(void * buf, lv_color_format_t cf) +static void * _buf_align(void * buf, lv_color_format_t cf) { uint8_t align_bytes = vglite_get_alignment(cf); @@ -93,17 +90,54 @@ static void * _align_buf(void * buf, lv_color_format_t cf) return buf_u8; } -static void _invalidate_cache(lv_draw_buf_t * draw_buf, const char * area) +static void _invalidate_cache(void * buf, uint32_t stride, lv_color_format_t cf, const lv_area_t * area) { - LV_UNUSED(draw_buf); - LV_UNUSED(area); + if(area->y1 == 0) { + uint16_t size = stride * lv_area_get_height(area); - DEMO_CleanInvalidateCache(); + /* Invalidate full buffer. */ + DEMO_CleanInvalidateCacheByAddr((void *)buf, size); + return; + } + + const uint8_t * buf_u8 = buf; + /* ARM require a 32 byte aligned address. */ + uint8_t align_bytes = 32; + uint8_t bits_per_pixel = lv_color_format_get_bpp(cf); + + uint16_t align_pixels = align_bytes * 8 / bits_per_pixel; + uint16_t offset_x = 0; + + if(area->x1 >= (int32_t)(area->x1 % align_pixels)) { + uint16_t shift_x = area->x1 - (area->x1 % align_pixels); + + offset_x = area->x1 - shift_x; + buf_u8 += (shift_x * bits_per_pixel) / 8; + } + + if(area->y1) { + uint16_t shift_y = area->y1; + + buf_u8 += shift_y * stride; + } + + /* Area to clear can start from a different offset in buffer. + * Invalidate the area line by line. + */ + uint16_t line_pixels = offset_x + lv_area_get_width(area); + uint16_t line_size = (line_pixels * bits_per_pixel) / 8; + uint16_t area_height = lv_area_get_height(area); + + for(uint16_t y = 0; y < area_height; y++) { + const void * line_addr = buf_u8 + y * stride; + + DEMO_CleanInvalidateCacheByAddr((void *)line_addr, line_size); + } } static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf) { - uint8_t bits_per_pixel = vglite_get_px_size(cf); + uint8_t bits_per_pixel = lv_color_format_get_bpp(cf); uint32_t width_bits = (w * bits_per_pixel + 7) & ~7; uint32_t width_bytes = width_bits / 8; uint8_t align_bytes = vglite_get_alignment(cf); @@ -111,70 +145,4 @@ static uint32_t _width_to_stride(uint32_t w, lv_color_format_t cf) return (width_bytes + align_bytes - 1) & ~(align_bytes - 1); } -/** - * @todo - * LVGL needs to use hardware acceleration for buf_copy and do not affect GPU rendering. - */ -#if 0 - -static void _vglite_buf_clear(lv_draw_buf_t * draw_buf, const lv_area_t * area) -{ - uint32_t stride = lv_draw_buf_get_stride(draw_buf); - - /* Set vgbuf structure. */ - vg_lite_buffer_t vgbuf; - vglite_set_buf(&vgbuf, draw_buf->buf, draw_buf->width, draw_buf->height, stride, draw_buf->color_format); - - vg_lite_color_t vgcol = 0; - - vg_lite_rectangle_t rect = { - .x = area->x1, - .y = area->y1, - .width = lv_area_get_width(area), - .height = lv_area_get_height(area) - }; - - vg_lite_error_t err = vg_lite_clear(&vgbuf, &rect, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear failed."); - - vglite_run(); -} - -static void _vglite_buf_copy(void * dest_buf, uint32_t dest_stride, const lv_area_t * dest_area, - void * src_buf, uint32_t src_stride, const lv_area_t * src_area, - lv_color_format_t cf) -{ - /* Set src_vgbuf structure. */ - vg_lite_buffer_t src_vgbuf; - vglite_set_buf(&src_vgbuf, src_buf, lv_area_get_width(src_area), lv_area_get_height(src_area), src_stride, cf); - - /* Set dest_vgbuf structure. */ - vg_lite_buffer_t dest_vgbuf; - vglite_set_buf(&dest_vgbuf, dest_buf, lv_area_get_width(dest_area), lv_area_get_height(dest_area), dest_stride, cf); - - uint32_t rect[] = { - (uint32_t)src_area->x1, /* start x */ - (uint32_t)src_area->y1, /* start y */ - (uint32_t)lv_area_get_width(src_area), /* width */ - (uint32_t)lv_area_get_height(src_area) /* height */ - }; - - /* Set scissor. */ - vglite_set_scissor(dest_area); - - /* Set vgmatrix. */ - vglite_set_translation_matrix(dest_area); - vg_lite_matrix_t * vgmatrix = vglite_get_matrix(); - - vg_lite_error_t err = vg_lite_blit_rect(&dest_vgbuf, &src_vgbuf, rect, vgmatrix, - VG_LITE_BLEND_NONE, 0xFFFFFFFFU, VG_LITE_FILTER_POINT); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Blit rectangle failed."); - - vglite_run(); - - /* Disable scissor. */ - vglite_disable_scissor(); -} -#endif - #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite.c b/src/draw/nxp/vglite/lv_draw_vglite.c index c26366dd8..2b5570b31 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite.c +++ b/src/draw/nxp/vglite/lv_draw_vglite.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -19,7 +19,9 @@ #include "lv_vglite_buf.h" #include "lv_vglite_utils.h" -#include "../../../display/lv_display_private.h" +#if LV_USE_PARALLEL_DRAW_DEBUG + #include "../../../core/lv_global.h" +#endif /********************* * DEFINES @@ -27,7 +29,7 @@ #define DRAW_UNIT_ID_VGLITE 2 -#if LV_USE_OS +#if LV_USE_VGLITE_DRAW_ASYNC #define VGLITE_TASK_BUF_SIZE 10 #endif @@ -35,7 +37,7 @@ * TYPEDEFS **********************/ -#if LV_USE_OS +#if LV_USE_VGLITE_DRAW_ASYNC /** * Structure of pending vglite draw task */ @@ -50,16 +52,21 @@ typedef struct _vglite_draw_task_t { **********************/ /* - * Dispatch a task to the VGLite unit. + * Evaluate a task and set the score and preferred VGLite draw unit. + * Return 1 if task is preferred, 0 otherwise (task is not supported). + */ +static int32_t _vglite_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task); + +/* + * Dispatch (assign) a task to VGLite draw unit (itself). * Return 1 if task was dispatched, 0 otherwise (task not supported). */ static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer); /* - * Evaluate a task and set the score and preferred VGLite unit. - * Return 1 if task is preferred, 0 otherwise (task is not supported). + * Delete the VGLite draw unit. */ -static int32_t _vglite_evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task); +static int32_t _vglite_delete(lv_draw_unit_t * draw_unit); #if LV_USE_OS static void _vglite_render_thread_cb(void * ptr); @@ -71,7 +78,11 @@ static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u); * STATIC VARIABLES **********************/ -#if LV_USE_OS +#if LV_USE_PARALLEL_DRAW_DEBUG + #define _draw_info LV_GLOBAL_DEFAULT()->draw_info +#endif + +#if LV_USE_VGLITE_DRAW_ASYNC /* * Circular buffer to hold the queued and the flushed tasks. * Two indexes, _head and _tail, are used to signal the beginning @@ -95,11 +106,12 @@ void lv_draw_vglite_init(void) lv_draw_buf_vglite_init_handlers(); lv_draw_vglite_unit_t * draw_vglite_unit = lv_draw_create_unit(sizeof(lv_draw_vglite_unit_t)); - draw_vglite_unit->base_unit.dispatch_cb = _vglite_dispatch; draw_vglite_unit->base_unit.evaluate_cb = _vglite_evaluate; + draw_vglite_unit->base_unit.dispatch_cb = _vglite_dispatch; + draw_vglite_unit->base_unit.delete_cb = _vglite_delete; #if LV_USE_OS - lv_thread_init(&draw_vglite_unit->thread, LV_THREAD_PRIO_HIGH, _vglite_render_thread_cb, 8 * 1024, draw_vglite_unit); + lv_thread_init(&draw_vglite_unit->thread, LV_THREAD_PRIO_HIGH, _vglite_render_thread_cb, 2 * 1024, draw_vglite_unit); #endif } @@ -111,19 +123,70 @@ void lv_draw_vglite_deinit(void) * STATIC FUNCTIONS **********************/ -static inline bool _vglite_cf_supported(lv_color_format_t cf) +static inline bool _vglite_src_cf_supported(lv_color_format_t cf) { - /*Add here the platform specific code for supported formats.*/ + bool is_cf_supported = false; - bool is_cf_unsupported = (cf == LV_COLOR_FORMAT_RGB565A8 || cf == LV_COLOR_FORMAT_RGB888); + switch(cf) { +#if CHIPID == 0x255 || CHIPID == 0x555 + case LV_COLOR_FORMAT_I1: + case LV_COLOR_FORMAT_I2: + case LV_COLOR_FORMAT_I4: + case LV_COLOR_FORMAT_I8: +#endif + case LV_COLOR_FORMAT_A4: + case LV_COLOR_FORMAT_A8: + case LV_COLOR_FORMAT_L8: + case LV_COLOR_FORMAT_RGB565: +#if CHIPID == 0x555 + case LV_COLOR_FORMAT_RGB565A8: + case LV_COLOR_FORMAT_RGB888: +#endif + case LV_COLOR_FORMAT_ARGB8888: + case LV_COLOR_FORMAT_XRGB8888: + is_cf_supported = true; + break; + default: + break; + } - return (!is_cf_unsupported); + return is_cf_supported; +} + +static inline bool _vglite_dest_cf_supported(lv_color_format_t cf) +{ + bool is_cf_supported = false; + + switch(cf) { + case LV_COLOR_FORMAT_A8: +#if CHIPID == 0x255 || CHIPID == 0x555 + case LV_COLOR_FORMAT_L8: +#endif + case LV_COLOR_FORMAT_RGB565: +#if CHIPTID == 0x555 + case LV_COLOR_FORMAT_RGB565A8: + case LV_COLOR_FORMAT_RGB888: +#endif + case LV_COLOR_FORMAT_ARGB8888: + case LV_COLOR_FORMAT_XRGB8888: + is_cf_supported = true; + break; + default: + break; + } + + return is_cf_supported; } static int32_t _vglite_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) { LV_UNUSED(u); + const lv_draw_dsc_base_t * draw_dsc_base = (lv_draw_dsc_base_t *) t->draw_dsc; + + if(!_vglite_dest_cf_supported(draw_dsc_base->layer->color_format)) + return 0; + switch(t->type) { case LV_DRAW_TASK_TYPE_FILL: if(t->preference_score > 80) { @@ -134,6 +197,7 @@ static int32_t _vglite_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) case LV_DRAW_TASK_TYPE_LINE: case LV_DRAW_TASK_TYPE_ARC: + case LV_DRAW_TASK_TYPE_TRIANGLE: if(t->preference_score > 90) { t->preference_score = 90; t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE; @@ -160,37 +224,11 @@ static int32_t _vglite_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) return 1; } - case LV_DRAW_TASK_TYPE_BG_IMG: { - const lv_draw_bg_image_dsc_t * draw_dsc = (lv_draw_bg_image_dsc_t *) t->draw_dsc; - lv_image_src_t src_type = lv_image_src_get_type(draw_dsc->src); - - if(src_type != LV_IMAGE_SRC_SYMBOL) { - bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP); - - if(has_recolor - || (!_vglite_cf_supported(draw_dsc->img_header.cf)) - || (!vglite_buf_aligned(draw_dsc->src, draw_dsc->img_header.stride, draw_dsc->img_header.cf)) - ) - return 0; - } - - if(t->preference_score > 80) { - t->preference_score = 80; - t->preferred_draw_unit_id = DRAW_UNIT_ID_VGLITE; - } - return 1; - } - case LV_DRAW_TASK_TYPE_LAYER: { const lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc; lv_layer_t * layer_to_draw = (lv_layer_t *)draw_dsc->src; - lv_draw_buf_t * draw_buf = &layer_to_draw->draw_buf; - bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP); - - if(has_recolor - || (!_vglite_cf_supported(draw_buf->color_format)) - ) + if(!_vglite_src_cf_supported(layer_to_draw->color_format)) return 0; if(t->preference_score > 80) { @@ -204,16 +242,15 @@ static int32_t _vglite_evaluate(lv_draw_unit_t * u, lv_draw_task_t * t) lv_draw_image_dsc_t * draw_dsc = (lv_draw_image_dsc_t *) t->draw_dsc; const lv_image_dsc_t * img_dsc = draw_dsc->src; - bool has_recolor = (draw_dsc->recolor_opa != LV_OPA_TRANSP); -#if VGLITE_BLIT_SPLIT_ENABLED - bool has_transform = (draw_dsc->angle != 0 || draw_dsc->zoom != LV_ZOOM_NONE); +#if LV_USE_VGLITE_BLIT_SPLIT + bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE || + draw_dsc->scale_y != LV_SCALE_NONE); #endif - if(has_recolor -#if VGLITE_BLIT_SPLIT_ENABLED + if((!_vglite_src_cf_supported(img_dsc->header.cf)) +#if LV_USE_VGLITE_BLIT_SPLIT || has_transform #endif - || (!_vglite_cf_supported(img_dsc->header.cf)) || (!vglite_buf_aligned(img_dsc->data, img_dsc->header.stride, img_dsc->header.cf)) ) return 0; @@ -239,19 +276,11 @@ static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) if(draw_vglite_unit->task_act) return 0; - /* Return if target buffer format is not supported. - * - * FIXME: Source format and destination format support is different! - */ - if(!_vglite_cf_supported(layer->draw_buf.color_format)) - return 0; - /* Try to get an ready to draw. */ lv_draw_task_t * t = lv_draw_get_next_available_task(layer, NULL, DRAW_UNIT_ID_VGLITE); - /* Return 0 is no selection, some tasks can be supported by other units. */ if(t == NULL || t->preferred_draw_unit_id != DRAW_UNIT_ID_VGLITE) - return 0; + return -1; void * buf = lv_draw_layer_alloc_buf(layer); if(buf == NULL) @@ -264,7 +293,8 @@ static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) #if LV_USE_OS /* Let the render thread work. */ - lv_thread_sync_signal(&draw_vglite_unit->sync); + if(draw_vglite_unit->inited) + lv_thread_sync_signal(&draw_vglite_unit->sync); #else _vglite_execute_drawing(draw_vglite_unit); @@ -278,17 +308,55 @@ static int32_t _vglite_dispatch(lv_draw_unit_t * draw_unit, lv_layer_t * layer) return 1; } +static int32_t _vglite_delete(lv_draw_unit_t * draw_unit) +{ +#if LV_USE_OS + lv_draw_vglite_unit_t * draw_vglite_unit = (lv_draw_vglite_unit_t *) draw_unit; + + LV_LOG_INFO("Cancel VGLite draw thread."); + draw_vglite_unit->exit_status = true; + + if(draw_vglite_unit->inited) + lv_thread_sync_signal(&draw_vglite_unit->sync); + + lv_result_t res = lv_thread_delete(&draw_vglite_unit->thread); + + return res; +#else + LV_UNUSED(draw_unit); + + return 0; +#endif +} + static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u) { lv_draw_task_t * t = u->task_act; lv_draw_unit_t * draw_unit = (lv_draw_unit_t *)u; + lv_layer_t * layer = draw_unit->target_layer; /* Set target buffer */ - lv_layer_t * layer = draw_unit->target_layer; - vglite_set_dest_buf(&layer->draw_buf); + uint32_t buf_width = lv_area_get_width(&layer->buf_area); + uint32_t buf_height = lv_area_get_height(&layer->buf_area); - /* Invalidate cache */ - lv_draw_buf_invalidate_cache(&layer->draw_buf, (const char *)&t->area); + vglite_set_dest_buf(layer->buf, buf_width, buf_height, layer->buf_stride, layer->color_format); + + lv_area_t clip_area; + lv_area_copy(&clip_area, draw_unit->clip_area); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); + + lv_area_t draw_area; + lv_area_copy(&draw_area, &t->area); + lv_area_move(&draw_area, -layer->buf_area.x1, -layer->buf_area.y1); + + if(!_lv_area_intersect(&draw_area, &draw_area, &clip_area)) + return; /*Fully clipped, nothing to do*/ + + /* Invalidate the drawing area */ + lv_draw_buf_invalidate_cache(layer->buf, layer->buf_stride, layer->color_format, &draw_area); + + /* Set scissor area */ + vglite_set_scissor(&clip_area); switch(t->type) { case LV_DRAW_TASK_TYPE_LABEL: @@ -300,9 +368,6 @@ static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u) case LV_DRAW_TASK_TYPE_BORDER: lv_draw_vglite_border(draw_unit, t->draw_dsc, &t->area); break; - case LV_DRAW_TASK_TYPE_BG_IMG: - lv_draw_vglite_bg_img(draw_unit, t->draw_dsc, &t->area); - break; case LV_DRAW_TASK_TYPE_IMAGE: lv_draw_vglite_img(draw_unit, t->draw_dsc, &t->area); break; @@ -315,20 +380,25 @@ static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u) case LV_DRAW_TASK_TYPE_LAYER: lv_draw_vglite_layer(draw_unit, t->draw_dsc, &t->area); break; + case LV_DRAW_TASK_TYPE_TRIANGLE: + lv_draw_vglite_triangle(draw_unit, t->draw_dsc); + break; default: break; } + /* Disable scissor */ + vglite_set_scissor(&layer->buf_area); + #if LV_USE_PARALLEL_DRAW_DEBUG - /* Layers manage it for themselves. */ + /*Layers manage it for themselves*/ if(t->type != LV_DRAW_TASK_TYPE_LAYER) { lv_area_t draw_area; if(!_lv_area_intersect(&draw_area, &t->area, u->base_unit.clip_area)) return; int32_t idx = 0; - lv_disp_t * disp = _lv_refr_get_disp_refreshing(); - lv_draw_unit_t * draw_unit_tmp = disp->draw_unit_head; + lv_draw_unit_t * draw_unit_tmp = _draw_info.unit_head; while(draw_unit_tmp != (lv_draw_unit_t *)u) { draw_unit_tmp = draw_unit_tmp->next; idx++; @@ -340,10 +410,10 @@ static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u) rect_dsc.bg_opa = LV_OPA_10; rect_dsc.border_opa = LV_OPA_80; rect_dsc.border_width = 1; - lv_draw_vglite_rect((lv_draw_unit_t *)u, &rect_dsc, &draw_area); + lv_draw_sw_fill((lv_draw_unit_t *)u, &rect_dsc, &draw_area); lv_point_t txt_size; - lv_txt_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); + lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); lv_area_t txt_area; txt_area.x1 = draw_area.x1; @@ -353,7 +423,7 @@ static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u) lv_draw_rect_dsc_init(&rect_dsc); rect_dsc.bg_color = lv_color_white(); - lv_draw_vglite_rect((lv_draw_unit_t *)u, &rect_dsc, &txt_area); + lv_draw_sw_fill((lv_draw_unit_t *)u, &rect_dsc, &txt_area); char buf[8]; lv_snprintf(buf, sizeof(buf), "%d", idx); @@ -361,12 +431,12 @@ static void _vglite_execute_drawing(lv_draw_vglite_unit_t * u) lv_draw_label_dsc_init(&label_dsc); label_dsc.color = lv_color_black(); label_dsc.text = buf; - lv_draw_vglite_label((lv_draw_unit_t *)u, &label_dsc, &txt_area); + lv_draw_sw_label((lv_draw_unit_t *)u, &label_dsc, &txt_area); } #endif } -#if LV_USE_OS +#if LV_USE_VGLITE_DRAW_ASYNC static inline void _vglite_queue_task(lv_draw_task_t * task_act) { _draw_task_buf[_tail].task = task_act; @@ -397,29 +467,47 @@ static inline void _vglite_signal_task_ready(lv_draw_task_t * task_act) } if(task_act) - LV_ASSERT_MSG(_tail != _head, "VGLite task buffer full."); + VGLITE_ASSERT_MSG(_tail != _head, "VGLite task buffer full."); } +#endif +#if LV_USE_OS static void _vglite_render_thread_cb(void * ptr) { lv_draw_vglite_unit_t * u = ptr; lv_thread_sync_init(&u->sync); + u->inited = true; while(1) { - /* - * Wait for sync if no task received or _draw_task_buf is empty. - * The thread will have to run as much as there are pending tasks. - */ - while(u->task_act == NULL && _head == _tail) { + /* Wait for sync if there is no task set. */ + while(u->task_act == NULL +#if LV_USE_VGLITE_DRAW_ASYNC + /* + * Wait for sync if _draw_task_buf is empty. + * The thread will have to run as much as there are pending tasks. + */ + && _head == _tail +#endif + ) { + if(u->exit_status) + break; + lv_thread_sync_wait(&u->sync); } - if(u->task_act) { - _vglite_queue_task((void *)u->task_act); + if(u->exit_status) { + LV_LOG_INFO("Ready to exit VGLite draw thread."); + break; + } + if(u->task_act) { +#if LV_USE_VGLITE_DRAW_ASYNC + _vglite_queue_task((void *)u->task_act); +#endif _vglite_execute_drawing(u); } +#if LV_USE_VGLITE_DRAW_ASYNC else { /* * Update the flush status for last pending tasks. @@ -427,15 +515,23 @@ static void _vglite_render_thread_cb(void * ptr) */ vglite_run(); } - +#endif +#if LV_USE_VGLITE_DRAW_ASYNC _vglite_signal_task_ready((void *)u->task_act); - +#else + /* Signal the ready state to dispatcher. */ + u->task_act->state = LV_DRAW_TASK_STATE_READY; +#endif /* Cleanup. */ u->task_act = NULL; /* The draw unit is free now. Request a new dispatching as it can get a new task. */ lv_draw_dispatch_request(); } + + u->inited = false; + lv_thread_sync_delete(&u->sync); + LV_LOG_INFO("Exit VGLite draw thread."); } #endif diff --git a/src/draw/nxp/vglite/lv_draw_vglite.h b/src/draw/nxp/vglite/lv_draw_vglite.h index 2b6dcec68..fe3cdfbc2 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite.h +++ b/src/draw/nxp/vglite/lv_draw_vglite.h @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -29,33 +29,11 @@ extern "C" { * DEFINES *********************/ -/** - * Enable BLIT quality degradation workaround for RT595, - * recommended for screen's dimension > 352 pixels. - */ -#define RT595_BLIT_WRKRND_ENABLED 1 - -/* Internal compound symbol */ -#if (defined(CPU_MIMXRT595SFFOB) || defined(CPU_MIMXRT595SFFOB_cm33) || \ - defined(CPU_MIMXRT595SFFOC) || defined(CPU_MIMXRT595SFFOC_cm33)) && \ - RT595_BLIT_WRKRND_ENABLED -#define VGLITE_BLIT_SPLIT_ENABLED 1 -#else -#define VGLITE_BLIT_SPLIT_ENABLED 0 -#endif - /********************** * TYPEDEFS **********************/ -typedef struct { - lv_draw_unit_t base_unit; - lv_draw_task_t * task_act; -#if LV_USE_OS - lv_thread_sync_t sync; - lv_thread_t thread; -#endif -} lv_draw_vglite_unit_t; +typedef lv_draw_sw_unit_t lv_draw_vglite_unit_t; /********************** * GLOBAL PROTOTYPES @@ -70,9 +48,6 @@ void lv_draw_vglite_deinit(void); void lv_draw_vglite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * dsc, const lv_area_t * coords); -void lv_draw_vglite_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc, - const lv_area_t * coords); - void lv_draw_vglite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_t * dsc, const lv_area_t * coords); @@ -90,6 +65,8 @@ void lv_draw_vglite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t void lv_draw_vglite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * dsc); +void lv_draw_vglite_triangle(lv_draw_unit_t * draw_unit, const lv_draw_triangle_dsc_t * dsc); + /********************** * MACROS **********************/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_arc.c b/src/draw/nxp/vglite/lv_draw_vglite_arc.c index 8bc4b9c50..b35d2c74a 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_arc.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_arc.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2021-2023 NXP + * Copyright 2021-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -77,7 +77,7 @@ typedef struct _cubic_cont_pt { * Draw arc shape with effects * * @param[in] center Arc center with relative coordinates - * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] clip_area Clip area with relative coordinates to dest buff * @param[in] dsc Arc description structure (width, rounded ending, opacity) * */ @@ -109,13 +109,13 @@ void lv_draw_vglite_arc(lv_draw_unit_t * draw_unit, const lv_draw_arc_dsc_t * ds return; lv_layer_t * layer = draw_unit->target_layer; - lv_point_t rel_center = {dsc->center.x - layer->draw_buf_ofs.x, dsc->center.y - layer->draw_buf_ofs.y}; + lv_point_t center = {dsc->center.x - layer->buf_area.x1, dsc->center.y - layer->buf_area.y1}; - lv_area_t rel_clip_area; - lv_area_copy(&rel_clip_area, draw_unit->clip_area); - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_t clip_area; + lv_area_copy(&clip_area, draw_unit->clip_area); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); - _vglite_draw_arc(&rel_center, &rel_clip_area, dsc); + _vglite_draw_arc(¢er, &clip_area, dsc); } /********************** @@ -207,7 +207,7 @@ static void _set_full_arc(vg_arc * fullarc) fullarc->p3y = 0; break; default: - LV_ASSERT_MSG(false, "Invalid arc quarter."); + VGLITE_ASSERT_MSG(false, "Invalid arc quarter."); break; } } @@ -562,10 +562,14 @@ static void _add_arc_path(int32_t * arc_path, int * pidx, int32_t radius, static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_area, const lv_draw_arc_dsc_t * dsc) { - vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_path_t path; uint16_t start_angle = dsc->start_angle; uint16_t end_angle = dsc->end_angle; + + /* be sure end_angle > start_angle */ + if(end_angle < start_angle) + end_angle += 360; + bool donut = ((end_angle - start_angle) % 360 == 0) ? true : false; vg_lite_buffer_t * vgbuf = vglite_get_dest_buf(); @@ -662,10 +666,9 @@ static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_a arc_path[pidx++] = VLC_OP_END; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, (uint32_t)pidx * sizeof(int32_t), arc_path, - (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, - ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed."); + VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, (uint32_t)pidx * sizeof(int32_t), arc_path, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f)); lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa); vg_lite_color_t vgcol = vglite_get_color(col32, false); @@ -673,18 +676,12 @@ static void _vglite_draw_arc(const lv_point_t * center, const lv_area_t * clip_a vg_lite_matrix_t matrix; vg_lite_identity(&matrix); - vglite_set_scissor(clip_area); - /*** Draw arc ***/ - err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw arc failed."); + VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol)); vglite_run(); - vglite_disable_scissor(); - - err = vg_lite_clear_path(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed."); + VGLITE_CHECK_ERROR(vg_lite_clear_path(&path)); } #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_bg_img.c b/src/draw/nxp/vglite/lv_draw_vglite_bg_img.c deleted file mode 100644 index b66af8336..000000000 --- a/src/draw/nxp/vglite/lv_draw_vglite_bg_img.c +++ /dev/null @@ -1,113 +0,0 @@ -/** - * @file lv_draw_vglite_bg_img.c - * - */ - -/** - * Copyright 2022, 2023 NXP - * - * SPDX-License-Identifier: MIT - */ - -/********************* - * INCLUDES - *********************/ - -#include "lv_draw_vglite.h" - -#if LV_USE_DRAW_VGLITE - -/********************* - * DEFINES - *********************/ - -/********************** - * TYPEDEFS - **********************/ - -/********************** - * STATIC PROTOTYPES - **********************/ - -/********************** - * STATIC VARIABLES - **********************/ - -/********************** - * MACROS - **********************/ - -/********************** - * GLOBAL FUNCTIONS - **********************/ - -void lv_draw_vglite_bg_img(lv_draw_unit_t * draw_unit, const lv_draw_bg_image_dsc_t * dsc, - const lv_area_t * coords) -{ - if(dsc->src == NULL) return; - if(dsc->opa <= LV_OPA_MIN) return; - - lv_area_t clip_area; - if(!_lv_area_intersect(&clip_area, coords, draw_unit->clip_area)) { - return; - } - - const lv_area_t * clip_area_ori = draw_unit->clip_area; - draw_unit->clip_area = &clip_area; - - lv_image_src_t src_type = lv_image_src_get_type(dsc->src); - if(src_type == LV_IMAGE_SRC_SYMBOL) { - lv_point_t size; - lv_text_get_size(&size, dsc->src, dsc->font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE); - lv_area_t a; - a.x1 = coords->x1 + lv_area_get_width(coords) / 2 - size.x / 2; - a.x2 = a.x1 + size.x - 1; - a.y1 = coords->y1 + lv_area_get_height(coords) / 2 - size.y / 2; - a.y2 = a.y1 + size.y - 1; - - lv_draw_label_dsc_t label_draw_dsc; - lv_draw_label_dsc_init(&label_draw_dsc); - label_draw_dsc.font = dsc->font; - label_draw_dsc.color = dsc->recolor; - label_draw_dsc.opa = dsc->opa; - label_draw_dsc.text = dsc->src; - lv_draw_vglite_label(draw_unit, &label_draw_dsc, &a); - } - else { - lv_draw_image_dsc_t img_dsc; - lv_draw_image_dsc_init(&img_dsc); - img_dsc.recolor = dsc->recolor; - img_dsc.recolor_opa = dsc->recolor_opa; - img_dsc.opa = dsc->opa; - img_dsc.src = dsc->src; - - /*Center align*/ - if(dsc->tiled == false) { - lv_area_t area; - area.x1 = coords->x1 + lv_area_get_width(coords) / 2 - dsc->img_header.w / 2; - area.y1 = coords->y1 + lv_area_get_height(coords) / 2 - dsc->img_header.h / 2; - area.x2 = area.x1 + dsc->img_header.w - 1; - area.y2 = area.y1 + dsc->img_header.h - 1; - - lv_draw_vglite_img(draw_unit, &img_dsc, &area); - } - else { - lv_area_t area; - area.y1 = coords->y1; - area.y2 = area.y1 + dsc->img_header.h - 1; - - for(; area.y1 <= coords->y2; area.y1 += dsc->img_header.h, area.y2 += dsc->img_header.h) { - - area.x1 = coords->x1; - area.x2 = area.x1 + dsc->img_header.w - 1; - for(; area.x1 <= coords->x2; area.x1 += dsc->img_header.w, area.x2 += dsc->img_header.w) { - lv_draw_vglite_img(draw_unit, &img_dsc, &area); - } - } - } - } - - draw_unit->clip_area = clip_area_ori; -} - -#endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_border.c b/src/draw/nxp/vglite/lv_draw_vglite_border.c index 0ea8073ea..eb8c93bae 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_border.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_border.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2022, 2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -42,7 +42,7 @@ * Draw rectangle border/outline shape with effects (rounded corners, opacity) * * @param[in] coords Coordinates of the rectangle border/outline (relative to dest buff) - * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] clip_area Clip area with relative coordinates to dest buff * @param[in] dsc Description of the rectangle border/outline * */ @@ -72,33 +72,26 @@ void lv_draw_vglite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_ return; lv_layer_t * layer = draw_unit->target_layer; - lv_area_t rel_coords; + lv_area_t inward_coords; int32_t width = dsc->width; /* Move border inwards to align with software rendered border */ - rel_coords.x1 = coords->x1 + ceil(width / 2.0f); - rel_coords.x2 = coords->x2 - floor(width / 2.0f); - rel_coords.y1 = coords->y1 + ceil(width / 2.0f); - rel_coords.y2 = coords->y2 - floor(width / 2.0f); + inward_coords.x1 = coords->x1 + ceil(width / 2.0f); + inward_coords.x2 = coords->x2 - floor(width / 2.0f); + inward_coords.y1 = coords->y1 + ceil(width / 2.0f); + inward_coords.y2 = coords->y2 - floor(width / 2.0f); - /* Move outline outwards to align with software rendered outline */ - //int32_t outline_pad = dsc->outline_pad - 1; - //rel_coords.x1 = coords->x1 - outline_pad - floor(dsc->outline_width / 2.0f); - //rel_coords.x2 = coords->x2 + outline_pad + ceil(dsc->outline_width / 2.0f); - //rel_coords.y1 = coords->y1 - outline_pad - floor(dsc->outline_width / 2.0f); - //rel_coords.y2 = coords->y2 + outline_pad + ceil(dsc->outline_width / 2.0f); + lv_area_move(&inward_coords, -layer->buf_area.x1, -layer->buf_area.y1); - lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); - - lv_area_t rel_clip_area; - lv_area_copy(&rel_clip_area, draw_unit->clip_area); - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_t clip_area; + lv_area_copy(&clip_area, draw_unit->clip_area); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t clipped_coords; - if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area)) + if(!_lv_area_intersect(&clipped_coords, &inward_coords, &clip_area)) return; /*Fully clipped, nothing to do*/ - _vglite_draw_border(&rel_coords, &rel_clip_area, dsc); + _vglite_draw_border(&inward_coords, &clip_area, dsc); } /********************** @@ -108,7 +101,6 @@ void lv_draw_vglite_border(lv_draw_unit_t * draw_unit, const lv_draw_border_dsc_ static void _vglite_draw_border(const lv_area_t * coords, const lv_area_t * clip_area, const lv_draw_border_dsc_t * dsc) { - vg_lite_error_t err = VG_LITE_SUCCESS; int32_t radius = dsc->radius; vg_lite_buffer_t * vgbuf = vglite_get_dest_buf(); @@ -119,13 +111,6 @@ static void _vglite_draw_border(const lv_area_t * coords, const lv_area_t * clip if(radius > border_half) radius = radius - border_half; - //else { - // /* Draw outline - always has radius, leave the same radius in the circle case */ - // int32_t outline_half = (int32_t)ceil(dsc->outline_width / 2.0f); - // if(radius < (int32_t)LV_RADIUS_CIRCLE - outline_half) - // radius = radius + outline_half; - //} - vg_lite_cap_style_t cap_style = (radius) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT; vg_lite_join_style_t join_style = (radius) ? VG_LITE_JOIN_ROUND : VG_LITE_JOIN_MITER; @@ -136,10 +121,9 @@ static void _vglite_draw_border(const lv_area_t * coords, const lv_area_t * clip vg_lite_quality_t path_quality = radius > 0 ? VG_LITE_HIGH : VG_LITE_MEDIUM; vg_lite_path_t path; - err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data, - (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, - ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed."); + VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f)); lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa); vg_lite_color_t vgcol = vglite_get_color(col32, false); @@ -150,26 +134,17 @@ static void _vglite_draw_border(const lv_area_t * coords, const lv_area_t * clip int32_t line_width = dsc->width; /*** Draw border ***/ - err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set draw path type failed."); + VGLITE_CHECK_ERROR(vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH)); - err = vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set stroke failed."); + VGLITE_CHECK_ERROR(vg_lite_set_stroke(&path, cap_style, join_style, line_width, 8, NULL, 0, 0, vgcol)); - err = vg_lite_update_stroke(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Update stroke failed."); + VGLITE_CHECK_ERROR(vg_lite_update_stroke(&path)); - vglite_set_scissor(clip_area); - - err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw border failed."); + VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol)); vglite_run(); - vglite_disable_scissor(); - - err = vg_lite_clear_path(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed."); + VGLITE_CHECK_ERROR(vg_lite_clear_path(&path)); } #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_fill.c b/src/draw/nxp/vglite/lv_draw_vglite_fill.c index d2d452295..bf066859e 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_fill.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_fill.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2020-2023 NXP + * Copyright 2020-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -47,7 +47,7 @@ static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * * Draw rectangle background with effects (rounded corners, gradient) * * @param[in] coords Coordinates of the rectangle background (relative to dest buff) - * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] clip_area Clip area with relative coordinates to dest buff * @param[in] dsc Description of the rectangle background * */ @@ -73,24 +73,16 @@ void lv_draw_vglite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * return; lv_layer_t * layer = draw_unit->target_layer; - lv_area_t rel_coords; - lv_area_copy(&rel_coords, coords); + lv_area_t relative_coords; + lv_area_copy(&relative_coords, coords); + lv_area_move(&relative_coords, -layer->buf_area.x1, -layer->buf_area.y1); - /*If the border fully covers make the bg area 1px smaller to avoid artifacts on the corners*/ - //if(dsc->border_width > 1 && dsc->border_opa >= (lv_opa_t)LV_OPA_MAX && dsc->radius != 0) { - // rel_coords.x1 += (dsc->border_side & LV_BORDER_SIDE_LEFT) ? 1 : 0; - // rel_coords.y1 += (dsc->border_side & LV_BORDER_SIDE_TOP) ? 1 : 0; - // rel_coords.x2 -= (dsc->border_side & LV_BORDER_SIDE_RIGHT) ? 1 : 0; - // rel_coords.y2 -= (dsc->border_side & LV_BORDER_SIDE_BOTTOM) ? 1 : 0; - //} - lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); - - lv_area_t rel_clip_area; - lv_area_copy(&rel_clip_area, draw_unit->clip_area); - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_t clip_area; + lv_area_copy(&clip_area, draw_unit->clip_area); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t clipped_coords; - if(!_lv_area_intersect(&clipped_coords, &rel_coords, &rel_clip_area)) + if(!_lv_area_intersect(&clipped_coords, &relative_coords, &clip_area)) return; /*Fully clipped, nothing to do*/ /* @@ -99,7 +91,7 @@ void lv_draw_vglite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * if((dsc->radius == 0) && (dsc->grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_NONE)) _vglite_fill(&clipped_coords, dsc); else - _vglite_draw_rect(&rel_coords, &rel_clip_area, dsc); + _vglite_draw_rect(&relative_coords, &clip_area, dsc); } /********************** @@ -108,7 +100,6 @@ void lv_draw_vglite_fill(lv_draw_unit_t * draw_unit, const lv_draw_fill_dsc_t * static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * dsc) { - vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_buffer_t * vgbuf = vglite_get_dest_buf(); lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa); @@ -122,8 +113,7 @@ static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * .height = lv_area_get_height(dest_area) }; - err = vg_lite_clear(vgbuf, &rect, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear failed."); + VGLITE_CHECK_ERROR(vg_lite_clear(vgbuf, &rect, vgcol)); vglite_run(); } @@ -139,32 +129,29 @@ static void _vglite_fill(const lv_area_t * dest_area, const lv_draw_fill_dsc_t * VLC_OP_END }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_MEDIUM, sizeof(path_data), path_data, - (vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1, - ((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed."); + VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_MEDIUM, sizeof(path_data), path_data, + (vg_lite_float_t) dest_area->x1, (vg_lite_float_t) dest_area->y1, + ((vg_lite_float_t) dest_area->x2) + 1.0f, ((vg_lite_float_t) dest_area->y2) + 1.0f)); vg_lite_matrix_t matrix; vg_lite_identity(&matrix); /*Draw rectangle*/ - err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw rectangle failed."); + VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol)); vglite_run(); - err = vg_lite_clear_path(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed."); + VGLITE_CHECK_ERROR(vg_lite_clear_path(&path)); } } static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_area, const lv_draw_fill_dsc_t * dsc) { - vg_lite_error_t err = VG_LITE_SUCCESS; int32_t width = lv_area_get_width(coords); int32_t height = lv_area_get_height(coords); int32_t radius = dsc->radius; + lv_opa_t opa = dsc->opa; vg_lite_buffer_t * vgbuf = vglite_get_dest_buf(); if(dsc->radius < 0) @@ -177,20 +164,17 @@ static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_a vg_lite_quality_t path_quality = dsc->radius > 0 ? VG_LITE_HIGH : VG_LITE_MEDIUM; vg_lite_path_t path; - err = vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data, - (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, - ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed."); + VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, path_quality, path_data_size, path_data, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f)); vg_lite_matrix_t matrix; vg_lite_identity(&matrix); /*** Init Color ***/ - lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa); + lv_color32_t col32 = lv_color_to_32(dsc->color, opa); vg_lite_color_t vgcol = vglite_get_color(col32, false); - vglite_set_scissor(clip_area); - vg_lite_linear_gradient_t gradient; bool has_gradient = (dsc->grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE); @@ -198,29 +182,30 @@ static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_a if(has_gradient) { vg_lite_matrix_t * grad_matrix; - uint32_t colors[2]; - uint32_t stops[2]; - lv_color32_t col32[2]; + vg_lite_uint32_t colors[LV_GRADIENT_MAX_STOPS]; + vg_lite_uint32_t stops[LV_GRADIENT_MAX_STOPS]; + lv_color32_t col32[LV_GRADIENT_MAX_STOPS]; /* Gradient setup */ - uint8_t cnt = LV_MAX(dsc->grad.stops_count, 2); + vg_lite_uint32_t cnt = LV_MAX(dsc->grad.stops_count, LV_GRADIENT_MAX_STOPS); + lv_opa_t opa; + for(uint8_t i = 0; i < cnt; i++) { stops[i] = dsc->grad.stops[i].frac; - col32[i] = lv_color_to_32(dsc->grad.stops[i].color, dsc->opa); + opa = LV_OPA_MIX2(dsc->grad.stops[i].opa, dsc->opa); + + col32[i] = lv_color_to_32(dsc->grad.stops[i].color, opa); colors[i] = vglite_get_color(col32[i], true); } lv_memzero(&gradient, sizeof(vg_lite_linear_gradient_t)); - err = vg_lite_init_grad(&gradient); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init gradient failed"); + VGLITE_CHECK_ERROR(vg_lite_init_grad(&gradient)); - err = vg_lite_set_grad(&gradient, cnt, colors, stops); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set gradient failed."); + VGLITE_CHECK_ERROR(vg_lite_set_grad(&gradient, cnt, colors, stops)); - err = vg_lite_update_grad(&gradient); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Update gradient failed."); + VGLITE_CHECK_ERROR(vg_lite_update_grad(&gradient)); grad_matrix = vg_lite_get_grad_matrix(&gradient); vg_lite_identity(grad_matrix); @@ -234,25 +219,19 @@ static void _vglite_draw_rect(const lv_area_t * coords, const lv_area_t * clip_a vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix); } - err = vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, VG_LITE_BLEND_SRC_OVER); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw gradient failed."); + VGLITE_CHECK_ERROR(vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, + VG_LITE_BLEND_SRC_OVER)); } else { - err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw rectangle failed."); + VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol)); } vglite_run(); - vglite_disable_scissor(); + VGLITE_CHECK_ERROR(vg_lite_clear_path(&path)); - err = vg_lite_clear_path(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed."); - - if(has_gradient) { - err = vg_lite_clear_grad(&gradient); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear gradient failed."); - } + if(has_gradient) + VGLITE_CHECK_ERROR(vg_lite_clear_grad(&gradient)); } #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_img.c b/src/draw/nxp/vglite/lv_draw_vglite_img.c index 58af218db..a95374904 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_img.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_img.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2020-2023 NXP + * Copyright 2020-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -26,7 +26,7 @@ * DEFINES *********************/ -#if VGLITE_BLIT_SPLIT_ENABLED +#if LV_USE_VGLITE_BLIT_SPLIT /** * BLIT split threshold - BLITs with width or height higher than this value will * be done in multiple steps. Value must be multiple of stride alignment in px. @@ -47,7 +47,7 @@ do { \ } while (0) #endif -#endif +#endif /*LV_USE_VGLITE_BLIT_SPLIT*/ /********************** * TYPEDEFS @@ -63,12 +63,13 @@ * * @param[in] dest_area Destination area with relative coordinates to dest buffer * @param[in] src_area Source area with relative coordinates to src buffer - * @param[in] opa Opacity + * @param[in] dsc Image descriptor * */ -static void _vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa); +static void _vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, + const lv_draw_image_dsc_t * dsc); -#if VGLITE_BLIT_SPLIT_ENABLED +#if LV_USE_VGLITE_BLIT_SPLIT /** * Move buffer pointer as close as possible to area, but with respect to alignment requirements. * @@ -91,26 +92,25 @@ static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stri * @param[in] src_area Source area with relative coordinates to src buffer * @param[in] src_stride Stride of source buffer in bytes * @param[in] src_cf Color format of source buffer - * @param[in] opa Opacity + * @param[in] dsc Image descriptor * */ static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t dest_stride, lv_color_format_t dest_cf, const void * src_buf, lv_area_t * src_area, uint32_t src_stride, lv_color_format_t src_cf, - lv_opa_t opa); + const lv_draw_image_dsc_t * dsc); #else /** * BLock Image Transfer - copy rectangular image from src_buf to dst_buf with transformation. * By default, image is copied directly, with optional opacity. * * @param[in] dest_area Area with relative coordinates to dest buffer - * @param[in] clip_area Clip area with relative coordinates to dest buffer * @param[in] src_area Source area with relative coordinates to src buffer * @param[in] dsc Image descriptor * */ -static void _vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * clip_area, - const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc); -#endif /*VGLITE_BLIT_SPLIT_ENABLED*/ +static void _vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * src_area, + const lv_draw_image_dsc_t * dsc); +#endif /*LV_USE_VGLITE_BLIT_SPLIT*/ /********************** * STATIC VARIABLES @@ -133,28 +133,28 @@ void lv_draw_vglite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * lv_layer_t * layer = draw_unit->target_layer; const lv_image_dsc_t * img_dsc = dsc->src; - lv_area_t rel_coords; - lv_area_copy(&rel_coords, coords); - lv_area_move(&rel_coords, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_t relative_coords; + lv_area_copy(&relative_coords, coords); + lv_area_move(&relative_coords, -layer->buf_area.x1, -layer->buf_area.y1); - lv_area_t rel_clip_area; - lv_area_copy(&rel_clip_area, draw_unit->clip_area); - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_t clip_area; + lv_area_copy(&clip_area, draw_unit->clip_area); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); lv_area_t blend_area; - bool has_transform = dsc->rotation != 0 || dsc->zoom != LV_SCALE_NONE; + bool has_transform = (dsc->rotation != 0 || dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE); if(has_transform) - lv_area_copy(&blend_area, &rel_coords); - else if(!_lv_area_intersect(&blend_area, &rel_coords, &rel_clip_area)) + lv_area_copy(&blend_area, &relative_coords); + else if(!_lv_area_intersect(&blend_area, &relative_coords, &clip_area)) return; /*Fully clipped, nothing to do*/ const void * src_buf = img_dsc->data; lv_area_t src_area; - src_area.x1 = blend_area.x1 - (coords->x1 - layer->draw_buf_ofs.x); - src_area.y1 = blend_area.y1 - (coords->y1 - layer->draw_buf_ofs.y); - src_area.x2 = src_area.x1 + lv_area_get_width(coords) - 1; - src_area.y2 = src_area.y1 + lv_area_get_height(coords) - 1; + src_area.x1 = blend_area.x1 - (coords->x1 - layer->buf_area.x1); + src_area.y1 = blend_area.y1 - (coords->y1 - layer->buf_area.y1); + src_area.x2 = img_dsc->header.w - 1; + src_area.y2 = img_dsc->header.h - 1; lv_color_format_t src_cf = img_dsc->header.cf; uint32_t src_stride = img_dsc->header.stride; @@ -162,86 +162,82 @@ void lv_draw_vglite_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * /* Set src_vgbuf structure. */ vglite_set_src_buf(src_buf, lv_area_get_width(&src_area), lv_area_get_height(&src_area), src_stride, src_cf); -#if VGLITE_BLIT_SPLIT_ENABLED - void * dest_buf = lv_draw_buf_get_buf(&layer->draw_buf); - uint32_t dest_stride = lv_draw_buf_get_stride(&layer->draw_buf); - lv_color_format_t dest_cf = layer->draw_buf.color_format; +#if LV_USE_VGLITE_BLIT_SPLIT + void * dest_buf = layer->buf; + uint32_t dest_stride = layer->buf_stride; + lv_color_format_t dest_cf = layer->color_format; if(!has_transform) _vglite_blit_split(dest_buf, &blend_area, dest_stride, dest_cf, - src_buf, &src_area, src_stride, src_cf, dsc->opa); + src_buf, &src_area, src_stride, src_cf, dsc); #else if(has_transform) - _vglite_blit_transform(&blend_area, &rel_clip_area, &src_area, dsc); + _vglite_blit_transform(&blend_area, &src_area, dsc); else - _vglite_blit_single(&blend_area, &src_area, dsc->opa); -#endif + _vglite_blit_single(&blend_area, &src_area, dsc); +#endif /*LV_USE_VGLITE_BLIT_SPLIT*/ } /********************** * STATIC FUNCTIONS **********************/ -static void _vglite_blit(const lv_area_t * src_area, lv_opa_t opa) +static void _vglite_blit(const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc) { - vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_buffer_t * dst_vgbuf = vglite_get_dest_buf(); vg_lite_buffer_t * src_vgbuf = vglite_get_src_buf(); - uint32_t rect[] = { - (uint32_t)src_area->x1, /* start x */ - (uint32_t)src_area->y1, /* start y */ - (uint32_t)lv_area_get_width(src_area), /* width */ - (uint32_t)lv_area_get_height(src_area) /* height */ + vg_lite_rectangle_t rect = { + .x = (vg_lite_int32_t)src_area->x1, + .y = (vg_lite_int32_t)src_area->y1, + .width = (vg_lite_int32_t)lv_area_get_width(src_area), + .height = (vg_lite_int32_t)lv_area_get_height(src_area) }; - uint32_t color; - vg_lite_blend_t blend; - if(opa >= (lv_opa_t)LV_OPA_MAX) { - color = 0xFFFFFFFFU; - blend = VG_LITE_BLEND_SRC_OVER; - src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; + src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; + src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; + + lv_color_t color; + lv_opa_t opa; + + bool has_recolor = (dsc->recolor_opa > LV_OPA_MIN); + if(has_recolor) { + color = dsc->recolor; + opa = LV_OPA_MIX2(dsc->recolor_opa, dsc->opa); } else { - if(vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - color = (opa << 24) | 0x00FFFFFFU; - } - else { - color = (opa << 24) | (opa << 16) | (opa << 8) | opa; - } - blend = VG_LITE_BLEND_SRC_OVER; - src_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; - src_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; + color.red = 0xFF; + color.green = 0xFF; + color.blue = 0xFF; + opa = dsc->opa; } - vg_lite_matrix_t * vgmatrix = vglite_get_matrix(); + lv_color32_t col32 = lv_color_to_32(color, opa); + vg_lite_color_t vgcol = vglite_get_color(col32, false); - err = vg_lite_blit_rect(dst_vgbuf, src_vgbuf, rect, vgmatrix, blend, color, VG_LITE_FILTER_POINT); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Blit rectangle failed."); + vg_lite_matrix_t * vgmatrix = vglite_get_matrix(); + vg_lite_blend_t vgblend = vglite_get_blend_mode(dsc->blend_mode); + + VGLITE_CHECK_ERROR(vg_lite_blit_rect(dst_vgbuf, src_vgbuf, &rect, vgmatrix, vgblend, vgcol, VG_LITE_FILTER_POINT)); vglite_run(); } -static void _vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, lv_opa_t opa) +static void _vglite_blit_single(const lv_area_t * dest_area, const lv_area_t * src_area, + const lv_draw_image_dsc_t * dsc) { - /* Set scissor. */ - vglite_set_scissor(dest_area); - /* Set vgmatrix. */ vglite_set_translation_matrix(dest_area); /* Start blit. */ - _vglite_blit(src_area, opa); - - /* Disable scissor. */ - vglite_disable_scissor(); + _vglite_blit(src_area, dsc); } -#if VGLITE_BLIT_SPLIT_ENABLED +#if LV_USE_VGLITE_BLIT_SPLIT static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stride, lv_color_format_t cf) { uint8_t ** buf_u8 = (uint8_t **)buf; uint8_t align_bytes = vglite_get_alignment(cf); - uint8_t bits_per_pixel = vglite_get_px_size(cf); + uint8_t bits_per_pixel = lv_color_format_get_bpp(cf); uint16_t align_pixels = align_bytes * 8 / bits_per_pixel; @@ -264,7 +260,7 @@ static void _move_buf_close_to_area(void ** buf, lv_area_t * area, uint32_t stri static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t dest_stride, lv_color_format_t dest_cf, const void * src_buf, lv_area_t * src_area, uint32_t src_stride, lv_color_format_t src_cf, - lv_opa_t opa) + const lv_draw_image_dsc_t * dsc) { VGLITE_TRACE("Blit " "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " @@ -288,7 +284,7 @@ static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t vglite_set_dest_buf_ptr(dest_buf); vglite_set_src_buf_ptr(src_buf); - _vglite_blit_single(dest_area, src_area, opa); + _vglite_blit_single(dest_area, src_area, dsc); VGLITE_TRACE("Single " "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " @@ -355,8 +351,8 @@ static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t tile_dest_area.x1 = shift_dest_x; if(x > 0) { /* Advance start pointer for every tile, except the first raw (x = 0) */ - tile_src_buf += VGLITE_BLIT_SPLIT_THR * vglite_get_px_size(src_cf) / 8; - tile_dest_buf += VGLITE_BLIT_SPLIT_THR * vglite_get_px_size(dest_cf) / 8; + tile_src_buf += VGLITE_BLIT_SPLIT_THR * lv_color_format_get_bpp(src_cf) / 8; + tile_dest_buf += VGLITE_BLIT_SPLIT_THR * lv_color_format_get_bpp(dest_cf) / 8; } /* Calculate x2 coordinates */ @@ -375,7 +371,7 @@ static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t vglite_set_dest_buf_ptr(tile_dest_buf); vglite_set_src_buf_ptr(tile_src_buf); - _vglite_blit_single(&tile_dest_area, &tile_src_area, opa); + _vglite_blit_single(&tile_dest_area, &tile_src_area, dsc); VGLITE_TRACE("Tile [%d, %d] " "Area: ([%d,%d], [%d,%d]) -> ([%d,%d], [%d,%d]) | " @@ -391,21 +387,15 @@ static void _vglite_blit_split(void * dest_buf, lv_area_t * dest_area, uint32_t } } #else -static void _vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * clip_area, - const lv_area_t * src_area, const lv_draw_image_dsc_t * dsc) +static void _vglite_blit_transform(const lv_area_t * dest_area, const lv_area_t * src_area, + const lv_draw_image_dsc_t * dsc) { - /* Set scissor. */ - vglite_set_scissor(clip_area); - /* Set vgmatrix. */ vglite_set_transformation_matrix(dest_area, dsc); /* Start blit. */ - _vglite_blit(src_area, dsc->opa); - - /* Disable scissor. */ - vglite_disable_scissor(); + _vglite_blit(src_area, dsc); } -#endif /*VGLITE_BLIT_SPLIT_ENABLED*/ +#endif /*LV_USE_VGLITE_BLIT_SPLIT*/ #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_label.c b/src/draw/nxp/vglite/lv_draw_vglite_label.c index 52af6bc24..587f55f79 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_label.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_label.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -40,17 +40,12 @@ static void _draw_vglite_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t /** * Draw letter (character bitmap blend) with optional color and opacity * - * @param[in] dest_area Area with relative coordinates of destination buffer - * @param[in] mask_buf Mask buffer * @param[in] mask_area Mask area with relative coordinates of source buffer - * @param[in] mask_stride Stride of mask buffer in bytes * @param[in] color Color * @param[in] opa Opacity * */ -static void _vglite_draw_letter(const lv_area_t * dest_area, - const void * mask_buf, const lv_area_t * mask_area, uint32_t mask_stride, - lv_color_t color, lv_opa_t opa); +static void _vglite_draw_letter(const lv_area_t * mask_area, lv_color_t color, lv_opa_t opa); /********************** * STATIC VARIABLES @@ -105,24 +100,20 @@ static void _draw_vglite_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t lv_area_t blend_area; if(!_lv_area_intersect(&blend_area, glyph_draw_dsc->letter_coords, draw_unit->clip_area)) return; - lv_area_move(&blend_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_move(&blend_area, -layer->buf_area.x1, -layer->buf_area.y1); const lv_draw_buf_t * draw_buf = glyph_draw_dsc->glyph_data; - const uint8_t * mask_buf = draw_buf->data; - lv_area_t mask_area; - lv_area_copy(&mask_area, glyph_draw_dsc->letter_coords); - lv_area_move(&mask_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + const void * mask_buf = draw_buf->data; - /** - * @todo check if we can use draw_buf->header.stride directly. - */ - uint32_t mask_stride = lv_draw_buf_width_to_stride( - lv_area_get_width(glyph_draw_dsc->letter_coords), - LV_COLOR_FORMAT_A8); - if(mask_buf) { - mask_buf += mask_stride * (blend_area.y1 - glyph_draw_dsc->letter_coords->y1) + - (blend_area.x1 - glyph_draw_dsc->letter_coords->x1); - } + uint32_t mask_width = lv_area_get_width(glyph_draw_dsc->letter_coords); + uint32_t mask_height = lv_area_get_height(glyph_draw_dsc->letter_coords); + uint32_t mask_stride = draw_buf->header.stride; + + lv_area_t mask_area; + mask_area.x1 = blend_area.x1 - (glyph_draw_dsc->letter_coords->x1 - layer->buf_area.x1); + mask_area.y1 = blend_area.y1 - (glyph_draw_dsc->letter_coords->y1 - layer->buf_area.y1); + mask_area.x2 = mask_width - 1; + mask_area.y2 = mask_height - 1; if(!vglite_buf_aligned(mask_buf, mask_stride, LV_COLOR_FORMAT_A8)) { /* Draw a placeholder rectangle*/ @@ -134,9 +125,15 @@ static void _draw_vglite_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t lv_draw_vglite_border(draw_unit, &border_draw_dsc, glyph_draw_dsc->bg_coords); } else { + /* Set src_vgbuf structure. */ + vglite_set_src_buf(mask_buf, mask_width, mask_height, mask_stride, LV_COLOR_FORMAT_A8); - _vglite_draw_letter(&blend_area, mask_buf, &mask_area, mask_stride, - glyph_draw_dsc->color, glyph_draw_dsc->opa); + /* Set vgmatrix. */ + vglite_set_translation_matrix(&blend_area); + + lv_draw_buf_invalidate_cache((void *)mask_buf, mask_stride, LV_COLOR_FORMAT_A8, &mask_area); + + _vglite_draw_letter(&mask_area, glyph_draw_dsc->color, glyph_draw_dsc->opa); } } else if(glyph_draw_dsc->format == LV_DRAW_LETTER_BITMAP_FORMAT_IMAGE) { @@ -157,46 +154,29 @@ static void _draw_vglite_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t } } -static void _vglite_draw_letter(const lv_area_t * dest_area, - const void * mask_buf, const lv_area_t * mask_area, uint32_t mask_stride, - lv_color_t color, lv_opa_t opa) +static void _vglite_draw_letter(const lv_area_t * mask_area, lv_color_t color, lv_opa_t opa) { - vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_buffer_t * dst_vgbuf = vglite_get_dest_buf(); + vg_lite_buffer_t * mask_vgbuf = vglite_get_src_buf(); - vg_lite_buffer_t mask_vgbuf; - mask_vgbuf.format = VG_LITE_A8; - mask_vgbuf.tiled = VG_LITE_LINEAR; - mask_vgbuf.image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; - mask_vgbuf.transparency_mode = VG_LITE_IMAGE_TRANSPARENT; - mask_vgbuf.width = (int32_t)lv_area_get_width(mask_area); - mask_vgbuf.height = (int32_t)lv_area_get_height(mask_area); - mask_vgbuf.stride = (int32_t)mask_stride; + mask_vgbuf->image_mode = VG_LITE_MULTIPLY_IMAGE_MODE; + mask_vgbuf->transparency_mode = VG_LITE_IMAGE_TRANSPARENT; - lv_memzero(&mask_vgbuf.yuv, sizeof(mask_vgbuf.yuv)); - - mask_vgbuf.memory = (void *)mask_buf; - mask_vgbuf.address = (uint32_t)mask_vgbuf.memory; - mask_vgbuf.handle = NULL; - - uint32_t rect[] = { - (uint32_t)0, /* start x */ - (uint32_t)0, /* start y */ - (uint32_t)lv_area_get_width(mask_area), /* width */ - (uint32_t)lv_area_get_height(mask_area) /* height */ + vg_lite_rectangle_t rect = { + .x = (vg_lite_int32_t)mask_area->x1, + .y = (vg_lite_int32_t)mask_area->y1, + .width = (vg_lite_int32_t)lv_area_get_width(mask_area), + .height = (vg_lite_int32_t)lv_area_get_height(mask_area) }; lv_color32_t col32 = lv_color_to_32(color, opa); vg_lite_color_t vgcol = vglite_get_color(col32, false); - /* Set vgmatrix. */ - vglite_set_translation_matrix(dest_area); vg_lite_matrix_t * vgmatrix = vglite_get_matrix(); /*Blit with font color as paint color*/ - err = vg_lite_blit_rect(dst_vgbuf, &mask_vgbuf, rect, vgmatrix, VG_LITE_BLEND_SRC_OVER, vgcol, - VG_LITE_FILTER_POINT); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw letter failed."); + VGLITE_CHECK_ERROR(vg_lite_blit_rect(dst_vgbuf, mask_vgbuf, &rect, vgmatrix, VG_LITE_BLEND_SRC_OVER, vgcol, + VG_LITE_FILTER_POINT)); vglite_run(); } diff --git a/src/draw/nxp/vglite/lv_draw_vglite_layer.c b/src/draw/nxp/vglite/lv_draw_vglite_layer.c index 85af7c481..5f7b46528 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_layer.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_layer.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2023 NXP + * Copyright 2023-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -18,6 +18,9 @@ #if LV_USE_DRAW_VGLITE #include "../../../stdlib/lv_string.h" +#if LV_USE_PARALLEL_DRAW_DEBUG + #include "../../../core/lv_global.h" +#endif /********************* * DEFINES @@ -35,6 +38,10 @@ * STATIC VARIABLES **********************/ +#if LV_USE_PARALLEL_DRAW_DEBUG + #define _draw_info LV_GLOBAL_DEFAULT()->draw_info +#endif + /********************** * MACROS **********************/ @@ -50,20 +57,112 @@ void lv_draw_vglite_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t /*It can happen that nothing was draw on a layer and therefore its buffer is not allocated. *In this case just return. */ - if(layer_to_draw->draw_buf.buf == NULL) + if(layer_to_draw->buf == NULL) return; - lv_image_dsc_t img_dsc = { 0 }; - img_dsc.header.w = layer_to_draw->draw_buf.width; - img_dsc.header.h = layer_to_draw->draw_buf.height; - img_dsc.header.cf = layer_to_draw->draw_buf.color_format; - img_dsc.data = lv_draw_buf_get_buf(&layer_to_draw->draw_buf); + uint32_t width = lv_area_get_width(&layer_to_draw->buf_area); + uint32_t height = lv_area_get_height(&layer_to_draw->buf_area); + const lv_area_t area = { + .x1 = 0, + .y1 = 0, + .x2 = width - 1, + .y2 = height - 1 + }; + lv_draw_buf_invalidate_cache(layer_to_draw->buf, layer_to_draw->buf_stride, layer_to_draw->color_format, &area); + + lv_image_dsc_t img_dsc = {0}; + img_dsc.header.w = width; + img_dsc.header.h = height; + img_dsc.header.cf = layer_to_draw->color_format; + img_dsc.header.stride = layer_to_draw->buf_stride; + img_dsc.data = layer_to_draw->buf; lv_draw_image_dsc_t new_draw_dsc; lv_memcpy(&new_draw_dsc, draw_dsc, sizeof(lv_draw_image_dsc_t)); new_draw_dsc.src = &img_dsc; lv_draw_vglite_img(draw_unit, &new_draw_dsc, coords); + +#if LV_USE_LAYER_DEBUG || LV_USE_PARALLEL_DRAW_DEBUG + lv_area_t area_rot; + lv_area_copy(&area_rot, coords); + bool has_transform = (draw_dsc->rotation != 0 || draw_dsc->scale_x != LV_SCALE_NONE || + draw_dsc->scale_y != LV_SCALE_NONE); + + if(has_transform) { + int32_t w = lv_area_get_width(coords); + int32_t h = lv_area_get_height(coords); + + _lv_image_buf_get_transformed_area(&area_rot, w, h, draw_dsc->rotation, draw_dsc->scale_x, draw_dsc->scale_y, + &draw_dsc->pivot); + + area_rot.x1 += coords->x1; + area_rot.y1 += coords->y1; + area_rot.x2 += coords->x1; + area_rot.y2 += coords->y1; + } + lv_area_t draw_area; + if(!_lv_area_intersect(&draw_area, &area_rot, draw_unit->clip_area)) return; +#endif + +#if LV_USE_LAYER_DEBUG + lv_draw_fill_dsc_t fill_dsc; + lv_draw_fill_dsc_init(&fill_dsc); + fill_dsc.color = lv_color_hex(layer_to_draw->color_format == LV_COLOR_FORMAT_ARGB8888 ? 0xff0000 : 0x00ff00); + fill_dsc.opa = LV_OPA_20; + lv_draw_sw_fill(draw_unit, &fill_dsc, &area_rot); + + lv_draw_border_dsc_t border_dsc; + lv_draw_border_dsc_init(&border_dsc); + border_dsc.color = fill_dsc.color; + border_dsc.opa = LV_OPA_60; + border_dsc.width = 2; + lv_draw_sw_border(draw_unit, &border_dsc, &area_rot); + +#endif + +#if LV_USE_PARALLEL_DRAW_DEBUG + uint32_t idx = 0; + lv_draw_unit_t * draw_unit_tmp = _draw_info.unit_head; + while(draw_unit_tmp != draw_unit) { + draw_unit_tmp = draw_unit_tmp->next; + idx++; + } + + lv_draw_fill_dsc_t fill_dsc; + lv_draw_rect_dsc_init(&fill_dsc); + fill_dsc.color = lv_palette_main(idx % _LV_PALETTE_LAST); + fill_dsc.opa = LV_OPA_10; + lv_draw_sw_fill(draw_unit, &fill_dsc, &area_rot); + + lv_draw_border_dsc_t border_dsc; + lv_draw_border_dsc_init(&border_dsc); + border_dsc.color = lv_palette_main(idx % _LV_PALETTE_LAST); + border_dsc.opa = LV_OPA_100; + border_dsc.width = 2; + lv_draw_sw_border(draw_unit, &border_dsc, &area_rot); + + lv_point_t txt_size; + lv_text_get_size(&txt_size, "W", LV_FONT_DEFAULT, 0, 0, 100, LV_TEXT_FLAG_NONE); + + lv_area_t txt_area; + txt_area.x1 = draw_area.x1; + txt_area.x2 = draw_area.x1 + txt_size.x - 1; + txt_area.y2 = draw_area.y2; + txt_area.y1 = draw_area.y2 - txt_size.y + 1; + + lv_draw_fill_dsc_init(&fill_dsc); + fill_dsc.color = lv_color_black(); + lv_draw_sw_fill(draw_unit, &fill_dsc, &txt_area); + + char buf[8]; + lv_snprintf(buf, sizeof(buf), "%d", idx); + lv_draw_label_dsc_t label_dsc; + lv_draw_label_dsc_init(&label_dsc); + label_dsc.color = lv_color_white(); + label_dsc.text = buf; + lv_draw_sw_label(draw_unit, &label_dsc, &txt_area); +#endif } #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_line.c b/src/draw/nxp/vglite/lv_draw_vglite_line.c index cae4bbd52..d458375c5 100644 --- a/src/draw/nxp/vglite/lv_draw_vglite_line.c +++ b/src/draw/nxp/vglite/lv_draw_vglite_line.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2022, 2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -36,7 +36,7 @@ * * @param[in] point1 Starting point with relative coordinates * @param[in] point2 Ending point with relative coordinates - * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] clip_area Clip area with relative coordinates to dest buff * @param[in] dsc Line description structure (width, rounded ending, opacity, ...) * */ @@ -65,21 +65,21 @@ void lv_draw_vglite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * return; lv_layer_t * layer = draw_unit->target_layer; - lv_area_t rel_clip_area; - rel_clip_area.x1 = LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width / 2; - rel_clip_area.x2 = LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width / 2; - rel_clip_area.y1 = LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width / 2; - rel_clip_area.y2 = LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width / 2; + lv_area_t clip_area; + clip_area.x1 = LV_MIN(dsc->p1.x, dsc->p2.x) - dsc->width / 2; + clip_area.x2 = LV_MAX(dsc->p1.x, dsc->p2.x) + dsc->width / 2; + clip_area.y1 = LV_MIN(dsc->p1.y, dsc->p2.y) - dsc->width / 2; + clip_area.y2 = LV_MAX(dsc->p1.y, dsc->p2.y) + dsc->width / 2; - if(!_lv_area_intersect(&rel_clip_area, &rel_clip_area, draw_unit->clip_area)) + if(!_lv_area_intersect(&clip_area, &clip_area, draw_unit->clip_area)) return; /*Fully clipped, nothing to do*/ - lv_area_move(&rel_clip_area, -layer->draw_buf_ofs.x, -layer->draw_buf_ofs.y); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); - lv_point_t rel_point1 = {dsc->p1.x - layer->draw_buf_ofs.x, dsc->p1.y - layer->draw_buf_ofs.y}; - lv_point_t rel_point2 = {dsc->p2.x - layer->draw_buf_ofs.x, dsc->p2.y - layer->draw_buf_ofs.y}; + lv_point_t point1 = {dsc->p1.x - layer->buf_area.x1, dsc->p1.y - layer->buf_area.y1}; + lv_point_t point2 = {dsc->p2.x - layer->buf_area.x1, dsc->p2.y - layer->buf_area.y1}; - _vglite_draw_line(&rel_point1, &rel_point2, &rel_clip_area, dsc); + _vglite_draw_line(&point1, &point2, &clip_area, dsc); } /********************** @@ -89,7 +89,6 @@ void lv_draw_vglite_line(lv_draw_unit_t * draw_unit, const lv_draw_line_dsc_t * static void _vglite_draw_line(const lv_point_t * point1, const lv_point_t * point2, const lv_area_t * clip_area, const lv_draw_line_dsc_t * dsc) { - vg_lite_error_t err = VG_LITE_SUCCESS; vg_lite_path_t path; vg_lite_buffer_t * vgbuf = vglite_get_dest_buf(); vg_lite_cap_style_t cap_style = (dsc->round_start || dsc->round_end) ? VG_LITE_CAP_ROUND : VG_LITE_CAP_BUTT; @@ -107,8 +106,7 @@ static void _vglite_draw_line(const lv_point_t * point1, const lv_point_t * poin stroke_dash_phase = (vg_lite_float_t)dsc->dash_width / 2; } - /* Choose vglite blend mode based on given lvgl blend mode */ - vg_lite_blend_t vglite_blend_mode = vglite_get_blend_mode(dsc->blend_mode); + vg_lite_blend_t vgblend = vglite_get_blend_mode(dsc->blend_mode); /*** Init path ***/ int32_t width = dsc->width; @@ -119,10 +117,9 @@ static void _vglite_draw_line(const lv_point_t * point1, const lv_point_t * poin VLC_OP_END }; - err = vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(line_path), line_path, - (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, - ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Init path failed."); + VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(line_path), line_path, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f)); lv_color32_t col32 = lv_color_to_32(dsc->color, dsc->opa); vg_lite_color_t vgcol = vglite_get_color(col32, false); @@ -131,27 +128,18 @@ static void _vglite_draw_line(const lv_point_t * point1, const lv_point_t * poin vg_lite_identity(&matrix); /*** Draw line ***/ - err = vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set draw path type failed."); + VGLITE_CHECK_ERROR(vg_lite_set_draw_path_type(&path, VG_LITE_DRAW_STROKE_PATH)); - err = vg_lite_set_stroke(&path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count, - stroke_dash_phase, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Set stroke failed."); + VGLITE_CHECK_ERROR(vg_lite_set_stroke(&path, cap_style, join_style, width, 8, stroke_dash_pattern, stroke_dash_count, + stroke_dash_phase, vgcol)); - err = vg_lite_update_stroke(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Update stroke failed."); + VGLITE_CHECK_ERROR(vg_lite_update_stroke(&path)); - vglite_set_scissor(clip_area); - - err = vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vglite_blend_mode, vgcol); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Draw line failed."); + VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_NON_ZERO, &matrix, vgblend, vgcol)); vglite_run(); - vglite_disable_scissor(); - - err = vg_lite_clear_path(&path); - LV_ASSERT_MSG(err == VG_LITE_SUCCESS, "Clear path failed."); + VGLITE_CHECK_ERROR(vg_lite_clear_path(&path)); } #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_draw_vglite_triangle.c b/src/draw/nxp/vglite/lv_draw_vglite_triangle.c new file mode 100644 index 000000000..0de169dc0 --- /dev/null +++ b/src/draw/nxp/vglite/lv_draw_vglite_triangle.c @@ -0,0 +1,179 @@ +/** + * @file lv_draw_vglite_triangle.c + * + */ + +/** + * Copyright 2023-2024 NXP + * + * SPDX-License-Identifier: MIT + */ + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_vglite.h" + +#if LV_USE_DRAW_VGLITE +#include "lv_vglite_buf.h" +#include "lv_vglite_path.h" +#include "lv_vglite_utils.h" + +#include "../../../stdlib/lv_string.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +/********************** + * STATIC PROTOTYPES + **********************/ + +/** + * Draw triangle shape with effects (opacity, gradient) + * + * @param[in] coords Coordinates of the triangle (relative to dest buff) + * @param[in] clip_area Clipping area with relative coordinates to dest buff + * @param[in] dsc Description of the triangle + * + */ +static void _vglite_draw_triangle(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_triangle_dsc_t * dsc); + +/********************** + * STATIC VARIABLES + **********************/ + +/********************** + * MACROS + **********************/ + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +void lv_draw_vglite_triangle(lv_draw_unit_t * draw_unit, const lv_draw_triangle_dsc_t * dsc) +{ + if(dsc->bg_opa <= (lv_opa_t)LV_OPA_MIN) + return; + + lv_layer_t * layer = draw_unit->target_layer; + lv_area_t clip_area; + lv_area_copy(&clip_area, draw_unit->clip_area); + lv_area_move(&clip_area, -layer->buf_area.x1, -layer->buf_area.y1); + + lv_area_t coords; + coords.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x); + coords.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y); + coords.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x); + coords.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y); + + lv_area_move(&coords, -layer->buf_area.x1, -layer->buf_area.y1); + + lv_area_t clipped_coords; + if(!_lv_area_intersect(&clipped_coords, &coords, &clip_area)) + return; /* Fully clipped, nothing to do */ + + _vglite_draw_triangle(&coords, &clip_area, dsc); +} + +/********************** + * STATIC FUNCTIONS + **********************/ + +static void _vglite_draw_triangle(const lv_area_t * coords, const lv_area_t * clip_area, + const lv_draw_triangle_dsc_t * dsc) +{ + vg_lite_buffer_t * vgbuf = vglite_get_dest_buf(); + + lv_area_t tri_area; + tri_area.x1 = (int32_t)LV_MIN3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x); + tri_area.y1 = (int32_t)LV_MIN3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y); + tri_area.x2 = (int32_t)LV_MAX3(dsc->p[0].x, dsc->p[1].x, dsc->p[2].x); + tri_area.y2 = (int32_t)LV_MAX3(dsc->p[0].y, dsc->p[1].y, dsc->p[2].y); + + uint32_t width = tri_area.x2 - tri_area.x1; + uint32_t height = tri_area.y2 - tri_area.y1; + + /* Init path */ + int32_t triangle_path[] = { /*VG line path*/ + VLC_OP_MOVE, dsc->p[0].x, dsc->p[0].y, + VLC_OP_LINE, dsc->p[1].x, dsc->p[1].y, + VLC_OP_LINE, dsc->p[2].x, dsc->p[2].y, + VLC_OP_LINE, dsc->p[0].x, dsc->p[0].y, + VLC_OP_END + }; + + vg_lite_path_t path; + VGLITE_CHECK_ERROR(vg_lite_init_path(&path, VG_LITE_S32, VG_LITE_HIGH, sizeof(triangle_path), triangle_path, + (vg_lite_float_t)clip_area->x1, (vg_lite_float_t)clip_area->y1, + ((vg_lite_float_t)clip_area->x2) + 1.0f, ((vg_lite_float_t)clip_area->y2) + 1.0f)); + + vg_lite_matrix_t matrix; + vg_lite_identity(&matrix); + + /* Init Color */ + lv_color32_t col32 = lv_color_to_32(dsc->bg_color, dsc->bg_opa); + vg_lite_color_t vgcol = vglite_get_color(col32, false); + + vg_lite_linear_gradient_t gradient; + bool has_gradient = (dsc->bg_grad.dir != (lv_grad_dir_t)LV_GRAD_DIR_NONE); + + /* Init Gradient*/ + if(has_gradient) { + vg_lite_matrix_t * grad_matrix; + + vg_lite_uint32_t colors[LV_GRADIENT_MAX_STOPS]; + vg_lite_uint32_t stops[LV_GRADIENT_MAX_STOPS]; + lv_color32_t col32[LV_GRADIENT_MAX_STOPS]; + + /* Gradient Setup */ + vg_lite_uint32_t cnt = LV_MAX(dsc->bg_grad.stops_count, LV_GRADIENT_MAX_STOPS); + for(uint8_t i = 0; i < cnt; i++) { + stops[i] = dsc->bg_grad.stops[i].frac; + + col32[i] = lv_color_to_32(dsc->bg_grad.stops[i].color, dsc->bg_grad.stops[i].opa); + colors[i] = vglite_get_color(col32[i], true); + } + + lv_memzero(&gradient, sizeof(vg_lite_linear_gradient_t)); + + VGLITE_CHECK_ERROR(vg_lite_init_grad(&gradient)); + + VGLITE_CHECK_ERROR(vg_lite_set_grad(&gradient, cnt, colors, stops)); + + VGLITE_CHECK_ERROR(vg_lite_update_grad(&gradient)); + + grad_matrix = vg_lite_get_grad_matrix(&gradient); + vg_lite_identity(grad_matrix); + vg_lite_translate((float)coords->x1, (float)coords->y1, grad_matrix); + + if(dsc->bg_grad.dir == (lv_grad_dir_t)LV_GRAD_DIR_VER) { + vg_lite_scale(1.0f, (float)height / 256.0f, grad_matrix); + vg_lite_rotate(90.0f, grad_matrix); + } + else { /*LV_GRAD_DIR_HOR*/ + vg_lite_scale((float)width / 256.0f, 1.0f, grad_matrix); + } + + VGLITE_CHECK_ERROR(vg_lite_draw_gradient(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, &gradient, + VG_LITE_BLEND_SRC_OVER)); + } + else { + VGLITE_CHECK_ERROR(vg_lite_draw(vgbuf, &path, VG_LITE_FILL_EVEN_ODD, &matrix, VG_LITE_BLEND_SRC_OVER, vgcol)); + } + + vglite_run(); + + VGLITE_CHECK_ERROR(vg_lite_clear_path(&path)); + + if(has_gradient) + VGLITE_CHECK_ERROR(vg_lite_clear_grad(&gradient)); +} + +#endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/draw/nxp/vglite/lv_vglite_buf.c b/src/draw/nxp/vglite/lv_vglite_buf.c index 4dc6217c3..a72c8e554 100644 --- a/src/draw/nxp/vglite/lv_vglite_buf.c +++ b/src/draw/nxp/vglite/lv_vglite_buf.c @@ -69,20 +69,20 @@ void vglite_set_src_buf_ptr(const void * buf) _set_vgbuf_ptr(&_src_vgbuf, (void *)buf); } -void vglite_set_dest_buf(const lv_draw_buf_t * draw_buf) +void vglite_set_dest_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride, + lv_color_format_t cf) { - vglite_set_buf(&_dest_vgbuf, draw_buf->buf, draw_buf->width, draw_buf->height, - lv_draw_buf_get_stride(draw_buf), draw_buf->color_format); + vglite_set_buf(&_dest_vgbuf, (void *)buf, width, height, stride, cf); } -void vglite_set_src_buf(const void * buf, int32_t width, int32_t height, uint32_t stride, +void vglite_set_src_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride, lv_color_format_t cf) { vglite_set_buf(&_src_vgbuf, (void *)buf, width, height, stride, cf); } void vglite_set_buf(vg_lite_buffer_t * vgbuf, void * buf, - int32_t width, int32_t height, uint32_t stride, + uint32_t width, uint32_t height, uint32_t stride, lv_color_format_t cf) { vg_lite_buffer_format_t vgformat = vglite_get_buf_format(cf); diff --git a/src/draw/nxp/vglite/lv_vglite_buf.h b/src/draw/nxp/vglite/lv_vglite_buf.h index 97529a5d2..3ef434748 100644 --- a/src/draw/nxp/vglite/lv_vglite_buf.h +++ b/src/draw/nxp/vglite/lv_vglite_buf.h @@ -71,12 +71,17 @@ void vglite_set_dest_buf_ptr(void * buf); void vglite_set_src_buf_ptr(const void * buf); /** - * Set vglite target (destination) buffer. + * Set vglite destination buffer. * - * @param[in] draw_buf Destination draw buffer descriptor + * @param[in] buf Destination buffer address + * @param[in] width Destination buffer width + * @param[in] height Destination buffer height + * @param[in] stride Destination buffer stride in bytes + * @param[in] cf Destination buffer color format * */ -void vglite_set_dest_buf(const lv_draw_buf_t * draw_buf); +void vglite_set_dest_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride, + lv_color_format_t cf); /** * Set vglite source buffer. @@ -88,7 +93,7 @@ void vglite_set_dest_buf(const lv_draw_buf_t * draw_buf); * @param[in] cf Source buffer color format * */ -void vglite_set_src_buf(const void * buf, int32_t width, int32_t height, uint32_t stride, +void vglite_set_src_buf(const void * buf, uint32_t width, uint32_t height, uint32_t stride, lv_color_format_t cf); /** @@ -103,7 +108,7 @@ void vglite_set_src_buf(const void * buf, int32_t width, int32_t height, uint32_ * */ void vglite_set_buf(vg_lite_buffer_t * vgbuf, void * buf, - int32_t width, int32_t height, uint32_t stride, + uint32_t width, uint32_t height, uint32_t stride, lv_color_format_t cf); /********************** diff --git a/src/draw/nxp/vglite/lv_vglite_matrix.c b/src/draw/nxp/vglite/lv_vglite_matrix.c index 8d41e8b60..3076c6c91 100644 --- a/src/draw/nxp/vglite/lv_vglite_matrix.c +++ b/src/draw/nxp/vglite/lv_vglite_matrix.c @@ -58,15 +58,16 @@ void vglite_set_transformation_matrix(const lv_area_t * dest_area, const lv_draw { vglite_set_translation_matrix(dest_area); - bool has_scale = (dsc->zoom != LV_SCALE_NONE); + bool has_scale = (dsc->scale_x != LV_SCALE_NONE || dsc->scale_y != LV_SCALE_NONE); bool has_rotation = (dsc->rotation != 0); vg_lite_translate(dsc->pivot.x, dsc->pivot.y, &_vgmatrix); if(has_rotation) vg_lite_rotate(dsc->rotation / 10.0f, &_vgmatrix); /* angle is 1/10 degree */ if(has_scale) { - vg_lite_float_t scale = 1.0f * dsc->zoom / LV_SCALE_NONE; - vg_lite_scale(scale, scale, &_vgmatrix); + vg_lite_float_t scale_x = 1.0f * dsc->scale_x / LV_SCALE_NONE; + vg_lite_float_t scale_y = 1.0f * dsc->scale_y / LV_SCALE_NONE; + vg_lite_scale(scale_x, scale_y, &_vgmatrix); } vg_lite_translate(0.0f - dsc->pivot.x, 0.0f - dsc->pivot.y, &_vgmatrix); } diff --git a/src/draw/nxp/vglite/lv_vglite_utils.c b/src/draw/nxp/vglite/lv_vglite_utils.c index 17201fc69..7e923cefc 100644 --- a/src/draw/nxp/vglite/lv_vglite_utils.c +++ b/src/draw/nxp/vglite/lv_vglite_utils.c @@ -4,7 +4,7 @@ */ /** - * Copyright 2022, 2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -20,10 +20,6 @@ #include "../../../core/lv_refr.h" -#if LV_USE_OS - #include "vg_lite_gpu.h" -#endif - /********************* * DEFINES *********************/ @@ -40,7 +36,7 @@ * STATIC VARIABLES **********************/ -#if LV_USE_OS +#if LV_USE_VGLITE_DRAW_ASYNC static volatile bool _cmd_buf_flushed = false; #endif @@ -52,7 +48,29 @@ * GLOBAL FUNCTIONS **********************/ -#if LV_USE_OS +const char * vglite_error_to_string(vg_lite_error_t error) +{ + switch(error) { + ENUM_TO_STRING(VG_LITE_SUCCESS); + ENUM_TO_STRING(VG_LITE_INVALID_ARGUMENT); + ENUM_TO_STRING(VG_LITE_OUT_OF_MEMORY); + ENUM_TO_STRING(VG_LITE_NO_CONTEXT); + ENUM_TO_STRING(VG_LITE_TIMEOUT); + ENUM_TO_STRING(VG_LITE_OUT_OF_RESOURCES); + ENUM_TO_STRING(VG_LITE_GENERIC_IO); + ENUM_TO_STRING(VG_LITE_NOT_SUPPORT); + ENUM_TO_STRING(VG_LITE_ALREADY_EXISTS); + ENUM_TO_STRING(VG_LITE_NOT_ALIGNED); + ENUM_TO_STRING(VG_LITE_FLEXA_TIME_OUT); + ENUM_TO_STRING(VG_LITE_FLEXA_HANDSHAKE_FAIL); + default: + break; + } + + return "VG_LITE_UKNOWN_ERROR"; +} + +#if LV_USE_VGLITE_DRAW_ASYNC bool vglite_cmd_buf_is_flushed(void) { return _cmd_buf_flushed; @@ -61,10 +79,12 @@ bool vglite_cmd_buf_is_flushed(void) void vglite_run(void) { -#if LV_USE_OS - vg_lite_gpu_state_t gpu_state = vg_lite_get_gpu_state(); +#if LV_USE_VGLITE_DRAW_ASYNC + vg_lite_uint32_t gpu_idle = 0; - if(gpu_state == VG_LITE_GPU_BUSY) { + VGLITE_CHECK_ERROR(vg_lite_get_parameter(VG_LITE_GPU_IDLE_STATE, 1, (vg_lite_pointer)&gpu_idle)); + + if(!gpu_idle) { _cmd_buf_flushed = false; return; @@ -72,15 +92,15 @@ void vglite_run(void) #endif /* - * For multithreading version (with OS), we simply flush the command buffer - * and the vglite draw thread will signal the dispatcher for completed tasks. - * Without OS, we process the tasks and signal them as complete one by one. + * If LV_USE_VGLITE_DRAW_ASYNC is enabled, simply flush the command buffer and the + * vglite draw thread will signal asynchronous the dispatcher for completed tasks. + * Without draw async, process the tasks and signal them as complete one by one. */ -#if LV_USE_OS - LV_ASSERT_MSG(vg_lite_flush() == VG_LITE_SUCCESS, "Flush failed."); +#if LV_USE_VGLITE_DRAW_ASYNC + VGLITE_CHECK_ERROR(vg_lite_flush()); _cmd_buf_flushed = true; #else - LV_ASSERT_MSG(vg_lite_finish() == VG_LITE_SUCCESS, "Finish failed."); + VGLITE_CHECK_ERROR(vg_lite_finish()); #endif } @@ -88,12 +108,10 @@ vg_lite_color_t vglite_get_color(lv_color32_t lv_col32, bool gradient) { vg_lite_color_t vg_col32; - /* Only pre-multiply color if hardware pre-multiplication is not present */ - if(!vg_lite_query_feature(gcFEATURE_BIT_VG_PE_PREMULTIPLY)) { - lv_col32.red = (uint8_t)((lv_col32.red * lv_col32.alpha) >> 8); - lv_col32.green = (uint8_t)((lv_col32.green * lv_col32.alpha) >> 8); - lv_col32.blue = (uint8_t)((lv_col32.blue * lv_col32.alpha) >> 8); - } + /* Pre-multiply alpha */ + lv_col32.red = LV_UDIV255(lv_col32.red * lv_col32.alpha); + lv_col32.green = LV_UDIV255(lv_col32.green * lv_col32.alpha); + lv_col32.blue = LV_UDIV255(lv_col32.blue * lv_col32.alpha); if(!gradient) /* The color is in ABGR8888 format with red channel in the lower 8 bits. */ @@ -109,21 +127,45 @@ vg_lite_color_t vglite_get_color(lv_color32_t lv_col32, bool gradient) vg_lite_blend_t vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode) { - vg_lite_blend_t vg_blend_mode; + vg_lite_blend_t vg_blend_mode = VG_LITE_BLEND_NONE; - switch(lv_blend_mode) { - case LV_BLEND_MODE_ADDITIVE: - vg_blend_mode = VG_LITE_BLEND_ADDITIVE; - break; - case LV_BLEND_MODE_SUBTRACTIVE: - vg_blend_mode = VG_LITE_BLEND_SUBTRACT; - break; - case LV_BLEND_MODE_MULTIPLY: - vg_blend_mode = VG_LITE_BLEND_MULTIPLY; - break; - default: - vg_blend_mode = VG_LITE_BLEND_SRC_OVER; - break; + if(vg_lite_query_feature(gcFEATURE_BIT_VG_LVGL_SUPPORT)) { + switch(lv_blend_mode) { + case LV_BLEND_MODE_NORMAL: + vg_blend_mode = VG_LITE_BLEND_NORMAL_LVGL; + break; + case LV_BLEND_MODE_ADDITIVE: + vg_blend_mode = VG_LITE_BLEND_ADDITIVE_LVGL; + break; + case LV_BLEND_MODE_SUBTRACTIVE: + vg_blend_mode = VG_LITE_BLEND_SUBTRACT_LVGL; + break; + case LV_BLEND_MODE_MULTIPLY: + vg_blend_mode = VG_LITE_BLEND_MULTIPLY_LVGL; + break; + default: + VGLITE_ASSERT_MSG(false, "Unsupported blend mode."); + break; + } + } + else { + switch(lv_blend_mode) { + case LV_BLEND_MODE_NORMAL: + vg_blend_mode = VG_LITE_BLEND_SRC_OVER; + break; + case LV_BLEND_MODE_ADDITIVE: + vg_blend_mode = VG_LITE_BLEND_ADDITIVE; + break; + case LV_BLEND_MODE_SUBTRACTIVE: + vg_blend_mode = VG_LITE_BLEND_SUBTRACT; + break; + case LV_BLEND_MODE_MULTIPLY: + vg_blend_mode = VG_LITE_BLEND_MULTIPLY; + break; + default: + VGLITE_ASSERT_MSG(false, "Unsupported blend mode."); + break; + } } return vg_blend_mode; @@ -134,7 +176,6 @@ vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf) vg_lite_buffer_format_t vg_buffer_format = VG_LITE_BGR565; switch(cf) { - /*<=1 byte (+alpha) formats*/ case LV_COLOR_FORMAT_L8: vg_buffer_format = VG_LITE_L8; break; @@ -153,18 +194,14 @@ vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf) case LV_COLOR_FORMAT_I8: vg_buffer_format = VG_LITE_INDEX_8; break; - - /*2 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB565: vg_buffer_format = VG_LITE_BGR565; break; case LV_COLOR_FORMAT_RGB565A8: - LV_ASSERT_MSG(false, "Unsupported color format."); + vg_buffer_format = VG_LITE_ABGR8565; break; - - /*3 byte (+alpha) formats*/ case LV_COLOR_FORMAT_RGB888: - LV_ASSERT_MSG(false, "Unsupported color format."); + vg_buffer_format = VG_LITE_BGR888; break; case LV_COLOR_FORMAT_ARGB8888: vg_buffer_format = VG_LITE_BGRA8888; @@ -174,52 +211,13 @@ vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf) break; default: - LV_ASSERT_MSG(false, "Unsupported color format."); + VGLITE_ASSERT_MSG(false, "Unsupported color format."); break; } return vg_buffer_format; } -uint8_t vglite_get_px_size(lv_color_format_t cf) -{ - uint8_t bits_per_pixel = LV_COLOR_DEPTH; - - switch(cf) { - case LV_COLOR_FORMAT_I1: - bits_per_pixel = 1; - break; - case LV_COLOR_FORMAT_I2: - bits_per_pixel = 2; - break; - case LV_COLOR_FORMAT_I4: - bits_per_pixel = 4; - break; - case LV_COLOR_FORMAT_I8: - case LV_COLOR_FORMAT_A8: - case LV_COLOR_FORMAT_L8: - bits_per_pixel = 8; - break; - case LV_COLOR_FORMAT_RGB565: - bits_per_pixel = 16; - break; - case LV_COLOR_FORMAT_RGB565A8: - case LV_COLOR_FORMAT_RGB888: - bits_per_pixel = 24; - break; - case LV_COLOR_FORMAT_ARGB8888: - case LV_COLOR_FORMAT_XRGB8888: - bits_per_pixel = 32; - break; - - default: - LV_ASSERT_MSG(false, "Unsupported buffer format."); - break; - } - - return bits_per_pixel; -} - uint8_t vglite_get_alignment(lv_color_format_t cf) { uint8_t align_bytes = LV_COLOR_DEPTH / 8 * 16; /*16 pixels*/ @@ -228,12 +226,20 @@ uint8_t vglite_get_alignment(lv_color_format_t cf) case LV_COLOR_FORMAT_I1: case LV_COLOR_FORMAT_I2: case LV_COLOR_FORMAT_I4: - align_bytes = 8; + /* + * VGLite alignment require 8 bytes. + * But ARM clean and invalidate cache needs 32 bytes address alignment. + */ + align_bytes = 32; break; case LV_COLOR_FORMAT_I8: case LV_COLOR_FORMAT_A8: case LV_COLOR_FORMAT_L8: - align_bytes = 16; + /* + * VGLite alignment require 16 bytes. + * But ARM clean and invalidate cache needs 32 bytes address alignment. + */ + align_bytes = 32; break; case LV_COLOR_FORMAT_RGB565: align_bytes = 32; @@ -248,7 +254,7 @@ uint8_t vglite_get_alignment(lv_color_format_t cf) break; default: - LV_ASSERT_MSG(false, "Unsupported buffer format."); + VGLITE_ASSERT_MSG(false, "Unsupported buffer format."); break; } @@ -262,18 +268,12 @@ bool vglite_buf_aligned(const void * buf, uint32_t stride, lv_color_format_t cf) /* No alignment requirement for destination buffer when using mode VG_LITE_LINEAR */ /* Test for pointer alignment */ - if((uintptr_t)buf % align_bytes) { - LV_LOG_ERROR("Buffer address (0x%x) not aligned to %d bytes.", - (size_t)buf, align_bytes); + if((uintptr_t)buf % align_bytes) return false; - } /* Test for stride alignment */ - if(stride % align_bytes) { - LV_LOG_ERROR("Buffer stride (%d bytes) not aligned to %d bytes.", - stride, align_bytes); + if(stride == 0 || stride % align_bytes) return false; - } return true; } diff --git a/src/draw/nxp/vglite/lv_vglite_utils.h b/src/draw/nxp/vglite/lv_vglite_utils.h index 899743943..822d162a4 100644 --- a/src/draw/nxp/vglite/lv_vglite_utils.h +++ b/src/draw/nxp/vglite/lv_vglite_utils.h @@ -4,7 +4,7 @@ */ /** - * Copyright 2022, 2023 NXP + * Copyright 2022-2024 NXP * * SPDX-License-Identifier: MIT */ @@ -25,11 +25,34 @@ extern "C" { #include "../../sw/lv_draw_sw.h" #include "vg_lite.h" +#include "vg_lite_options.h" /********************* * DEFINES *********************/ +#define ENUM_TO_STRING(e) \ + case (e): \ + return #e + +#if LV_USE_VGLITE_ASSERT +#define VGLITE_ASSERT(expr) LV_ASSERT(expr) +#define VGLITE_ASSERT_MSG(expr, msg) LV_ASSERT_MSG(expr, msg) +#else +#define VGLITE_ASSERT(expr) +#define VGLITE_ASSERT_MSG(expr, msg) LV_LOG_ERROR(msg) +#endif + +#define VGLITE_CHECK_ERROR(function) \ + do { \ + vg_lite_error_t error = function; \ + if(error != VG_LITE_SUCCESS) { \ + LV_LOG_ERROR("Execute '" #function "' error(%d): %s", \ + (int)error, vglite_error_to_string(error)); \ + VGLITE_ASSERT(false); \ + } \ + } while (0) + /********************** * TYPEDEFS **********************/ @@ -39,24 +62,20 @@ extern "C" { **********************/ /** - * Enable scissor and set the clipping box. + * Set the clipping box. * * @param[in] clip_area Clip area with relative coordinates of destination buffer * */ static inline void vglite_set_scissor(const lv_area_t * clip_area); -/** - * Disable scissor. - * - */ -static inline void vglite_disable_scissor(void); - /********************** * GLOBAL PROTOTYPES **********************/ -#if LV_USE_OS +const char * vglite_error_to_string(vg_lite_error_t error); + +#if LV_USE_VGLITE_DRAW_ASYNC /** * Get VG-Lite command buffer flushed status. * @@ -65,7 +84,7 @@ bool vglite_cmd_buf_is_flushed(void); #endif /** - * Clear cache and flush command to VG-Lite. + * Flush command to VG-Lite. * */ void vglite_run(void); @@ -102,16 +121,6 @@ vg_lite_blend_t vglite_get_blend_mode(lv_blend_mode_t lv_blend_mode); */ vg_lite_buffer_format_t vglite_get_buf_format(lv_color_format_t cf); -/** - * Get vglite buffer pixel size. - * - * @param[in] cf Color format - * - * @retval Bits per pixel - * - */ -uint8_t vglite_get_px_size(lv_color_format_t cf); - /** * Get vglite buffer alignment. * @@ -144,15 +153,7 @@ bool vglite_buf_aligned(const void * buf, uint32_t stride, lv_color_format_t cf) static inline void vglite_set_scissor(const lv_area_t * clip_area) { - vg_lite_enable_scissor(); - vg_lite_set_scissor((int32_t)clip_area->x1, (int32_t)clip_area->y1, - (int32_t)lv_area_get_width(clip_area), - (int32_t)lv_area_get_height(clip_area)); -} - -static inline void vglite_disable_scissor(void) -{ - vg_lite_disable_scissor(); + vg_lite_set_scissor(clip_area->x1, clip_area->y1, clip_area->x2 + 1, clip_area->y2 + 1); } #endif /*LV_USE_DRAW_VGLITE*/ diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index ce664d2f0..fe5cfb163 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -189,6 +189,35 @@ #endif #endif +/*================= + * OPERATING SYSTEM + *=================*/ +/*Select an operating system to use. Possible options: + * - LV_OS_NONE + * - LV_OS_PTHREAD + * - LV_OS_FREERTOS + * - LV_OS_CMSIS_RTOS2 + * - LV_OS_RTTHREAD + * - LV_OS_WINDOWS + * - LV_OS_CUSTOM */ +#ifndef LV_USE_OS + #ifdef CONFIG_LV_USE_OS + #define LV_USE_OS CONFIG_LV_USE_OS + #else + #define LV_USE_OS LV_OS_NONE + #endif +#endif + +#if LV_USE_OS == LV_OS_CUSTOM + #ifndef LV_OS_CUSTOM_INCLUDE + #ifdef CONFIG_LV_OS_CUSTOM_INCLUDE + #define LV_OS_CUSTOM_INCLUDE CONFIG_LV_OS_CUSTOM_INCLUDE + #else + #define LV_OS_CUSTOM_INCLUDE + #endif + #endif +#endif + /*======================== * RENDERING CONFIGURATION *========================*/ @@ -332,6 +361,41 @@ #endif #endif +#if LV_USE_DRAW_VGLITE + /* Enable blit quality degradation workaround recommended for screen's dimension > 352 pixels. */ + #ifndef LV_USE_VGLITE_BLIT_SPLIT + #ifdef CONFIG_LV_USE_VGLITE_BLIT_SPLIT + #define LV_USE_VGLITE_BLIT_SPLIT CONFIG_LV_USE_VGLITE_BLIT_SPLIT + #else + #define LV_USE_VGLITE_BLIT_SPLIT 0 + #endif + #endif + + #if LV_USE_OS + /* Enable VGLite draw async. Queue multiple tasks and flash them once to the GPU. */ + #ifndef LV_USE_VGLITE_DRAW_ASYNC + #ifdef _LV_KCONFIG_PRESENT + #ifdef CONFIG_LV_USE_VGLITE_DRAW_ASYNC + #define LV_USE_VGLITE_DRAW_ASYNC CONFIG_LV_USE_VGLITE_DRAW_ASYNC + #else + #define LV_USE_VGLITE_DRAW_ASYNC 0 + #endif + #else + #define LV_USE_VGLITE_DRAW_ASYNC 1 + #endif + #endif + #endif + + /* Enable VGLite asserts. */ + #ifndef LV_USE_VGLITE_ASSERT + #ifdef CONFIG_LV_USE_VGLITE_ASSERT + #define LV_USE_VGLITE_ASSERT CONFIG_LV_USE_VGLITE_ASSERT + #else + #define LV_USE_VGLITE_ASSERT 0 + #endif + #endif +#endif + /* Use NXP's PXP on iMX RTxxx platforms. */ #ifndef LV_USE_DRAW_PXP #ifdef CONFIG_LV_USE_DRAW_PXP @@ -341,6 +405,17 @@ #endif #endif +#if LV_USE_DRAW_PXP + /* Enable PXP asserts. */ + #ifndef LV_USE_PXP_ASSERT + #ifdef CONFIG_LV_USE_PXP_ASSERT + #define LV_USE_PXP_ASSERT CONFIG_LV_USE_PXP_ASSERT + #else + #define LV_USE_PXP_ASSERT 0 + #endif + #endif +#endif + /* Use Renesas Dave2D on RA platforms. */ #ifndef LV_USE_DRAW_DAVE2D #ifdef CONFIG_LV_USE_DRAW_DAVE2D @@ -389,35 +464,6 @@ #endif -/*================= - * OPERATING SYSTEM - *=================*/ -/*Select an operating system to use. Possible options: - * - LV_OS_NONE - * - LV_OS_PTHREAD - * - LV_OS_FREERTOS - * - LV_OS_CMSIS_RTOS2 - * - LV_OS_RTTHREAD - * - LV_OS_WINDOWS - * - LV_OS_CUSTOM */ -#ifndef LV_USE_OS - #ifdef CONFIG_LV_USE_OS - #define LV_USE_OS CONFIG_LV_USE_OS - #else - #define LV_USE_OS LV_OS_NONE - #endif -#endif - -#if LV_USE_OS == LV_OS_CUSTOM - #ifndef LV_OS_CUSTOM_INCLUDE - #ifdef CONFIG_LV_OS_CUSTOM_INCLUDE - #define LV_OS_CUSTOM_INCLUDE CONFIG_LV_OS_CUSTOM_INCLUDE - #else - #define LV_OS_CUSTOM_INCLUDE - #endif - #endif -#endif - /*======================= * FEATURE CONFIGURATION *=======================*/ diff --git a/src/stdlib/builtin/lv_mem_core_builtin.c b/src/stdlib/builtin/lv_mem_core_builtin.c index 4d42f8929..c8f3233e3 100644 --- a/src/stdlib/builtin/lv_mem_core_builtin.c +++ b/src/stdlib/builtin/lv_mem_core_builtin.c @@ -70,6 +70,10 @@ static void lv_mem_walker(void * ptr, size_t size, int used, void * user); void lv_mem_init(void) { +#if LV_USE_OS + lv_mutex_init(&state.mutex); +#endif + #if LV_MEM_ADR == 0 #ifdef LV_MEM_POOL_ALLOC state.tlsf = lv_tlsf_create_with_pool((void *)LV_MEM_POOL_ALLOC(LV_MEM_SIZE), LV_MEM_SIZE); @@ -82,10 +86,6 @@ void lv_mem_init(void) state.tlsf = lv_tlsf_create_with_pool((void *)LV_MEM_ADR, LV_MEM_SIZE); #endif -#if LV_USE_OS - lv_mutex_init(&state.mutex); -#endif - _lv_ll_init(&state.pool_ll, sizeof(lv_pool_t)); /*Record the first pool*/ diff --git a/tests/src/test_cases/draw/test_draw_sw_rotate.c b/tests/src/test_cases/draw/test_draw_sw_rotate.c index 6863c0c9d..268d7d2ad 100644 --- a/tests/src/test_cases/draw/test_draw_sw_rotate.c +++ b/tests/src/test_cases/draw/test_draw_sw_rotate.c @@ -1,4 +1,4 @@ -#if LV_BUILD_TEST || 1 +#if LV_BUILD_TEST #include "../lvgl.h" #include "unity/unity.h" diff --git a/tests/src/test_cases/test_anim.c b/tests/src/test_cases/test_anim.c index 7394c305f..cb8c59606 100644 --- a/tests/src/test_cases/test_anim.c +++ b/tests/src/test_cases/test_anim.c @@ -1,4 +1,4 @@ -#if LV_BUILD_TEST || 1 +#if LV_BUILD_TEST #include "../lvgl.h" #include "unity/unity.h" diff --git a/tests/src/test_cases/test_bindings.c b/tests/src/test_cases/test_bindings.c index 419e17db0..f6848d152 100644 --- a/tests/src/test_cases/test_bindings.c +++ b/tests/src/test_cases/test_bindings.c @@ -1,4 +1,4 @@ -#if LV_BUILD_TEST || 1 +#if LV_BUILD_TEST #include "../lvgl.h" #include "unity/unity.h" diff --git a/tests/src/test_cases/widgets/test_bar.c b/tests/src/test_cases/widgets/test_bar.c index 93920631e..c3b0c3973 100644 --- a/tests/src/test_cases/widgets/test_bar.c +++ b/tests/src/test_cases/widgets/test_bar.c @@ -1,4 +1,4 @@ -#if LV_BUILD_TEST || 1 +#if LV_BUILD_TEST #include "../lvgl.h" #include "unity/unity.h" diff --git a/tests/src/test_cases/widgets/test_msgbox.c b/tests/src/test_cases/widgets/test_msgbox.c index b85a6b3ee..689803a9b 100644 --- a/tests/src/test_cases/widgets/test_msgbox.c +++ b/tests/src/test_cases/widgets/test_msgbox.c @@ -1,4 +1,4 @@ -#if LV_BUILD_TEST || 1 +#if LV_BUILD_TEST #include "../lvgl.h" #include "unity/unity.h"